From 52b8cdf3f0d15e8d263268320a614a17df0bade5 Mon Sep 17 00:00:00 2001 From: Bernhard B Date: Sat, 20 Mar 2021 19:34:50 +0100 Subject: [PATCH] added API endpoint to react to messages see #110 --- doc/EXAMPLES.md | 11 ++++++++ src/api/api.go | 62 +++++++++++++++++++++++++++++++++++++++++++ src/docs/docs.go | 61 ++++++++++++++++++++++++++++++++++++++++++ src/docs/swagger.json | 61 ++++++++++++++++++++++++++++++++++++++++++ src/docs/swagger.yaml | 39 +++++++++++++++++++++++++++ src/main.go | 8 ++++++ 6 files changed, 242 insertions(+) diff --git a/doc/EXAMPLES.md b/doc/EXAMPLES.md index 2a18ab7..a505ed3 100644 --- a/doc/EXAMPLES.md +++ b/doc/EXAMPLES.md @@ -107,6 +107,17 @@ e.g: Due to security reason of Signal, the provided QR-Code will change with each request. +- React to a message + + `curl -X POST -H "Content-Type: application/json" -d '{"reaction": "", "timestamp": , "number": "", "recipient": ""}' 'http://127.0.0.1:8080/v1/react'` + + e.g: + + `curl -X POST -H "Content-Type: application/json" -d '{"reaction": "😀", "timestamp": 1616247771636, "number": "+431212131491291", "recipient": "+4354546464654"}' 'http://127.0.0.1:8080/v1/react'` + + The REST API endpoint requires you to specify the author and the timestamp of the message you want to react to. + The timestamp of the message you want to react to, can be obtained via the `/receive` endpoint. + The following REST API endpoints are **deprecated and no longer maintained!** `/v1/send` diff --git a/src/api/api.go b/src/api/api.go index 3cbfc8c..c1f1808 100644 --- a/src/api/api.go +++ b/src/api/api.go @@ -76,6 +76,13 @@ type VerifyNumberSettings struct { Pin string `json:"pin"` } +type Reaction struct { + Number string `json:"number"` + Timestamp int64 `json:"timestamp"` + Recipient string `json:"recipient"` + Reaction string `json:"reaction"` +} + type SendMessageV1 struct { Number string `json:"number"` Recipients []string `json:"recipients"` @@ -1224,3 +1231,58 @@ func (a *Api) QuitGroup(c *gin.Context) { } c.Status(http.StatusNoContent) } + +// @Summary Send a reaction. +// @Tags Reactions +// @Description React to a message. +// @Accept json +// @Produce json +// @Success 201 {string} OK +// @Failure 400 {object} Error +// @Param data body Reaction true "Reaction" +// @Router /v1/react/{number} [post] +func (a *Api) SendReaction(c *gin.Context) { + var req Reaction + err := c.BindJSON(&req) + if err != nil { + c.JSON(400, Error{Msg: "Couldn't process request - invalid request"}) + log.Error(err.Error()) + return + } + + if req.Recipient == "" { + c.JSON(400, Error{Msg: "Couldn't process request - recipient missing"}) + return + } + + if req.Timestamp == 0 { + c.JSON(400, Error{Msg: "Couldn't process request - timestamp missing"}) + return + } + + if req.Reaction == "" { + c.JSON(400, Error{Msg: "Couldn't process request - reaction missing"}) + return + } + + if req.Number == "" { + c.JSON(400, Error{Msg: "Couldn't process request - number missing"}) + return + } + + if strings.HasPrefix(req.Recipient, groupPrefix) { + c.JSON(500, Error{Msg: "Sending reactions to Signal Groups isn't implemented yet"}) + return + } + + + cmd := []string{"--config", a.signalCliConfig, "-u", req.Number, "sendReaction", req.Recipient, "-a", req.Recipient, "-t", + strconv.FormatInt(req.Timestamp, 10), "-e", req.Reaction} + + _, err = runSignalCli(true, cmd, "") + if err != nil { + c.JSON(400, Error{Msg: err.Error()}) + return + } + c.Status(http.StatusNoContent) +} diff --git a/src/docs/docs.go b/src/docs/docs.go index 0328e8d..9b672ba 100644 --- a/src/docs/docs.go +++ b/src/docs/docs.go @@ -685,6 +685,46 @@ var doc = `{ } } }, + "/v1/react/{number}": { + "post": { + "description": "React to a message.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Reactions" + ], + "summary": "Send a reaction.", + "parameters": [ + { + "description": "Reaction", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/api.Reaction" + } + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "type": "string" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/api.Error" + } + } + } + } + }, "/v1/receive/{number}": { "get": { "description": "Receives Signal Messages from the Signal Network.", @@ -1014,6 +1054,23 @@ var doc = `{ } } }, + "api.Reaction": { + "type": "object", + "properties": { + "number": { + "type": "string" + }, + "reaction": { + "type": "string" + }, + "recipient": { + "type": "string" + }, + "timestamp": { + "type": "integer" + } + } + }, "api.RegisterNumberRequest": { "type": "object", "properties": { @@ -1127,6 +1184,10 @@ var doc = `{ { "description": "List and Trust Identities.", "name": "Identities" + }, + { + "description": "React to messages.", + "name": "Reactions" } ] }` diff --git a/src/docs/swagger.json b/src/docs/swagger.json index 8585c45..13c92c1 100644 --- a/src/docs/swagger.json +++ b/src/docs/swagger.json @@ -670,6 +670,46 @@ } } }, + "/v1/react/{number}": { + "post": { + "description": "React to a message.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Reactions" + ], + "summary": "Send a reaction.", + "parameters": [ + { + "description": "Reaction", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/api.Reaction" + } + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "type": "string" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/api.Error" + } + } + } + } + }, "/v1/receive/{number}": { "get": { "description": "Receives Signal Messages from the Signal Network.", @@ -999,6 +1039,23 @@ } } }, + "api.Reaction": { + "type": "object", + "properties": { + "number": { + "type": "string" + }, + "reaction": { + "type": "string" + }, + "recipient": { + "type": "string" + }, + "timestamp": { + "type": "integer" + } + } + }, "api.RegisterNumberRequest": { "type": "object", "properties": { @@ -1112,6 +1169,10 @@ { "description": "List and Trust Identities.", "name": "Identities" + }, + { + "description": "React to messages.", + "name": "Reactions" } ] } \ No newline at end of file diff --git a/src/docs/swagger.yaml b/src/docs/swagger.yaml index d985659..12fc149 100644 --- a/src/docs/swagger.yaml +++ b/src/docs/swagger.yaml @@ -68,6 +68,17 @@ definitions: Level: type: string type: object + api.Reaction: + properties: + number: + type: string + reaction: + type: string + recipient: + type: string + timestamp: + type: integer + type: object api.RegisterNumberRequest: properties: captcha: @@ -567,6 +578,32 @@ paths: summary: Link device and generate QR code. tags: - Devices + /v1/react/{number}: + post: + consumes: + - application/json + description: React to a message. + parameters: + - description: Reaction + in: body + name: data + required: true + schema: + $ref: '#/definitions/api.Reaction' + produces: + - application/json + responses: + "201": + description: Created + schema: + type: string + "400": + description: Bad Request + schema: + $ref: '#/definitions/api.Error' + summary: Send a reaction. + tags: + - Reactions /v1/receive/{number}: get: consumes: @@ -729,3 +766,5 @@ tags: name: Profiles - description: List and Trust Identities. name: Identities +- description: React to messages. + name: Reactions diff --git a/src/main.go b/src/main.go index 47414b6..9ff7a0e 100644 --- a/src/main.go +++ b/src/main.go @@ -41,6 +41,9 @@ import ( // @tag.name Identities // @tag.description List and Trust Identities. +// @tag.name Reactions +// @tag.description React to messages. + // @host 127.0.0.1:8080 // @BasePath / func main() { @@ -136,6 +139,11 @@ func main() { identities.GET(":number", api.ListIdentities) identities.PUT(":number/trust/:numbertotrust", api.TrustIdentity) } + + react := v1.Group("react") + { + react.POST("", api.SendReaction) + } } v2 := router.Group("/v2")