Merge pull request #20 from danijelst/master

Add Endpoint for link to existing device
This commit is contained in:
Bernhard B
2020-06-28 17:56:47 +02:00
committed by GitHub
2 changed files with 142 additions and 91 deletions

105
README.md
View File

@@ -2,13 +2,11 @@
This project creates a small dockerized REST API around [signal-cli](https://github.com/AsamK/signal-cli). This project creates a small dockerized REST API around [signal-cli](https://github.com/AsamK/signal-cli).
At the moment, the following functionality is exposed via REST: At the moment, the following functionality is exposed via REST:
* Register a number - Register a number
* Verify the number using the code received via SMS - Verify the number using the code received via SMS
* Send message (+ attachment) to multiple recipients - Send message (+ attachment) to multiple recipients
## Examples ## Examples
@@ -29,95 +27,104 @@ services:
Sample REST API calls: Sample REST API calls:
* Register a number (with SMS verification) - Register a number (with SMS verification)
```curl -X POST -H "Content-Type: application/json" 'http://127.0.0.1:8080/v1/register/<number>'``` `curl -X POST -H "Content-Type: application/json" 'http://127.0.0.1:8080/v1/register/<number>'`
e.g:
`curl -X POST -H "Content-Type: application/json" 'http://127.0.0.1:8080/v1/register/+431212131491291'`
- Register a number (with voice verification)
`curl -X POST -H "Content-Type: application/json" --data '{"use_voice": true}' 'http://127.0.0.1:8080/v1/register/<number>'`
e.g:
`curl -X POST -H "Content-Type: application/json" --data '{"use_voice": true}' 'http://127.0.0.1:8080/v1/register/+431212131491291'`
- Verify the number using the code received via SMS/voice
`curl -X POST -H "Content-Type: application/json" 'http://127.0.0.1:8080/v1/register/<number>/verify/<verification code>'`
e.g: e.g:
```curl -X POST -H "Content-Type: application/json" 'http://127.0.0.1:8080/v1/register/+431212131491291'``` `curl -X POST -H "Content-Type: application/json" 'http://127.0.0.1:8080/v1/register/+431212131491291/verify/123-456'`
* Register a number (with voice verification) - Send a message to multiple recipients
```curl -X POST -H "Content-Type: application/json" --data '{"use_voice": true}' 'http://127.0.0.1:8080/v1/register/<number>'``` `curl -X POST -H "Content-Type: application/json" -d '{"message": "<message>", "number": "<number>", "recipients": ["<recipient1>", "<recipient2>"]}' 'http://127.0.0.1:8080/v2/send'`
e.g: e.g:
```curl -X POST -H "Content-Type: application/json" --data '{"use_voice": true}' 'http://127.0.0.1:8080/v1/register/+431212131491291'``` `curl -X POST -H "Content-Type: application/json" -d '{"message": "Hello World!", "number": "+431212131491291", "recipients": ["+4354546464654", "+4912812812121"]}' 'http://127.0.0.1:8080/v2/send'`
* Verify the number using the code received via SMS/voice - Send a message (+ base64 encoded attachment) to multiple recipients
```curl -X POST -H "Content-Type: application/json" 'http://127.0.0.1:8080/v1/register/<number>/verify/<verification code>'``` `curl -X POST -H "Content-Type: application/json" -d '{"message": "<message>", "base64_attachments": ["<base64 encoded attachment>"], "number": "<number>", "recipients": ["<recipient1>", "<recipient2>"]}' 'http://127.0.0.1:8080/v2/send'`
- Send a message to a group
The group id can be obtained via the "List groups" REST call.
`curl -X POST -H "Content-Type: application/json" -d '{"message": "<message>", "number": "<number>", "recipients": ["<group id>"]}' 'http://127.0.0.1:8080/v2/send'`
e.g: e.g:
```curl -X POST -H "Content-Type: application/json" 'http://127.0.0.1:8080/v1/register/+431212131491291/verify/123-456'``` `curl -X POST -H "Content-Type: application/json" -d '{"message": "Hello World!", "number": "+431212131491291", "recipients": ["group.ckRzaEd4VmRzNnJaASAEsasa", "+4912812812121"]}' 'http://127.0.0.1:8080/v2/send'`
* Send a message to multiple recipients - Receive messages
```curl -X POST -H "Content-Type: application/json" -d '{"message": "<message>", "number": "<number>", "recipients": ["<recipient1>", "<recipient2>"]}' 'http://127.0.0.1:8080/v2/send'```
e.g:
```curl -X POST -H "Content-Type: application/json" -d '{"message": "Hello World!", "number": "+431212131491291", "recipients": ["+4354546464654", "+4912812812121"]}' 'http://127.0.0.1:8080/v2/send'```
* Send a message (+ base64 encoded attachment) to multiple recipients
```curl -X POST -H "Content-Type: application/json" -d '{"message": "<message>", "base64_attachments": ["<base64 encoded attachment>"], "number": "<number>", "recipients": ["<recipient1>", "<recipient2>"]}' 'http://127.0.0.1:8080/v2/send'```
* Send a message to a group
The group id can be obtained via the "List groups" REST call.
```curl -X POST -H "Content-Type: application/json" -d '{"message": "<message>", "number": "<number>", "recipients": ["<group id>"]}' 'http://127.0.0.1:8080/v2/send'```
e.g:
```curl -X POST -H "Content-Type: application/json" -d '{"message": "Hello World!", "number": "+431212131491291", "recipients": ["group.ckRzaEd4VmRzNnJaASAEsasa", "+4912812812121"]}' 'http://127.0.0.1:8080/v2/send'```
* Receive messages
Fetch all new messages in the inbox of the specified number. Fetch all new messages in the inbox of the specified number.
```curl -X GET -H "Content-Type: application/json" 'http://127.0.0.1:8080/v1/receive/<number>'``` `curl -X GET -H "Content-Type: application/json" 'http://127.0.0.1:8080/v1/receive/<number>'`
e.g: e.g:
```curl -X GET -H "Content-Type: application/json" 'http://127.0.0.1:8080/v1/receive/+431212131491291'``` `curl -X GET -H "Content-Type: application/json" 'http://127.0.0.1:8080/v1/receive/+431212131491291'`
* Create a new group - Create a new group
Create a new group with the specified name and members. Create a new group with the specified name and members.
```curl -X POST -H "Content-Type: application/json" -d '{"name": "<group name>", "members": ["<member1>", "<member2>"]}' 'http://127.0.0.1:8080/v1/groups/<number>'``` `curl -X POST -H "Content-Type: application/json" -d '{"name": "<group name>", "members": ["<member1>", "<member2>"]}' 'http://127.0.0.1:8080/v1/groups/<number>'`
e.g: e.g:
```curl -X POST -H "Content-Type: application/json" -d '{"name": "my group", "members": ["+4354546464654", "+4912812812121"]}' 'http://127.0.0.1:8080/v1/groups/+431212131491291'``` `curl -X POST -H "Content-Type: application/json" -d '{"name": "my group", "members": ["+4354546464654", "+4912812812121"]}' 'http://127.0.0.1:8080/v1/groups/+431212131491291'`
* List groups - List groups
```curl -X GET -H "Content-Type: application/json" 'http://127.0.0.1:8080/v1/groups/<number>'``` `curl -X GET -H "Content-Type: application/json" 'http://127.0.0.1:8080/v1/groups/<number>'`
e.g: e.g:
```curl -X GET -H "Content-Type: application/json" 'http://127.0.0.1:8080/v1/groups/+431212131491291'``` `curl -X GET -H "Content-Type: application/json" 'http://127.0.0.1:8080/v1/groups/+431212131491291'`
* Delete a group - Delete a group
Delete the group with the given group id. The group id can be obtained via the "List groups" REST call. Delete the group with the given group id. The group id can be obtained via the "List groups" REST call.
```curl -X DELETE -H "Content-Type: application/json" 'http://127.0.0.1:8080/v1/groups/<number>/<group id>'``` `curl -X DELETE -H "Content-Type: application/json" 'http://127.0.0.1:8080/v1/groups/<number>/<group id>'`
e.g: e.g:
```curl -X DELETE -H "Content-Type: application/json" 'http://127.0.0.1:8080/v1/groups/+431212131491291/ckRzaEd4VmRzNnJaASAEsasa'``` `curl -X DELETE -H "Content-Type: application/json" 'http://127.0.0.1:8080/v1/groups/+431212131491291/ckRzaEd4VmRzNnJaASAEsasa'`
- Link a device
`curl -X POST -H "Content-Type: application/json" 'http://127.0.0.1:8080/v1/qrcodelink?<device name>'`
e.g:
`curl -X POST -H "Content-Type: application/json" 'http://127.0.0.1:8080/v1/qrcodelink?HomeAssistant'`
This provides a QR-Code image. In case of an error a JSON object will be returned.
Due to security reason of Signal, the provided QR-Code will change with each request.
The following REST API endpoints are **deprecated and no longer maintained!** The following REST API endpoints are **deprecated and no longer maintained!**
```/v1/send``` `/v1/send`
In case you need more functionality, please **file a ticket** or **create a PR** In case you need more functionality, please **file a ticket** or **create a PR**

View File

@@ -1,19 +1,22 @@
package main package main
import ( import (
"bufio"
"bytes" "bytes"
"encoding/base64" "encoding/base64"
"encoding/json" "encoding/json"
"errors" "errors"
"flag" "flag"
"github.com/gin-gonic/gin"
"github.com/h2non/filetype"
"github.com/satori/go.uuid"
log "github.com/sirupsen/logrus"
"os" "os"
"os/exec" "os/exec"
"strings" "strings"
"time" "time"
"github.com/gin-gonic/gin"
"github.com/h2non/filetype"
uuid "github.com/satori/go.uuid"
log "github.com/sirupsen/logrus"
qrcode "github.com/skip2/go-qrcode"
) )
const groupPrefix = "group." const groupPrefix = "group."
@@ -31,7 +34,6 @@ func convertInternalGroupIdToGroupId(internalId string) string {
return groupPrefix + base64.StdEncoding.EncodeToString([]byte(internalId)) return groupPrefix + base64.StdEncoding.EncodeToString([]byte(internalId))
} }
func getStringInBetween(str string, start string, end string) (result string) { func getStringInBetween(str string, start string, end string) (result string) {
i := strings.Index(str, start) i := strings.Index(str, start)
if i == -1 { if i == -1 {
@@ -126,7 +128,7 @@ func send(c *gin.Context, attachmentTmpDir string, signalCliConfig string, numbe
cmd = append(cmd, attachmentTmpPaths...) cmd = append(cmd, attachmentTmpPaths...)
} }
_, err := runSignalCli(cmd) _, err := runSignalCli(true, cmd)
if err != nil { if err != nil {
cleanupTmpFiles(attachmentTmpPaths) cleanupTmpFiles(attachmentTmpPaths)
c.JSON(400, gin.H{"error": err.Error()}) c.JSON(400, gin.H{"error": err.Error()})
@@ -138,7 +140,7 @@ func send(c *gin.Context, attachmentTmpDir string, signalCliConfig string, numbe
func getGroups(number string, signalCliConfig string) ([]GroupEntry, error) { func getGroups(number string, signalCliConfig string) ([]GroupEntry, error) {
groupEntries := []GroupEntry{} groupEntries := []GroupEntry{}
out, err := runSignalCli([]string{"--config", signalCliConfig, "-u", number, "listGroups", "-d"}) out, err := runSignalCli(true, []string{"--config", signalCliConfig, "-u", number, "listGroups", "-d"})
if err != nil { if err != nil {
return groupEntries, err return groupEntries, err
} }
@@ -195,8 +197,9 @@ func getGroups(number string, signalCliConfig string) ([]GroupEntry, error) {
return groupEntries, nil return groupEntries, nil
} }
func runSignalCli(args []string) (string, error) { func runSignalCli(wait bool, args []string) (string, error) {
cmd := exec.Command("signal-cli", args...) cmd := exec.Command("signal-cli", args...)
if wait {
var errBuffer bytes.Buffer var errBuffer bytes.Buffer
var outBuffer bytes.Buffer var outBuffer bytes.Buffer
cmd.Stderr = &errBuffer cmd.Stderr = &errBuffer
@@ -224,6 +227,16 @@ func runSignalCli(args []string) (string, error) {
} }
} }
return outBuffer.String(), nil 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
}
} }
func main() { func main() {
@@ -277,7 +290,7 @@ func main() {
command = append(command, "--voice") command = append(command, "--voice")
} }
_, err := runSignalCli(command) _, err := runSignalCli(true, command)
if err != nil { if err != nil {
c.JSON(400, gin.H{"error": err.Error()}) c.JSON(400, gin.H{"error": err.Error()})
return return
@@ -299,7 +312,7 @@ func main() {
return return
} }
_, err := runSignalCli([]string{"--config", *signalCliConfig, "-u", number, "verify", token}) _, err := runSignalCli(true, []string{"--config", *signalCliConfig, "-u", number, "verify", token})
if err != nil { if err != nil {
c.JSON(400, gin.H{"error": err.Error()}) c.JSON(400, gin.H{"error": err.Error()})
return return
@@ -384,7 +397,7 @@ func main() {
number := c.Param("number") number := c.Param("number")
command := []string{"--config", *signalCliConfig, "-u", number, "receive", "-t", "1", "--json"} command := []string{"--config", *signalCliConfig, "-u", number, "receive", "-t", "1", "--json"}
out, err := runSignalCli(command) out, err := runSignalCli(true, command)
if err != nil { if err != nil {
c.JSON(400, gin.H{"error": err.Error()}) c.JSON(400, gin.H{"error": err.Error()})
return return
@@ -424,7 +437,7 @@ func main() {
cmd := []string{"--config", *signalCliConfig, "-u", number, "updateGroup", "-n", req.Name, "-m"} cmd := []string{"--config", *signalCliConfig, "-u", number, "updateGroup", "-n", req.Name, "-m"}
cmd = append(cmd, req.Members...) cmd = append(cmd, req.Members...)
out, err := runSignalCli(cmd) out, err := runSignalCli(true, cmd)
if err != nil { if err != nil {
c.JSON(400, gin.H{"error": err.Error()}) c.JSON(400, gin.H{"error": err.Error()})
return return
@@ -461,12 +474,43 @@ func main() {
return return
} }
_, err = runSignalCli([]string{"--config", *signalCliConfig, "-u", number, "quitGroup", "-g", string(groupId)}) _, err = runSignalCli(true, []string{"--config", *signalCliConfig, "-u", number, "quitGroup", "-g", string(groupId)})
if err != nil { if err != nil {
c.JSON(400, gin.H{"error": err.Error()}) c.JSON(400, gin.H{"error": err.Error()})
return 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)
})
router.Run() router.Run()
} }