mirror of
https://github.com/aljazceru/signal-cli-rest-api.git
synced 2025-12-18 23:24:20 +01:00
added swagger documentation
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,2 +1,3 @@
|
||||
signal-cli-config
|
||||
src/main
|
||||
src/signal-cli-rest-api
|
||||
|
||||
33
Dockerfile
33
Dockerfile
@@ -1,6 +1,7 @@
|
||||
FROM golang:1.13-buster
|
||||
|
||||
ARG SIGNAL_CLI_VERSION=0.6.8
|
||||
ARG SWAG_VERSION=1.6.7
|
||||
|
||||
ENV GIN_MODE=release
|
||||
|
||||
@@ -12,34 +13,36 @@ RUN sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && \
|
||||
dpkg-reconfigure --frontend=noninteractive locales && \
|
||||
update-locale LANG=en_US.UTF-8
|
||||
|
||||
ENV LANG en_US.UTF-8
|
||||
|
||||
#RUN cd /tmp/ \
|
||||
# && wget -P /tmp/ https://github.com/AsamK/signal-cli/archive/v${SIGNAL_CLI_VERSION}.tar.gz \
|
||||
# && tar -xvf /tmp/v${SIGNAL_CLI_VERSION}.tar.gz \
|
||||
# && cd signal-cli-${SIGNAL_CLI_VERSION} \
|
||||
# && ./gradlew build \
|
||||
# && ./gradlew installDist \
|
||||
# && ln -s /tmp/signal-cli-${SIGNAL_CLI_VERSION}/build/install/signal-cli/bin/signal-cli /usr/bin/signal-cli \
|
||||
# && rm -rf /tmp/v${SIGNAL_CLI_VERSION}.tar.gz
|
||||
|
||||
# https://github.com/AsamK/signal-cli/issues/259 is not yet in a release, so we need to check out the repository
|
||||
ENV LANG en_US.UTF-8
|
||||
|
||||
RUN cd /tmp/ \
|
||||
&& git clone https://github.com/swaggo/swag.git swag-${SWAG_VERSION} \
|
||||
&& cd swag-${SWAG_VERSION} \
|
||||
&& git checkout v${SWAG_VERSION} \
|
||||
&& make \
|
||||
&& cp /tmp/swag-${SWAG_VERSION}/swag /usr/bin/swag \
|
||||
&& rm -r /tmp/swag-${SWAG_VERSION}
|
||||
|
||||
RUN cd /tmp/ \
|
||||
&& git clone https://github.com/AsamK/signal-cli.git signal-cli-${SIGNAL_CLI_VERSION} \
|
||||
&& cd signal-cli-${SIGNAL_CLI_VERSION} \
|
||||
&& git checkout v${SIGNAL_CLI_VERSION} \
|
||||
&& ./gradlew build \
|
||||
&& ./gradlew installDist \
|
||||
&& ln -s /tmp/signal-cli-${SIGNAL_CLI_VERSION}/build/install/signal-cli/bin/signal-cli /usr/bin/signal-cli
|
||||
|
||||
RUN mkdir -p /signal-cli-config/
|
||||
RUN mkdir -p /home/.local/share/signal-cli
|
||||
COPY src/ /tmp/signal-cli-rest-api-src
|
||||
RUN cd /tmp/signal-cli-rest-api-src && go build
|
||||
|
||||
COPY src/api /tmp/signal-cli-rest-api-src/api
|
||||
COPY src/main.go /tmp/signal-cli-rest-api-src/
|
||||
COPY src/go.mod /tmp/signal-cli-rest-api-src/
|
||||
COPY src/go.sum /tmp/signal-cli-rest-api-src/
|
||||
|
||||
RUN cd /tmp/signal-cli-rest-api-src && swag init && go build
|
||||
|
||||
ENV PATH /tmp/signal-cli-rest-api-src/:/usr/bin/signal-cli-${SIGNAL_CLI_VERSION}/bin/:$PATH
|
||||
|
||||
EXPOSE 8080
|
||||
|
||||
ENTRYPOINT ["main"]
|
||||
ENTRYPOINT ["signal-cli-rest-api"]
|
||||
|
||||
619
src/api/api.go
Normal file
619
src/api/api.go
Normal file
@@ -0,0 +1,619 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"github.com/gin-gonic/gin"
|
||||
uuid "github.com/gofrs/uuid"
|
||||
"github.com/h2non/filetype"
|
||||
log "github.com/sirupsen/logrus"
|
||||
qrcode "github.com/skip2/go-qrcode"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const groupPrefix = "group."
|
||||
|
||||
type GroupEntry struct {
|
||||
Name string `json:"name"`
|
||||
Id string `json:"id"`
|
||||
InternalId string `json:"internal_id"`
|
||||
Members []string `json:"members"`
|
||||
Active bool `json:"active"`
|
||||
Blocked bool `json:"blocked"`
|
||||
}
|
||||
|
||||
type RegisterNumberRequest struct {
|
||||
UseVoice bool `json:"use_voice"`
|
||||
}
|
||||
|
||||
type SendMessageV1 struct {
|
||||
Number string `json:"number"`
|
||||
Recipients []string `json:"recipients"`
|
||||
Message string `json:"message"`
|
||||
Base64Attachment string `json:"base64_attachment"`
|
||||
IsGroup bool `json:"is_group"`
|
||||
}
|
||||
|
||||
type SendMessageV2 struct {
|
||||
Number string `json:"number"`
|
||||
Recipients []string `json:"recipients"`
|
||||
Message string `json:"message"`
|
||||
Base64Attachments []string `json:"base64_attachments"`
|
||||
}
|
||||
|
||||
type Error struct {
|
||||
Msg string `json:"error"`
|
||||
}
|
||||
|
||||
type About struct {
|
||||
SupportedApiVersions []string `json:"versions"`
|
||||
BuildNr int `json:"build"`
|
||||
}
|
||||
|
||||
type CreateGroup struct {
|
||||
Id string `json:"id"`
|
||||
}
|
||||
|
||||
func convertInternalGroupIdToGroupId(internalId string) string {
|
||||
return groupPrefix + base64.StdEncoding.EncodeToString([]byte(internalId))
|
||||
}
|
||||
|
||||
func getStringInBetween(str string, start string, end string) (result string) {
|
||||
i := strings.Index(str, start)
|
||||
if i == -1 {
|
||||
return
|
||||
}
|
||||
i += len(start)
|
||||
j := strings.Index(str[i:], end)
|
||||
if j == -1 {
|
||||
return
|
||||
}
|
||||
return str[i : i+j]
|
||||
}
|
||||
|
||||
func cleanupTmpFiles(paths []string) {
|
||||
for _, path := range paths {
|
||||
os.Remove(path)
|
||||
}
|
||||
}
|
||||
|
||||
func send(c *gin.Context, attachmentTmpDir string, signalCliConfig string, number string, message string,
|
||||
recipients []string, base64Attachments []string, isGroup bool) {
|
||||
cmd := []string{"--config", signalCliConfig, "-u", number, "send", "-m", message}
|
||||
|
||||
if len(recipients) == 0 {
|
||||
c.JSON(400, gin.H{"error": "Please specify at least one recipient"})
|
||||
return
|
||||
}
|
||||
|
||||
if !isGroup {
|
||||
cmd = append(cmd, recipients...)
|
||||
} else {
|
||||
if len(recipients) > 1 {
|
||||
c.JSON(400, gin.H{"error": "More than one recipient is currently not allowed"})
|
||||
return
|
||||
}
|
||||
|
||||
groupId, err := base64.StdEncoding.DecodeString(recipients[0])
|
||||
if err != nil {
|
||||
c.JSON(400, gin.H{"error": "Invalid group id"})
|
||||
return
|
||||
}
|
||||
|
||||
cmd = append(cmd, []string{"-g", string(groupId)}...)
|
||||
}
|
||||
|
||||
attachmentTmpPaths := []string{}
|
||||
for _, base64Attachment := range base64Attachments {
|
||||
u, err := uuid.NewV4()
|
||||
if err != nil {
|
||||
c.JSON(400, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
dec, err := base64.StdEncoding.DecodeString(base64Attachment)
|
||||
if err != nil {
|
||||
c.JSON(400, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
fType, err := filetype.Get(dec)
|
||||
if err != nil {
|
||||
c.JSON(400, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
attachmentTmpPath := attachmentTmpDir + u.String() + "." + fType.Extension
|
||||
attachmentTmpPaths = append(attachmentTmpPaths, attachmentTmpPath)
|
||||
|
||||
f, err := os.Create(attachmentTmpPath)
|
||||
if err != nil {
|
||||
c.JSON(400, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
if _, err := f.Write(dec); err != nil {
|
||||
cleanupTmpFiles(attachmentTmpPaths)
|
||||
c.JSON(400, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
if err := f.Sync(); err != nil {
|
||||
cleanupTmpFiles(attachmentTmpPaths)
|
||||
c.JSON(400, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
f.Close()
|
||||
}
|
||||
|
||||
if len(attachmentTmpPaths) > 0 {
|
||||
cmd = append(cmd, "-a")
|
||||
cmd = append(cmd, attachmentTmpPaths...)
|
||||
}
|
||||
|
||||
_, err := runSignalCli(true, cmd)
|
||||
if err != nil {
|
||||
cleanupTmpFiles(attachmentTmpPaths)
|
||||
c.JSON(400, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(201, nil)
|
||||
}
|
||||
|
||||
func getGroups(number string, signalCliConfig string) ([]GroupEntry, error) {
|
||||
groupEntries := []GroupEntry{}
|
||||
|
||||
out, err := runSignalCli(true, []string{"--config", signalCliConfig, "-u", number, "listGroups", "-d"})
|
||||
if err != nil {
|
||||
return groupEntries, err
|
||||
}
|
||||
|
||||
lines := strings.Split(out, "\n")
|
||||
for _, line := range lines {
|
||||
var groupEntry GroupEntry
|
||||
if line == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
idIdx := strings.Index(line, " Name: ")
|
||||
idPair := line[:idIdx]
|
||||
groupEntry.InternalId = strings.TrimPrefix(idPair, "Id: ")
|
||||
groupEntry.Id = convertInternalGroupIdToGroupId(groupEntry.InternalId)
|
||||
lineWithoutId := strings.TrimLeft(line[idIdx:], " ")
|
||||
|
||||
nameIdx := strings.Index(lineWithoutId, " Active: ")
|
||||
namePair := lineWithoutId[:nameIdx]
|
||||
groupEntry.Name = strings.TrimRight(strings.TrimPrefix(namePair, "Name: "), " ")
|
||||
lineWithoutName := strings.TrimLeft(lineWithoutId[nameIdx:], " ")
|
||||
|
||||
activeIdx := strings.Index(lineWithoutName, " Blocked: ")
|
||||
activePair := lineWithoutName[:activeIdx]
|
||||
active := strings.TrimPrefix(activePair, "Active: ")
|
||||
if active == "true" {
|
||||
groupEntry.Active = true
|
||||
} else {
|
||||
groupEntry.Active = false
|
||||
}
|
||||
lineWithoutActive := strings.TrimLeft(lineWithoutName[activeIdx:], " ")
|
||||
|
||||
blockedIdx := strings.Index(lineWithoutActive, " Members: ")
|
||||
blockedPair := lineWithoutActive[:blockedIdx]
|
||||
blocked := strings.TrimPrefix(blockedPair, "Blocked: ")
|
||||
if blocked == "true" {
|
||||
groupEntry.Blocked = true
|
||||
} else {
|
||||
groupEntry.Blocked = false
|
||||
}
|
||||
lineWithoutBlocked := strings.TrimLeft(lineWithoutActive[blockedIdx:], " ")
|
||||
|
||||
membersPair := lineWithoutBlocked
|
||||
members := strings.TrimPrefix(membersPair, "Members: ")
|
||||
trimmedMembers := strings.TrimRight(strings.TrimLeft(members, "["), "]")
|
||||
trimmedMembersList := strings.Split(trimmedMembers, ",")
|
||||
for _, member := range trimmedMembersList {
|
||||
groupEntry.Members = append(groupEntry.Members, strings.Trim(member, " "))
|
||||
}
|
||||
|
||||
groupEntries = append(groupEntries, groupEntry)
|
||||
}
|
||||
|
||||
return groupEntries, nil
|
||||
}
|
||||
|
||||
func runSignalCli(wait bool, args []string) (string, error) {
|
||||
cmd := exec.Command("signal-cli", args...)
|
||||
if wait {
|
||||
var errBuffer bytes.Buffer
|
||||
var outBuffer bytes.Buffer
|
||||
cmd.Stderr = &errBuffer
|
||||
cmd.Stdout = &outBuffer
|
||||
|
||||
err := cmd.Start()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
done := make(chan error, 1)
|
||||
go func() {
|
||||
done <- cmd.Wait()
|
||||
}()
|
||||
select {
|
||||
case <-time.After(60 * time.Second):
|
||||
err := cmd.Process.Kill()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return "", errors.New("process killed as timeout reached")
|
||||
case err := <-done:
|
||||
if err != nil {
|
||||
return "", errors.New(errBuffer.String())
|
||||
}
|
||||
}
|
||||
return outBuffer.String(), nil
|
||||
} else {
|
||||
stdout, err := cmd.StdoutPipe()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
cmd.Start()
|
||||
buf := bufio.NewReader(stdout) // Notice that this is not in a loop
|
||||
line, _, _ := buf.ReadLine()
|
||||
return string(line), nil
|
||||
}
|
||||
}
|
||||
|
||||
type Api struct {
|
||||
signalCliConfig string
|
||||
attachmentTmpDir string
|
||||
}
|
||||
|
||||
func NewApi(signalCliConfig string, attachmentTmpDir string) *Api {
|
||||
return &Api{
|
||||
signalCliConfig: signalCliConfig,
|
||||
attachmentTmpDir: attachmentTmpDir,
|
||||
}
|
||||
}
|
||||
|
||||
// @Summary Lists general information about the API
|
||||
// @Tags General
|
||||
// @Description Returns the supported API versions and the internal build nr
|
||||
// @Produce json
|
||||
// @Success 200 {object} About
|
||||
// @Router /v1/about [get]
|
||||
func (a *Api) About(c *gin.Context) {
|
||||
|
||||
|
||||
about := About{SupportedApiVersions: []string{"v1", "v2"}, BuildNr: 2}
|
||||
c.JSON(200, about)
|
||||
}
|
||||
|
||||
|
||||
|
||||
// @Summary Register a phone number.
|
||||
// @Tags Devices
|
||||
// @Description Register a phone number with the signal network.
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Success 201
|
||||
// @Failure 400 {object} Error
|
||||
// @Param number path string true "Registered Phone Number"
|
||||
// @Router /v1/register/{number} [post]
|
||||
func (a *Api) RegisterNumber(c *gin.Context) {
|
||||
number := c.Param("number")
|
||||
|
||||
var req RegisterNumberRequest
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
buf.ReadFrom(c.Request.Body)
|
||||
if buf.String() != "" {
|
||||
err := json.Unmarshal(buf.Bytes(), &req)
|
||||
if err != nil {
|
||||
log.Error("Couldn't register number: ", err.Error())
|
||||
c.JSON(400, Error{Msg: "Couldn't process request - invalid request."})
|
||||
return
|
||||
}
|
||||
} else {
|
||||
req.UseVoice = false
|
||||
}
|
||||
|
||||
if number == "" {
|
||||
c.JSON(400, gin.H{"error": "Please provide a number"})
|
||||
return
|
||||
}
|
||||
|
||||
command := []string{"--config", a.signalCliConfig, "-u", number, "register"}
|
||||
|
||||
if req.UseVoice == true {
|
||||
command = append(command, "--voice")
|
||||
}
|
||||
|
||||
_, err := runSignalCli(true, command)
|
||||
if err != nil {
|
||||
c.JSON(400, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(201, nil)
|
||||
}
|
||||
|
||||
// @Summary Verify a registered phone number.
|
||||
// @Tags Devices
|
||||
// @Description Verify a registered phone number with the signal network.
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Success 201 {string} string "OK"
|
||||
// @Failure 400 {object} Error
|
||||
// @Param number path string true "Registered Phone Number"
|
||||
// @Param token path string true "Verification Code"
|
||||
// @Router /v1/register/{number}/verify/{token} [post]
|
||||
func (a *Api) VerifyRegisteredNumber(c *gin.Context) {
|
||||
number := c.Param("number")
|
||||
token := c.Param("token")
|
||||
|
||||
if number == "" {
|
||||
c.JSON(400, gin.H{"error": "Please provide a number"})
|
||||
return
|
||||
}
|
||||
|
||||
if token == "" {
|
||||
c.JSON(400, gin.H{"error": "Please provide a verification code"})
|
||||
return
|
||||
}
|
||||
|
||||
_, err := runSignalCli(true, []string{"--config", a.signalCliConfig, "-u", number, "verify", token})
|
||||
if err != nil {
|
||||
c.JSON(400, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(201, nil)
|
||||
}
|
||||
|
||||
// @Summary Send a signal message.
|
||||
// @Tags Messages
|
||||
// @Description Send a signal message
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Success 201 {string} string "OK"
|
||||
// @Failure 400 {object} Error
|
||||
// @Param number path string true "Registered Phone Number"
|
||||
// @Param data body SendMessageV1 true "Input Data"
|
||||
// @Router /v1/send/{number} [post]
|
||||
// @Deprecated
|
||||
func (a *Api) Send(c *gin.Context) {
|
||||
|
||||
var req SendMessageV1
|
||||
err := c.BindJSON(&req)
|
||||
if err != nil {
|
||||
c.JSON(400, gin.H{"error": "Couldn't process request - invalid request"})
|
||||
return
|
||||
}
|
||||
|
||||
base64Attachments := []string{}
|
||||
if req.Base64Attachment != "" {
|
||||
base64Attachments = append(base64Attachments, req.Base64Attachment)
|
||||
}
|
||||
|
||||
send(c, a.signalCliConfig, a.signalCliConfig, req.Number, req.Message, req.Recipients, base64Attachments, req.IsGroup)
|
||||
}
|
||||
|
||||
// @Summary Send a signal message.
|
||||
// @Tags Messages
|
||||
// @Description Send a signal message
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Success 201 {string} string "OK"
|
||||
// @Failure 400 {object} Error
|
||||
// @Param number path string true "Registered Phone Number"
|
||||
// @Param data body SendMessageV2 true "Input Data"
|
||||
// @Router /v2/send/{number} [post]
|
||||
func (a *Api) SendV2(c *gin.Context) {
|
||||
var req SendMessageV2
|
||||
err := c.BindJSON(&req)
|
||||
if err != nil {
|
||||
c.JSON(400, gin.H{"error": "Couldn't process request - invalid request"})
|
||||
log.Error(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if len(req.Recipients) == 0 {
|
||||
c.JSON(400, gin.H{"error": "Couldn't process request - please provide at least one recipient"})
|
||||
return
|
||||
}
|
||||
|
||||
groups := []string{}
|
||||
recipients := []string{}
|
||||
|
||||
for _, recipient := range req.Recipients {
|
||||
if strings.HasPrefix(recipient, groupPrefix) {
|
||||
groups = append(groups, strings.TrimPrefix(recipient, groupPrefix))
|
||||
} else {
|
||||
recipients = append(recipients, recipient)
|
||||
}
|
||||
}
|
||||
|
||||
if len(recipients) > 0 && len(groups) > 0 {
|
||||
c.JSON(400, gin.H{"error": "Signal Messenger Groups and phone numbers cannot be specified together in one request! Please split them up into multiple REST API calls."})
|
||||
return
|
||||
}
|
||||
|
||||
if len(groups) > 1 {
|
||||
c.JSON(400, gin.H{"error": "A signal message cannot be sent to more than one group at once! Please use multiple REST API calls for that."})
|
||||
return
|
||||
}
|
||||
|
||||
for _, group := range groups {
|
||||
send(c, a.attachmentTmpDir, a.signalCliConfig, req.Number, req.Message, []string{group}, req.Base64Attachments, true)
|
||||
}
|
||||
|
||||
if len(recipients) > 0 {
|
||||
send(c, a.attachmentTmpDir, a.signalCliConfig, req.Number, req.Message, recipients, req.Base64Attachments, false)
|
||||
}
|
||||
}
|
||||
|
||||
// @Summary Receive Signal Messages.
|
||||
// @Tags Messages
|
||||
// @Description Receives Signal Messages from the Signal Network.
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Success 200 {object} []string
|
||||
// @Failure 400 {object} Error
|
||||
// @Param number path string true "Registered Phone Number"
|
||||
// @Router /v1/receive/{number} [get]
|
||||
func (a *Api) Receive(c *gin.Context) {
|
||||
number := c.Param("number")
|
||||
|
||||
command := []string{"--config", a.signalCliConfig, "-u", number, "receive", "-t", "1", "--json"}
|
||||
out, err := runSignalCli(true, command)
|
||||
if err != nil {
|
||||
c.JSON(400, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
out = strings.Trim(out, "\n")
|
||||
lines := strings.Split(out, "\n")
|
||||
|
||||
jsonStr := "["
|
||||
for i, line := range lines {
|
||||
jsonStr += line
|
||||
if i != (len(lines) - 1) {
|
||||
jsonStr += ","
|
||||
}
|
||||
}
|
||||
jsonStr += "]"
|
||||
|
||||
c.String(200, jsonStr)
|
||||
}
|
||||
|
||||
// @Summary Create a new Signal Group.
|
||||
// @Tags Groups
|
||||
// @Description Create a new Signal Group with the specified members.
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Success 201 {object} CreateGroup
|
||||
// @Failure 400 {object} Error
|
||||
// @Param number path string true "Registered Phone Number"
|
||||
// @Router /v1/groups/{number} [post]
|
||||
func (a *Api) CreateGroup(c *gin.Context) {
|
||||
number := c.Param("number")
|
||||
|
||||
type Request struct {
|
||||
Name string `json:"name"`
|
||||
Members []string `json:"members"`
|
||||
}
|
||||
|
||||
var req Request
|
||||
err := c.BindJSON(&req)
|
||||
if err != nil {
|
||||
c.JSON(400, gin.H{"error": "Couldn't process request - invalid request"})
|
||||
log.Error(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
cmd := []string{"--config", a.signalCliConfig, "-u", number, "updateGroup", "-n", req.Name, "-m"}
|
||||
cmd = append(cmd, req.Members...)
|
||||
|
||||
out, err := runSignalCli(true, cmd)
|
||||
if err != nil {
|
||||
c.JSON(400, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
internalGroupId := getStringInBetween(out, `"`, `"`)
|
||||
c.JSON(201, CreateGroup{Id: convertInternalGroupIdToGroupId(internalGroupId)})
|
||||
}
|
||||
|
||||
// @Summary List all Signal Groups.
|
||||
// @Tags Groups
|
||||
// @Description List all Signal Groups.
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Success 200 {object} []GroupEntry
|
||||
// @Failure 400 {object} Error
|
||||
// @Param number path string true "Registered Phone Number"
|
||||
// @Router /v1/groups/{number} [get]
|
||||
func (a *Api) GetGroups(c *gin.Context) {
|
||||
number := c.Param("number")
|
||||
|
||||
groups, err := getGroups(number, a.signalCliConfig)
|
||||
if err != nil {
|
||||
c.JSON(400, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, groups)
|
||||
}
|
||||
|
||||
// @Summary Delete a Signal Group.
|
||||
// @Tags Groups
|
||||
// @Description Delete a Signal Group.
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Success 200 {string} string "OK"
|
||||
// @Failure 400 {object} Error
|
||||
// @Param number path string true "Registered Phone Number"
|
||||
// @Param groupid path string true "Group Id"
|
||||
// @Router /v1/groups/{number}/{groupid} [delete]
|
||||
func (a *Api) DeleteGroup(c *gin.Context) {
|
||||
base64EncodedGroupId := c.Param("groupid")
|
||||
number := c.Param("number")
|
||||
|
||||
if base64EncodedGroupId == "" {
|
||||
c.JSON(400, gin.H{"error": "Please specify a group id"})
|
||||
return
|
||||
}
|
||||
|
||||
groupId, err := base64.StdEncoding.DecodeString(strings.TrimPrefix(base64EncodedGroupId, groupPrefix))
|
||||
if err != nil {
|
||||
c.JSON(400, gin.H{"error": "Invalid group id"})
|
||||
return
|
||||
}
|
||||
|
||||
_, err = runSignalCli(true, []string{"--config", a.signalCliConfig, "-u", number, "quitGroup", "-g", string(groupId)})
|
||||
if err != nil {
|
||||
c.JSON(400, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// @Summary Link device and generate QR code.
|
||||
// @Tags Devices
|
||||
// @Description test
|
||||
// @Produce json
|
||||
// @Success 200 {string} string "Image"
|
||||
// @Router /v1/qrcodelink [get]
|
||||
func (a *Api) GetQrCodeLink(c *gin.Context) {
|
||||
deviceName := c.Query("device_name")
|
||||
|
||||
if deviceName == "" {
|
||||
c.JSON(400, gin.H{"error": "Please provide a name for the device"})
|
||||
return
|
||||
}
|
||||
|
||||
command := []string{"--config", a.signalCliConfig, "link", "-n", deviceName}
|
||||
|
||||
tsdeviceLink, err := runSignalCli(false, command)
|
||||
if err != nil {
|
||||
c.JSON(400, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
q, err := qrcode.New(string(tsdeviceLink), qrcode.Medium)
|
||||
if err != nil {
|
||||
c.JSON(400, gin.H{"error": err.Error()})
|
||||
}
|
||||
|
||||
q.DisableBorder = true
|
||||
var png []byte
|
||||
png, err = q.PNG(256)
|
||||
if err != nil {
|
||||
c.JSON(400, gin.H{"error": err.Error()})
|
||||
}
|
||||
|
||||
c.Data(200, "image/png", png)
|
||||
}
|
||||
574
src/docs/docs.go
Normal file
574
src/docs/docs.go
Normal file
@@ -0,0 +1,574 @@
|
||||
// GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
|
||||
// This file was generated by swaggo/swag
|
||||
|
||||
package docs
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"strings"
|
||||
|
||||
"github.com/alecthomas/template"
|
||||
"github.com/swaggo/swag"
|
||||
)
|
||||
|
||||
var doc = `{
|
||||
"schemes": {{ marshal .Schemes }},
|
||||
"swagger": "2.0",
|
||||
"info": {
|
||||
"description": "{{.Description}}",
|
||||
"title": "{{.Title}}",
|
||||
"contact": {},
|
||||
"license": {},
|
||||
"version": "{{.Version}}"
|
||||
},
|
||||
"host": "{{.Host}}",
|
||||
"basePath": "{{.BasePath}}",
|
||||
"paths": {
|
||||
"/v1/about": {
|
||||
"get": {
|
||||
"description": "Returns the supported API versions and the internal build nr",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"General"
|
||||
],
|
||||
"summary": "Lists general information about the API",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/api.About"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/v1/groups/{number}": {
|
||||
"get": {
|
||||
"description": "List all Signal Groups.",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Groups"
|
||||
],
|
||||
"summary": "List all Signal Groups.",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Registered Phone Number",
|
||||
"name": "number",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/api.GroupEntry"
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/api.Error"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"description": "Create a new Signal Group with the specified members.",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Groups"
|
||||
],
|
||||
"summary": "Create a new Signal Group.",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Registered Phone Number",
|
||||
"name": "number",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "Created",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/api.CreateGroup"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/api.Error"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/v1/groups/{number}/{groupid}": {
|
||||
"delete": {
|
||||
"description": "Delete a Signal Group.",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Groups"
|
||||
],
|
||||
"summary": "Delete a Signal Group.",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Registered Phone Number",
|
||||
"name": "number",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Group Id",
|
||||
"name": "groupid",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/api.Error"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/v1/qrcodelink": {
|
||||
"get": {
|
||||
"description": "test",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Devices"
|
||||
],
|
||||
"summary": "Link device and generate QR code.",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Image",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/v1/receive/{number}": {
|
||||
"get": {
|
||||
"description": "Receives Signal Messages from the Signal Network.",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Messages"
|
||||
],
|
||||
"summary": "Receive Signal Messages.",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Registered Phone Number",
|
||||
"name": "number",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/api.Error"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/v1/register/{number}": {
|
||||
"post": {
|
||||
"description": "Register a phone number with the signal network.",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Devices"
|
||||
],
|
||||
"summary": "Register a phone number.",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Registered Phone Number",
|
||||
"name": "number",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"201": {},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/api.Error"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/v1/register/{number}/verify/{token}": {
|
||||
"post": {
|
||||
"description": "Verify a registered phone number with the signal network.",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Devices"
|
||||
],
|
||||
"summary": "Verify a registered phone number.",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Registered Phone Number",
|
||||
"name": "number",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Verification Code",
|
||||
"name": "token",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/api.Error"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/v1/send/{number}": {
|
||||
"post": {
|
||||
"description": "Send a signal message",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Messages"
|
||||
],
|
||||
"summary": "Send a signal message.",
|
||||
"deprecated": true,
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Registered Phone Number",
|
||||
"name": "number",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"description": "Input Data",
|
||||
"name": "data",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/api.SendMessageV1"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/api.Error"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/v2/send/{number}": {
|
||||
"post": {
|
||||
"description": "Send a signal message",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Messages"
|
||||
],
|
||||
"summary": "Send a signal message.",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Registered Phone Number",
|
||||
"name": "number",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"description": "Input Data",
|
||||
"name": "data",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/api.SendMessageV2"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/api.Error"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"api.About": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"build": {
|
||||
"type": "integer"
|
||||
},
|
||||
"versions": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"api.CreateGroup": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"api.Error": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"error": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"api.GroupEntry": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"active": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"blocked": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"internal_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"members": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"api.SendMessageV1": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"base64_attachment": {
|
||||
"type": "string"
|
||||
},
|
||||
"is_group": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"number": {
|
||||
"type": "string"
|
||||
},
|
||||
"recipients": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"api.SendMessageV2": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"base64_attachments": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"number": {
|
||||
"type": "string"
|
||||
},
|
||||
"recipients": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
{
|
||||
"description": "List general information.",
|
||||
"name": "General"
|
||||
},
|
||||
{
|
||||
"description": "Register and link Devices.",
|
||||
"name": "Devices"
|
||||
},
|
||||
{
|
||||
"description": "Create, List and Delete Signal Groups.",
|
||||
"name": "Groups"
|
||||
},
|
||||
{
|
||||
"description": "Send and Receive Signal Messages.",
|
||||
"name": "Messages"
|
||||
}
|
||||
]
|
||||
}`
|
||||
|
||||
type swaggerInfo struct {
|
||||
Version string
|
||||
Host string
|
||||
BasePath string
|
||||
Schemes []string
|
||||
Title string
|
||||
Description string
|
||||
}
|
||||
|
||||
// SwaggerInfo holds exported Swagger Info so clients can modify it
|
||||
var SwaggerInfo = swaggerInfo{
|
||||
Version: "1.0",
|
||||
Host: "127.0.0.1:8080",
|
||||
BasePath: "/",
|
||||
Schemes: []string{},
|
||||
Title: "Signal Cli REST API",
|
||||
Description: "This is the Signal Cli REST API documentation.",
|
||||
}
|
||||
|
||||
type s struct{}
|
||||
|
||||
func (s *s) ReadDoc() string {
|
||||
sInfo := SwaggerInfo
|
||||
sInfo.Description = strings.Replace(sInfo.Description, "\n", "\\n", -1)
|
||||
|
||||
t, err := template.New("swagger_info").Funcs(template.FuncMap{
|
||||
"marshal": func(v interface{}) string {
|
||||
a, _ := json.Marshal(v)
|
||||
return string(a)
|
||||
},
|
||||
}).Parse(doc)
|
||||
if err != nil {
|
||||
return doc
|
||||
}
|
||||
|
||||
var tpl bytes.Buffer
|
||||
if err := t.Execute(&tpl, sInfo); err != nil {
|
||||
return doc
|
||||
}
|
||||
|
||||
return tpl.String()
|
||||
}
|
||||
|
||||
func init() {
|
||||
swag.Register(swag.Name, &s{})
|
||||
}
|
||||
512
src/docs/swagger.json
Normal file
512
src/docs/swagger.json
Normal file
@@ -0,0 +1,512 @@
|
||||
{
|
||||
"swagger": "2.0",
|
||||
"info": {
|
||||
"description": "This is the Signal Cli REST API documentation.",
|
||||
"title": "Signal Cli REST API",
|
||||
"contact": {},
|
||||
"license": {},
|
||||
"version": "1.0"
|
||||
},
|
||||
"host": "127.0.0.1:8080",
|
||||
"basePath": "/",
|
||||
"paths": {
|
||||
"/v1/about": {
|
||||
"get": {
|
||||
"description": "Returns the supported API versions and the internal build nr",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"General"
|
||||
],
|
||||
"summary": "Lists general information about the API",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/api.About"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/v1/groups/{number}": {
|
||||
"get": {
|
||||
"description": "List all Signal Groups.",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Groups"
|
||||
],
|
||||
"summary": "List all Signal Groups.",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Registered Phone Number",
|
||||
"name": "number",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/api.GroupEntry"
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/api.Error"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"description": "Create a new Signal Group with the specified members.",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Groups"
|
||||
],
|
||||
"summary": "Create a new Signal Group.",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Registered Phone Number",
|
||||
"name": "number",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "Created",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/api.CreateGroup"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/api.Error"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/v1/groups/{number}/{groupid}": {
|
||||
"delete": {
|
||||
"description": "Delete a Signal Group.",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Groups"
|
||||
],
|
||||
"summary": "Delete a Signal Group.",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Registered Phone Number",
|
||||
"name": "number",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Group Id",
|
||||
"name": "groupid",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/api.Error"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/v1/qrcodelink": {
|
||||
"get": {
|
||||
"description": "test",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Devices"
|
||||
],
|
||||
"summary": "Link device and generate QR code.",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Image",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/v1/receive/{number}": {
|
||||
"get": {
|
||||
"description": "Receives Signal Messages from the Signal Network.",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Messages"
|
||||
],
|
||||
"summary": "Receive Signal Messages.",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Registered Phone Number",
|
||||
"name": "number",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/api.Error"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/v1/register/{number}": {
|
||||
"post": {
|
||||
"description": "Register a phone number with the signal network.",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Devices"
|
||||
],
|
||||
"summary": "Register a phone number.",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Registered Phone Number",
|
||||
"name": "number",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"201": {},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/api.Error"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/v1/register/{number}/verify/{token}": {
|
||||
"post": {
|
||||
"description": "Verify a registered phone number with the signal network.",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Devices"
|
||||
],
|
||||
"summary": "Verify a registered phone number.",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Registered Phone Number",
|
||||
"name": "number",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Verification Code",
|
||||
"name": "token",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/api.Error"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/v1/send/{number}": {
|
||||
"post": {
|
||||
"description": "Send a signal message",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Messages"
|
||||
],
|
||||
"summary": "Send a signal message.",
|
||||
"deprecated": true,
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Registered Phone Number",
|
||||
"name": "number",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"description": "Input Data",
|
||||
"name": "data",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/api.SendMessageV1"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/api.Error"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/v2/send/{number}": {
|
||||
"post": {
|
||||
"description": "Send a signal message",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Messages"
|
||||
],
|
||||
"summary": "Send a signal message.",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Registered Phone Number",
|
||||
"name": "number",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"description": "Input Data",
|
||||
"name": "data",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/api.SendMessageV2"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/api.Error"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"api.About": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"build": {
|
||||
"type": "integer"
|
||||
},
|
||||
"versions": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"api.CreateGroup": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"api.Error": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"error": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"api.GroupEntry": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"active": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"blocked": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"internal_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"members": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"api.SendMessageV1": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"base64_attachment": {
|
||||
"type": "string"
|
||||
},
|
||||
"is_group": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"number": {
|
||||
"type": "string"
|
||||
},
|
||||
"recipients": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"api.SendMessageV2": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"base64_attachments": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"number": {
|
||||
"type": "string"
|
||||
},
|
||||
"recipients": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
{
|
||||
"description": "List general information.",
|
||||
"name": "General"
|
||||
},
|
||||
{
|
||||
"description": "Register and link Devices.",
|
||||
"name": "Devices"
|
||||
},
|
||||
{
|
||||
"description": "Create, List and Delete Signal Groups.",
|
||||
"name": "Groups"
|
||||
},
|
||||
{
|
||||
"description": "Send and Receive Signal Messages.",
|
||||
"name": "Messages"
|
||||
}
|
||||
]
|
||||
}
|
||||
335
src/docs/swagger.yaml
Normal file
335
src/docs/swagger.yaml
Normal file
@@ -0,0 +1,335 @@
|
||||
basePath: /
|
||||
definitions:
|
||||
api.About:
|
||||
properties:
|
||||
build:
|
||||
type: integer
|
||||
versions:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
type: object
|
||||
api.CreateGroup:
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
type: object
|
||||
api.Error:
|
||||
properties:
|
||||
error:
|
||||
type: string
|
||||
type: object
|
||||
api.GroupEntry:
|
||||
properties:
|
||||
active:
|
||||
type: boolean
|
||||
blocked:
|
||||
type: boolean
|
||||
id:
|
||||
type: string
|
||||
internal_id:
|
||||
type: string
|
||||
members:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
name:
|
||||
type: string
|
||||
type: object
|
||||
api.SendMessageV1:
|
||||
properties:
|
||||
base64_attachment:
|
||||
type: string
|
||||
is_group:
|
||||
type: boolean
|
||||
message:
|
||||
type: string
|
||||
number:
|
||||
type: string
|
||||
recipients:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
type: object
|
||||
api.SendMessageV2:
|
||||
properties:
|
||||
base64_attachments:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
message:
|
||||
type: string
|
||||
number:
|
||||
type: string
|
||||
recipients:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
type: object
|
||||
host: 127.0.0.1:8080
|
||||
info:
|
||||
contact: {}
|
||||
description: This is the Signal Cli REST API documentation.
|
||||
license: {}
|
||||
title: Signal Cli REST API
|
||||
version: "1.0"
|
||||
paths:
|
||||
/v1/about:
|
||||
get:
|
||||
description: Returns the supported API versions and the internal build nr
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/api.About'
|
||||
summary: Lists general information about the API
|
||||
tags:
|
||||
- General
|
||||
/v1/groups/{number}:
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
description: List all Signal Groups.
|
||||
parameters:
|
||||
- description: Registered Phone Number
|
||||
in: path
|
||||
name: number
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
items:
|
||||
$ref: '#/definitions/api.GroupEntry'
|
||||
type: array
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/api.Error'
|
||||
summary: List all Signal Groups.
|
||||
tags:
|
||||
- Groups
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Create a new Signal Group with the specified members.
|
||||
parameters:
|
||||
- description: Registered Phone Number
|
||||
in: path
|
||||
name: number
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"201":
|
||||
description: Created
|
||||
schema:
|
||||
$ref: '#/definitions/api.CreateGroup'
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/api.Error'
|
||||
summary: Create a new Signal Group.
|
||||
tags:
|
||||
- Groups
|
||||
/v1/groups/{number}/{groupid}:
|
||||
delete:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Delete a Signal Group.
|
||||
parameters:
|
||||
- description: Registered Phone Number
|
||||
in: path
|
||||
name: number
|
||||
required: true
|
||||
type: string
|
||||
- description: Group Id
|
||||
in: path
|
||||
name: groupid
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
type: string
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/api.Error'
|
||||
summary: Delete a Signal Group.
|
||||
tags:
|
||||
- Groups
|
||||
/v1/qrcodelink:
|
||||
get:
|
||||
description: test
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: Image
|
||||
schema:
|
||||
type: string
|
||||
summary: Link device and generate QR code.
|
||||
tags:
|
||||
- Devices
|
||||
/v1/receive/{number}:
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Receives Signal Messages from the Signal Network.
|
||||
parameters:
|
||||
- description: Registered Phone Number
|
||||
in: path
|
||||
name: number
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/api.Error'
|
||||
summary: Receive Signal Messages.
|
||||
tags:
|
||||
- Messages
|
||||
/v1/register/{number}:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Register a phone number with the signal network.
|
||||
parameters:
|
||||
- description: Registered Phone Number
|
||||
in: path
|
||||
name: number
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"201": {}
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/api.Error'
|
||||
summary: Register a phone number.
|
||||
tags:
|
||||
- Devices
|
||||
/v1/register/{number}/verify/{token}:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Verify a registered phone number with the signal network.
|
||||
parameters:
|
||||
- description: Registered Phone Number
|
||||
in: path
|
||||
name: number
|
||||
required: true
|
||||
type: string
|
||||
- description: Verification Code
|
||||
in: path
|
||||
name: token
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"201":
|
||||
description: OK
|
||||
schema:
|
||||
type: string
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/api.Error'
|
||||
summary: Verify a registered phone number.
|
||||
tags:
|
||||
- Devices
|
||||
/v1/send/{number}:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
deprecated: true
|
||||
description: Send a signal message
|
||||
parameters:
|
||||
- description: Registered Phone Number
|
||||
in: path
|
||||
name: number
|
||||
required: true
|
||||
type: string
|
||||
- description: Input Data
|
||||
in: body
|
||||
name: data
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/api.SendMessageV1'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"201":
|
||||
description: OK
|
||||
schema:
|
||||
type: string
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/api.Error'
|
||||
summary: Send a signal message.
|
||||
tags:
|
||||
- Messages
|
||||
/v2/send/{number}:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Send a signal message
|
||||
parameters:
|
||||
- description: Registered Phone Number
|
||||
in: path
|
||||
name: number
|
||||
required: true
|
||||
type: string
|
||||
- description: Input Data
|
||||
in: body
|
||||
name: data
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/api.SendMessageV2'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"201":
|
||||
description: OK
|
||||
schema:
|
||||
type: string
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/api.Error'
|
||||
summary: Send a signal message.
|
||||
tags:
|
||||
- Messages
|
||||
swagger: "2.0"
|
||||
tags:
|
||||
- description: List general information.
|
||||
name: General
|
||||
- description: Register and link Devices.
|
||||
name: Devices
|
||||
- description: Create, List and Delete Signal Groups.
|
||||
name: Groups
|
||||
- description: Send and Receive Signal Messages.
|
||||
name: Messages
|
||||
13
src/go.mod
13
src/go.mod
@@ -3,9 +3,22 @@ module github.com/bbernhard/signal-cli-rest-api
|
||||
go 1.14
|
||||
|
||||
require (
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect
|
||||
github.com/gin-gonic/gin v1.6.3
|
||||
github.com/go-openapi/spec v0.19.8 // indirect
|
||||
github.com/go-openapi/swag v0.19.9 // indirect
|
||||
github.com/gofrs/uuid v3.3.0+incompatible
|
||||
github.com/h2non/filetype v1.1.0
|
||||
github.com/mailru/easyjson v0.7.1 // indirect
|
||||
github.com/sirupsen/logrus v1.6.0
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
|
||||
github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14
|
||||
github.com/swaggo/gin-swagger v1.2.0
|
||||
github.com/swaggo/swag v1.6.7
|
||||
github.com/urfave/cli/v2 v2.2.0 // indirect
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344 // indirect
|
||||
golang.org/x/text v0.3.3 // indirect
|
||||
golang.org/x/tools v0.0.0-20200626171337-aa94e735be7f // indirect
|
||||
gopkg.in/yaml.v2 v2.3.0 // indirect
|
||||
)
|
||||
|
||||
135
src/go.sum
135
src/go.sum
@@ -1,9 +1,50 @@
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
|
||||
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
|
||||
github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
|
||||
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/gin-contrib/gzip v0.0.1/go.mod h1:fGBJBCdt6qCZuCAOwWuFhBB4OOq9EFqlo5dEaFhhu5w=
|
||||
github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s=
|
||||
github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s=
|
||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
github.com/gin-gonic/gin v1.3.0/go.mod h1:7cKuhb5qV2ggCFctp2fJQ+ErvciLZrIeoOSOm6mUr7Y=
|
||||
github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM=
|
||||
github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14=
|
||||
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
|
||||
github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
|
||||
github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
|
||||
github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w=
|
||||
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||
github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
|
||||
github.com/go-openapi/jsonreference v0.19.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
|
||||
github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
|
||||
github.com/go-openapi/jsonreference v0.19.3 h1:5cxNfTy0UVC3X8JL5ymxzyoUZmo8iZb+jeTWn7tUa8o=
|
||||
github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
|
||||
github.com/go-openapi/spec v0.19.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
|
||||
github.com/go-openapi/spec v0.19.4 h1:ixzUSnHTd6hCemgtAJgluaTSGYpLNpJY4mA2DIkdOAo=
|
||||
github.com/go-openapi/spec v0.19.4/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
|
||||
github.com/go-openapi/spec v0.19.8 h1:qAdZLh1r6QF/hI/gTq+TJTvsQUodZsM7KLqkAJdiJNg=
|
||||
github.com/go-openapi/spec v0.19.8/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk=
|
||||
github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
|
||||
github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||
github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY=
|
||||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||
github.com/go-openapi/swag v0.19.9 h1:1IxuqvBUU3S2Bi4YC7tlP9SJF1gVpCvqN0T2Qof4azE=
|
||||
github.com/go-openapi/swag v0.19.9/go.mod h1:ao+8BpOPyKdpQz3AOJfbeEVpLmWAvlT1IfTe5McPyhY=
|
||||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
|
||||
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
||||
@@ -14,38 +55,132 @@ github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GO
|
||||
github.com/gofrs/uuid v1.2.0 h1:coDhrjgyJaglxSjxuJdqQSSdUpG3w6p1OwN2od6frBU=
|
||||
github.com/gofrs/uuid v3.3.0+incompatible h1:8K4tyRfvU1CYPgJsveYFQMhpFd/wXNM7iK6rR7UHz84=
|
||||
github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/h2non/filetype v1.1.0 h1:Or/gjocJrJRNK/Cri/TDEKFjAR+cfG6eK65NGYB6gBA=
|
||||
github.com/h2non/filetype v1.1.0/go.mod h1:319b3zT68BvV+WRj7cwy856M2ehB3HqNOt6sy1HndBY=
|
||||
github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
|
||||
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
||||
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e h1:hB2xlXdHp/pmPZq0y3QnmWAArdw9PqbmotexnWx/FU8=
|
||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.7.1 h1:mdxE1MF9o53iCb2Ghj1VfWvh7ZOwHpnVG/xwXrV90U8=
|
||||
github.com/mailru/easyjson v0.7.1/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
|
||||
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I=
|
||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0=
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14 h1:PyYN9JH5jY9j6av01SpfRMb+1DWg/i3MbGOKPxJ2wjM=
|
||||
github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14/go.mod h1:gxQT6pBGRuIGunNf/+tSOB5OHvguWi8Tbt82WOkf35E=
|
||||
github.com/swaggo/gin-swagger v1.2.0 h1:YskZXEiv51fjOMTsXrOetAjrMDfFaXD79PEoQBOe2W0=
|
||||
github.com/swaggo/gin-swagger v1.2.0/go.mod h1:qlH2+W7zXGZkczuL+r2nEBR2JTT+/lX05Nn6vPhc7OI=
|
||||
github.com/swaggo/swag v1.5.1/go.mod h1:1Bl9F/ZBpVWh22nY0zmYyASPO1lI/zIwRDrpZU+tv8Y=
|
||||
github.com/swaggo/swag v1.6.7 h1:e8GC2xDllJZr3omJkm9YfmK0Y56+rMO3cg0JBKNz09s=
|
||||
github.com/swaggo/swag v1.6.7/go.mod h1:xDhTyuFIujYiN3DKWC/H/83xcfHp+UE/IzWWampG7Zc=
|
||||
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
||||
github.com/ugorji/go v1.1.5-pre/go.mod h1:FwP/aQVg39TXzItUBMwnWp9T9gPQnXw4Poh4/oBQZ/0=
|
||||
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
|
||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||
github.com/ugorji/go/codec v0.0.0-20181022190402-e5e69e061d4f/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||
github.com/ugorji/go/codec v1.1.5-pre/go.mod h1:tULtS6Gy1AE1yCENaw4Vb//HLH5njI2tfCQDUqRd8fI=
|
||||
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
|
||||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||
github.com/urfave/cli v1.20.0 h1:fDqGv3UG/4jbVl/QkFwEdddtEDjh/5Ov6X+0B/3bPaw=
|
||||
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||
github.com/urfave/cli/v2 v2.1.1 h1:Qt8FeAtxE/vfdrLmR3rxR6JRE0RoVmbXu8+6kZtYU4k=
|
||||
github.com/urfave/cli/v2 v2.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
|
||||
github.com/urfave/cli/v2 v2.2.0 h1:JTTnM6wKzdA0Jqodd966MVj4vWbbquZykeX1sKbe2C4=
|
||||
github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190611141213-3f473d35a33a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM=
|
||||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190610200419-93c9922d18ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190606050223-4d9ae51c2468/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190611222205-d73e1c7e250b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59 h1:QjA/9ArTfVTLfEhClDCG7SGrZkZixxWpwNCDiwJfh88=
|
||||
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200626171337-aa94e735be7f h1:JcoF/bowzCDI+MXu1yLqQGNO3ibqWsWq+Sk7pOT218w=
|
||||
golang.org/x/tools v0.0.0-20200626171337-aa94e735be7f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
|
||||
gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
|
||||
526
src/main.go
526
src/main.go
@@ -1,244 +1,37 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"flag"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/h2non/filetype"
|
||||
uuid "github.com/gofrs/uuid"
|
||||
log "github.com/sirupsen/logrus"
|
||||
qrcode "github.com/skip2/go-qrcode"
|
||||
swaggerFiles "github.com/swaggo/files"
|
||||
ginSwagger "github.com/swaggo/gin-swagger"
|
||||
"github.com/bbernhard/signal-cli-rest-api/api"
|
||||
_ "github.com/bbernhard/signal-cli-rest-api/docs"
|
||||
|
||||
)
|
||||
|
||||
const groupPrefix = "group."
|
||||
|
||||
type GroupEntry struct {
|
||||
Name string `json:"name"`
|
||||
Id string `json:"id"`
|
||||
InternalId string `json:"internal_id"`
|
||||
Members []string `json:"members"`
|
||||
Active bool `json:"active"`
|
||||
Blocked bool `json:"blocked"`
|
||||
}
|
||||
|
||||
func convertInternalGroupIdToGroupId(internalId string) string {
|
||||
return groupPrefix + base64.StdEncoding.EncodeToString([]byte(internalId))
|
||||
}
|
||||
// @title Signal Cli REST API
|
||||
// @version 1.0
|
||||
// @description This is the Signal Cli REST API documentation.
|
||||
|
||||
func getStringInBetween(str string, start string, end string) (result string) {
|
||||
i := strings.Index(str, start)
|
||||
if i == -1 {
|
||||
return
|
||||
}
|
||||
i += len(start)
|
||||
j := strings.Index(str[i:], end)
|
||||
if j == -1 {
|
||||
return
|
||||
}
|
||||
return str[i : i+j]
|
||||
}
|
||||
// @tag.name General
|
||||
// @tag.description List general information.
|
||||
|
||||
func cleanupTmpFiles(paths []string) {
|
||||
for _, path := range paths {
|
||||
os.Remove(path)
|
||||
}
|
||||
}
|
||||
// @tag.name Devices
|
||||
// @tag.description Register and link Devices.
|
||||
|
||||
func send(c *gin.Context, attachmentTmpDir string, signalCliConfig string, number string, message string,
|
||||
recipients []string, base64Attachments []string, isGroup bool) {
|
||||
cmd := []string{"--config", signalCliConfig, "-u", number, "send", "-m", message}
|
||||
// @tag.name Groups
|
||||
// @tag.description Create, List and Delete Signal Groups.
|
||||
|
||||
if len(recipients) == 0 {
|
||||
c.JSON(400, gin.H{"error": "Please specify at least one recipient"})
|
||||
return
|
||||
}
|
||||
|
||||
if !isGroup {
|
||||
cmd = append(cmd, recipients...)
|
||||
} else {
|
||||
if len(recipients) > 1 {
|
||||
c.JSON(400, gin.H{"error": "More than one recipient is currently not allowed"})
|
||||
return
|
||||
}
|
||||
|
||||
groupId, err := base64.StdEncoding.DecodeString(recipients[0])
|
||||
if err != nil {
|
||||
c.JSON(400, gin.H{"error": "Invalid group id"})
|
||||
return
|
||||
}
|
||||
|
||||
cmd = append(cmd, []string{"-g", string(groupId)}...)
|
||||
}
|
||||
|
||||
attachmentTmpPaths := []string{}
|
||||
for _, base64Attachment := range base64Attachments {
|
||||
u, err := uuid.NewV4()
|
||||
if err != nil {
|
||||
c.JSON(400, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
dec, err := base64.StdEncoding.DecodeString(base64Attachment)
|
||||
if err != nil {
|
||||
c.JSON(400, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
fType, err := filetype.Get(dec)
|
||||
if err != nil {
|
||||
c.JSON(400, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
attachmentTmpPath := attachmentTmpDir + u.String() + "." + fType.Extension
|
||||
attachmentTmpPaths = append(attachmentTmpPaths, attachmentTmpPath)
|
||||
|
||||
f, err := os.Create(attachmentTmpPath)
|
||||
if err != nil {
|
||||
c.JSON(400, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
if _, err := f.Write(dec); err != nil {
|
||||
cleanupTmpFiles(attachmentTmpPaths)
|
||||
c.JSON(400, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
if err := f.Sync(); err != nil {
|
||||
cleanupTmpFiles(attachmentTmpPaths)
|
||||
c.JSON(400, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
f.Close()
|
||||
}
|
||||
|
||||
if len(attachmentTmpPaths) > 0 {
|
||||
cmd = append(cmd, "-a")
|
||||
cmd = append(cmd, attachmentTmpPaths...)
|
||||
}
|
||||
|
||||
_, err := runSignalCli(true, cmd)
|
||||
if err != nil {
|
||||
cleanupTmpFiles(attachmentTmpPaths)
|
||||
c.JSON(400, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(201, nil)
|
||||
}
|
||||
|
||||
func getGroups(number string, signalCliConfig string) ([]GroupEntry, error) {
|
||||
groupEntries := []GroupEntry{}
|
||||
|
||||
out, err := runSignalCli(true, []string{"--config", signalCliConfig, "-u", number, "listGroups", "-d"})
|
||||
if err != nil {
|
||||
return groupEntries, err
|
||||
}
|
||||
|
||||
lines := strings.Split(out, "\n")
|
||||
for _, line := range lines {
|
||||
var groupEntry GroupEntry
|
||||
if line == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
idIdx := strings.Index(line, " Name: ")
|
||||
idPair := line[:idIdx]
|
||||
groupEntry.InternalId = strings.TrimPrefix(idPair, "Id: ")
|
||||
groupEntry.Id = convertInternalGroupIdToGroupId(groupEntry.InternalId)
|
||||
lineWithoutId := strings.TrimLeft(line[idIdx:], " ")
|
||||
|
||||
nameIdx := strings.Index(lineWithoutId, " Active: ")
|
||||
namePair := lineWithoutId[:nameIdx]
|
||||
groupEntry.Name = strings.TrimRight(strings.TrimPrefix(namePair, "Name: "), " ")
|
||||
lineWithoutName := strings.TrimLeft(lineWithoutId[nameIdx:], " ")
|
||||
|
||||
activeIdx := strings.Index(lineWithoutName, " Blocked: ")
|
||||
activePair := lineWithoutName[:activeIdx]
|
||||
active := strings.TrimPrefix(activePair, "Active: ")
|
||||
if active == "true" {
|
||||
groupEntry.Active = true
|
||||
} else {
|
||||
groupEntry.Active = false
|
||||
}
|
||||
lineWithoutActive := strings.TrimLeft(lineWithoutName[activeIdx:], " ")
|
||||
|
||||
blockedIdx := strings.Index(lineWithoutActive, " Members: ")
|
||||
blockedPair := lineWithoutActive[:blockedIdx]
|
||||
blocked := strings.TrimPrefix(blockedPair, "Blocked: ")
|
||||
if blocked == "true" {
|
||||
groupEntry.Blocked = true
|
||||
} else {
|
||||
groupEntry.Blocked = false
|
||||
}
|
||||
lineWithoutBlocked := strings.TrimLeft(lineWithoutActive[blockedIdx:], " ")
|
||||
|
||||
membersPair := lineWithoutBlocked
|
||||
members := strings.TrimPrefix(membersPair, "Members: ")
|
||||
trimmedMembers := strings.TrimRight(strings.TrimLeft(members, "["), "]")
|
||||
trimmedMembersList := strings.Split(trimmedMembers, ",")
|
||||
for _, member := range trimmedMembersList {
|
||||
groupEntry.Members = append(groupEntry.Members, strings.Trim(member, " "))
|
||||
}
|
||||
|
||||
groupEntries = append(groupEntries, groupEntry)
|
||||
}
|
||||
|
||||
return groupEntries, nil
|
||||
}
|
||||
|
||||
func runSignalCli(wait bool, args []string) (string, error) {
|
||||
cmd := exec.Command("signal-cli", args...)
|
||||
if wait {
|
||||
var errBuffer bytes.Buffer
|
||||
var outBuffer bytes.Buffer
|
||||
cmd.Stderr = &errBuffer
|
||||
cmd.Stdout = &outBuffer
|
||||
|
||||
err := cmd.Start()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
done := make(chan error, 1)
|
||||
go func() {
|
||||
done <- cmd.Wait()
|
||||
}()
|
||||
select {
|
||||
case <-time.After(60 * time.Second):
|
||||
err := cmd.Process.Kill()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return "", errors.New("process killed as timeout reached")
|
||||
case err := <-done:
|
||||
if err != nil {
|
||||
return "", errors.New(errBuffer.String())
|
||||
}
|
||||
}
|
||||
return outBuffer.String(), nil
|
||||
} else {
|
||||
stdout, err := cmd.StdoutPipe()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
cmd.Start()
|
||||
buf := bufio.NewReader(stdout) // Notice that this is not in a loop
|
||||
line, _, _ := buf.ReadLine()
|
||||
return string(line), nil
|
||||
}
|
||||
}
|
||||
// @tag.name Messages
|
||||
// @tag.description Send and Receive Signal Messages.
|
||||
|
||||
// @host 127.0.0.1:8080
|
||||
// @BasePath /
|
||||
func main() {
|
||||
signalCliConfig := flag.String("signal-cli-config", "/home/.local/share/signal-cli/", "Config directory where signal-cli config is stored")
|
||||
attachmentTmpDir := flag.String("attachment-tmp-dir", "/tmp/", "Attachment tmp directory")
|
||||
@@ -247,270 +40,53 @@ func main() {
|
||||
router := gin.Default()
|
||||
log.Info("Started Signal Messenger REST API")
|
||||
|
||||
router.GET("/v1/about", func(c *gin.Context) {
|
||||
type About struct {
|
||||
SupportedApiVersions []string `json:"versions"`
|
||||
BuildNr int `json:"build"`
|
||||
api := api.NewApi(*signalCliConfig, *attachmentTmpDir)
|
||||
v1 := router.Group("/v1")
|
||||
{
|
||||
about := v1.Group("/about")
|
||||
{
|
||||
about.GET("", api.About)
|
||||
}
|
||||
|
||||
about := About{SupportedApiVersions: []string{"v1", "v2"}, BuildNr: 2}
|
||||
c.JSON(200, about)
|
||||
})
|
||||
|
||||
router.POST("/v1/register/:number", func(c *gin.Context) {
|
||||
number := c.Param("number")
|
||||
|
||||
type Request struct {
|
||||
UseVoice bool `json:"use_voice"`
|
||||
register := v1.Group("/register")
|
||||
{
|
||||
register.POST(":number", api.RegisterNumber)
|
||||
register.POST(":number/verify/:token", api.VerifyRegisteredNumber)
|
||||
}
|
||||
|
||||
var req Request
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
buf.ReadFrom(c.Request.Body)
|
||||
if buf.String() != "" {
|
||||
err := json.Unmarshal(buf.Bytes(), &req)
|
||||
if err != nil {
|
||||
log.Error("Couldn't register number: ", err.Error())
|
||||
c.JSON(400, gin.H{"error": "Couldn't process request - invalid request."})
|
||||
return
|
||||
}
|
||||
} else {
|
||||
req.UseVoice = false
|
||||
sendV1 := v1.Group("/send")
|
||||
{
|
||||
sendV1.POST("", api.Send)
|
||||
}
|
||||
|
||||
if number == "" {
|
||||
c.JSON(400, gin.H{"error": "Please provide a number"})
|
||||
return
|
||||
receive := v1.Group("/receive")
|
||||
{
|
||||
receive.GET(":number", api.Receive)
|
||||
}
|
||||
|
||||
command := []string{"--config", *signalCliConfig, "-u", number, "register"}
|
||||
|
||||
if req.UseVoice == true {
|
||||
command = append(command, "--voice")
|
||||
groups := v1.Group("/groups")
|
||||
{
|
||||
groups.POST(":number", api.CreateGroup)
|
||||
groups.GET(":number", api.GetGroups)
|
||||
groups.DELETE(":number/:groupid", api.DeleteGroup)
|
||||
}
|
||||
|
||||
_, err := runSignalCli(true, command)
|
||||
if err != nil {
|
||||
c.JSON(400, gin.H{"error": err.Error()})
|
||||
return
|
||||
link := v1.Group("qrcodelink")
|
||||
{
|
||||
link.GET("", api.GetQrCodeLink)
|
||||
}
|
||||
c.JSON(201, nil)
|
||||
})
|
||||
}
|
||||
|
||||
router.POST("/v1/register/:number/verify/:token", func(c *gin.Context) {
|
||||
number := c.Param("number")
|
||||
token := c.Param("token")
|
||||
|
||||
if number == "" {
|
||||
c.JSON(400, gin.H{"error": "Please provide a number"})
|
||||
return
|
||||
v2 := router.Group("/v2")
|
||||
{
|
||||
sendV2 := v2.Group("/send")
|
||||
{
|
||||
sendV2.POST("", api.SendV2)
|
||||
}
|
||||
}
|
||||
|
||||
if token == "" {
|
||||
c.JSON(400, gin.H{"error": "Please provide a verification code"})
|
||||
return
|
||||
}
|
||||
|
||||
_, err := runSignalCli(true, []string{"--config", *signalCliConfig, "-u", number, "verify", token})
|
||||
if err != nil {
|
||||
c.JSON(400, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(201, nil)
|
||||
})
|
||||
|
||||
router.POST("/v1/send", func(c *gin.Context) {
|
||||
type Request struct {
|
||||
Number string `json:"number"`
|
||||
Recipients []string `json:"recipients"`
|
||||
Message string `json:"message"`
|
||||
Base64Attachment string `json:"base64_attachment"`
|
||||
IsGroup bool `json:"is_group"`
|
||||
}
|
||||
var req Request
|
||||
err := c.BindJSON(&req)
|
||||
if err != nil {
|
||||
c.JSON(400, gin.H{"error": "Couldn't process request - invalid request"})
|
||||
return
|
||||
}
|
||||
|
||||
base64Attachments := []string{}
|
||||
if req.Base64Attachment != "" {
|
||||
base64Attachments = append(base64Attachments, req.Base64Attachment)
|
||||
}
|
||||
|
||||
send(c, *signalCliConfig, *signalCliConfig, req.Number, req.Message, req.Recipients, base64Attachments, req.IsGroup)
|
||||
})
|
||||
|
||||
router.POST("/v2/send", func(c *gin.Context) {
|
||||
type Request struct {
|
||||
Number string `json:"number"`
|
||||
Recipients []string `json:"recipients"`
|
||||
Message string `json:"message"`
|
||||
Base64Attachments []string `json:"base64_attachments"`
|
||||
}
|
||||
var req Request
|
||||
err := c.BindJSON(&req)
|
||||
if err != nil {
|
||||
c.JSON(400, gin.H{"error": "Couldn't process request - invalid request"})
|
||||
log.Error(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if len(req.Recipients) == 0 {
|
||||
c.JSON(400, gin.H{"error": "Couldn't process request - please provide at least one recipient"})
|
||||
return
|
||||
}
|
||||
|
||||
groups := []string{}
|
||||
recipients := []string{}
|
||||
|
||||
for _, recipient := range req.Recipients {
|
||||
if strings.HasPrefix(recipient, groupPrefix) {
|
||||
groups = append(groups, strings.TrimPrefix(recipient, groupPrefix))
|
||||
} else {
|
||||
recipients = append(recipients, recipient)
|
||||
}
|
||||
}
|
||||
|
||||
if len(recipients) > 0 && len(groups) > 0 {
|
||||
c.JSON(400, gin.H{"error": "Signal Messenger Groups and phone numbers cannot be specified together in one request! Please split them up into multiple REST API calls."})
|
||||
return
|
||||
}
|
||||
|
||||
if len(groups) > 1 {
|
||||
c.JSON(400, gin.H{"error": "A signal message cannot be sent to more than one group at once! Please use multiple REST API calls for that."})
|
||||
return
|
||||
}
|
||||
|
||||
for _, group := range groups {
|
||||
send(c, *attachmentTmpDir, *signalCliConfig, req.Number, req.Message, []string{group}, req.Base64Attachments, true)
|
||||
}
|
||||
|
||||
if len(recipients) > 0 {
|
||||
send(c, *attachmentTmpDir, *signalCliConfig, req.Number, req.Message, recipients, req.Base64Attachments, false)
|
||||
}
|
||||
})
|
||||
|
||||
router.GET("/v1/receive/:number", func(c *gin.Context) {
|
||||
number := c.Param("number")
|
||||
|
||||
command := []string{"--config", *signalCliConfig, "-u", number, "receive", "-t", "1", "--json"}
|
||||
out, err := runSignalCli(true, command)
|
||||
if err != nil {
|
||||
c.JSON(400, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
out = strings.Trim(out, "\n")
|
||||
lines := strings.Split(out, "\n")
|
||||
|
||||
jsonStr := "["
|
||||
for i, line := range lines {
|
||||
jsonStr += line
|
||||
if i != (len(lines) - 1) {
|
||||
jsonStr += ","
|
||||
}
|
||||
}
|
||||
jsonStr += "]"
|
||||
|
||||
c.String(200, jsonStr)
|
||||
})
|
||||
|
||||
router.POST("/v1/groups/:number", func(c *gin.Context) {
|
||||
number := c.Param("number")
|
||||
|
||||
type Request struct {
|
||||
Name string `json:"name"`
|
||||
Members []string `json:"members"`
|
||||
}
|
||||
|
||||
var req Request
|
||||
err := c.BindJSON(&req)
|
||||
if err != nil {
|
||||
c.JSON(400, gin.H{"error": "Couldn't process request - invalid request"})
|
||||
log.Error(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
cmd := []string{"--config", *signalCliConfig, "-u", number, "updateGroup", "-n", req.Name, "-m"}
|
||||
cmd = append(cmd, req.Members...)
|
||||
|
||||
out, err := runSignalCli(true, cmd)
|
||||
if err != nil {
|
||||
c.JSON(400, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
internalGroupId := getStringInBetween(out, `"`, `"`)
|
||||
c.JSON(201, gin.H{"id": convertInternalGroupIdToGroupId(internalGroupId)})
|
||||
})
|
||||
|
||||
router.GET("/v1/groups/:number", func(c *gin.Context) {
|
||||
number := c.Param("number")
|
||||
|
||||
groups, err := getGroups(number, *signalCliConfig)
|
||||
if err != nil {
|
||||
c.JSON(400, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, groups)
|
||||
})
|
||||
|
||||
router.DELETE("/v1/groups/:number/:groupid", func(c *gin.Context) {
|
||||
base64EncodedGroupId := c.Param("groupid")
|
||||
number := c.Param("number")
|
||||
|
||||
if base64EncodedGroupId == "" {
|
||||
c.JSON(400, gin.H{"error": "Please specify a group id"})
|
||||
return
|
||||
}
|
||||
|
||||
groupId, err := base64.StdEncoding.DecodeString(strings.TrimPrefix(base64EncodedGroupId, groupPrefix))
|
||||
if err != nil {
|
||||
c.JSON(400, gin.H{"error": "Invalid group id"})
|
||||
return
|
||||
}
|
||||
|
||||
_, err = runSignalCli(true, []string{"--config", *signalCliConfig, "-u", number, "quitGroup", "-g", string(groupId)})
|
||||
if err != nil {
|
||||
c.JSON(400, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
})
|
||||
|
||||
router.GET("/v1/qrcodelink", func(c *gin.Context) {
|
||||
deviceName := c.Query("device_name")
|
||||
|
||||
if deviceName == "" {
|
||||
c.JSON(400, gin.H{"error": "Please provide a name for the device"})
|
||||
return
|
||||
}
|
||||
|
||||
command := []string{"--config", *signalCliConfig, "link", "-n", deviceName}
|
||||
|
||||
tsdeviceLink, err := runSignalCli(false, command)
|
||||
if err != nil {
|
||||
c.JSON(400, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
q, err := qrcode.New(string(tsdeviceLink), qrcode.Medium)
|
||||
if err != nil {
|
||||
c.JSON(400, gin.H{"error": err.Error()})
|
||||
}
|
||||
|
||||
q.DisableBorder = true
|
||||
var png []byte
|
||||
png, err = q.PNG(256)
|
||||
if err != nil {
|
||||
c.JSON(400, gin.H{"error": err.Error()})
|
||||
}
|
||||
|
||||
c.Data(200, "image/png", png)
|
||||
})
|
||||
swaggerUrl := ginSwagger.URL("http://127.0.0.1:8080/swagger/doc.json")
|
||||
router.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler, swaggerUrl))
|
||||
|
||||
router.Run()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user