diff --git a/docker-compose.yml b/docker-compose.yml index 194f112..3aa7d2c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,9 +1,11 @@ version: "3" services: signal-cli-rest-api: - image: bbernhard/signal-cli-rest-api:latest + #image: bbernhard/signal-cli-rest-api:latest + build: . environment: - - MODE=normal #supported modes: json-rpc, native, normal + # - MODE=normal #supported modes: json-rpc, native, normal + - MODE=json-rpc #supported modes: json-rpc, native, normal #- AUTO_RECEIVE_SCHEDULE=0 22 * * * #enable this parameter on demand (see description below) ports: - "8080:8080" #map docker port 8080 to host port 8080. diff --git a/src/api/api.go b/src/api/api.go index 834eee5..fb93516 100644 --- a/src/api/api.go +++ b/src/api/api.go @@ -902,7 +902,7 @@ func (a *Api) QuitGroup(c *gin.Context) { // @Success 204 {string} OK // @Failure 400 {object} Error // @Param data body Reaction true "Reaction" -// @Router /v1/reaction/{number} [post] +// @Router /v1/reactions/{number} [post] func (a *Api) SendReaction(c *gin.Context) { var req Reaction err := c.BindJSON(&req) @@ -950,7 +950,7 @@ func (a *Api) SendReaction(c *gin.Context) { // @Success 204 {string} OK // @Failure 400 {object} Error // @Param data body Reaction true "Reaction" -// @Router /v1/reaction/{number} [delete] +// @Router /v1/reactions/{number} [delete] func (a *Api) RemoveReaction(c *gin.Context) { var req Reaction err := c.BindJSON(&req) @@ -967,11 +967,6 @@ func (a *Api) RemoveReaction(c *gin.Context) { return } - if req.Reaction == "" { - c.JSON(400, Error{Msg: "Couldn't process request - reaction missing"}) - return - } - if req.TargetAuthor == "" { c.JSON(400, Error{Msg: "Couldn't process request - target_author missing"}) return diff --git a/src/client/client.go b/src/client/client.go index f6c14a7..862d3e5 100644 --- a/src/client/client.go +++ b/src/client/client.go @@ -1008,6 +1008,9 @@ func (s *SignalClient) SendReaction(number string, recipient string, emoji strin return errors.New("Invalid group id") } } + if remove && emoji == "" { + emoji = "👍" // emoji must not be empty to remove a reaction + } if s.signalCliMode == JsonRpc { type Request struct { @@ -1027,7 +1030,7 @@ func (s *SignalClient) SendReaction(number string, recipient string, emoji strin request.Emoji = emoji request.TargetAuthor = target_author request.Timestamp = timestamp - if remove == true { + if remove { request.Remove = remove } jsonRpc2Client, err := s.getJsonRpc2Client(number) diff --git a/src/docs/swagger.json b/src/docs/swagger.json index 4d58533..88f3fb8 100644 --- a/src/docs/swagger.json +++ b/src/docs/swagger.json @@ -679,6 +679,101 @@ } } }, + "/v1/reaction/{number}": { + "post": { + "description": "React to a message.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Reaction" + ], + "summary": "Send a reaction.", + "parameters": [ + { + "description": "Reaction", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/api.Reaction" + } + } + ], + "responses": { + "204": { + "description": "No Content", + "schema": { + "type": "string" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/api.Error" + } + } + } + }, + "delete": { + "description": "Delete a reaction.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Reaction" + ], + "summary": "Delete a reaction.", + "parameters": [ + { + "description": "Reaction", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/api.Reaction" + } + } + ], + "responses": { + "204": { + "description": "No Content", + "schema": { + "type": "string" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/api.Error" + } + } + } + } + }, + "api.Reaction": { + "type": "object", + "properties": { + "recipient": { + "type": "string" + }, + "reaction": { + "type": "string" + }, + "target_author": { + "type": "string" + }, + "timestamp": { + "type": "integer" + } + } + }, "/v1/receive/{number}": { "get": { "description": "Receives Signal Messages from the Signal Network. If you are running the docker container in normal/native mode, this is a GET endpoint. In json-rpc mode this is a websocket endpoint.", @@ -1280,6 +1375,10 @@ { "description": "List and Trust Identities.", "name": "Identities" + }, + { + "description": "React to messages.", + "name": "Reaction" } ] } \ No newline at end of file diff --git a/src/docs/swagger.yaml b/src/docs/swagger.yaml index 9b7aee6..4843583 100644 --- a/src/docs/swagger.yaml +++ b/src/docs/swagger.yaml @@ -1,9 +1,9 @@ -basePath: / +"basePath: / definitions: api.Configuration: properties: logging: - $ref: '#/definitions/api.LoggingConfiguration' + $ref: "#/definitions/api.LoggingConfiguration" type: object type: object api.CreateGroupRequest: @@ -12,9 +12,9 @@ definitions: type: string group_link: enum: - - disabled - - enabled - - enabled-with-approval + - disabled + - enabled + - enabled-with-approval type: string members: items: @@ -23,7 +23,7 @@ definitions: name: type: string permissions: - $ref: '#/definitions/api.GroupPermissions' + $ref: "#/definitions/api.GroupPermissions" type: object type: object api.CreateGroupResponse: @@ -40,13 +40,13 @@ definitions: properties: add_members: enum: - - only-admins - - every-member + - only-admins + - every-member type: string edit_group: enum: - - only-admins - - every-member + - only-admins + - every-member type: string type: object api.LoggingConfiguration: @@ -54,6 +54,17 @@ definitions: Level: type: string type: object + api.Reaction: + properties: + recipient: + type: string + reaction: + type: string + target_author: + type: string + timestamp: + type: integer + type: object api.RegisterNumberRequest: properties: captcha: @@ -179,20 +190,20 @@ paths: get: description: Returns the supported API versions and the internal build nr produces: - - application/json + - application/json responses: "200": description: OK schema: - $ref: '#/definitions/client.About' + $ref: "#/definitions/client.About" summary: Lists general information about the API tags: - - General + - General /v1/attachments: get: description: List all downloaded attachments produces: - - application/json + - application/json responses: "200": description: OK @@ -203,21 +214,21 @@ paths: "400": description: Bad Request schema: - $ref: '#/definitions/api.Error' + $ref: "#/definitions/api.Error" summary: List all attachments. tags: - - Attachments + - Attachments /v1/attachments/{attachment}: delete: description: Remove the attachment with the given id from filesystem. parameters: - - description: Attachment ID - in: path - name: attachment - required: true - type: string + - description: Attachment ID + in: path + name: attachment + required: true + type: string produces: - - application/json + - application/json responses: "204": description: No Content @@ -226,20 +237,20 @@ paths: "400": description: Bad Request schema: - $ref: '#/definitions/api.Error' + $ref: "#/definitions/api.Error" summary: Remove attachment. tags: - - Attachments + - Attachments get: description: Serve the attachment with the given id parameters: - - description: Attachment ID - in: path - name: attachment - required: true - type: string + - description: Attachment ID + in: path + name: attachment + required: true + type: string produces: - - application/json + - application/json responses: "200": description: OK @@ -248,42 +259,42 @@ paths: "400": description: Bad Request schema: - $ref: '#/definitions/api.Error' + $ref: "#/definitions/api.Error" summary: Serve Attachment. tags: - - Attachments + - Attachments /v1/configuration: get: consumes: - - application/json + - application/json description: List the REST API configuration. produces: - - application/json + - application/json responses: "200": description: OK schema: - $ref: '#/definitions/api.Configuration' + $ref: "#/definitions/api.Configuration" "400": description: Bad Request schema: - $ref: '#/definitions/api.Error' + $ref: "#/definitions/api.Error" summary: List the REST API configuration. tags: - - General + - General post: consumes: - - application/json + - application/json description: Set the REST API configuration. parameters: - - description: Configuration - in: body - name: data - required: true - schema: - $ref: '#/definitions/api.Configuration' + - description: Configuration + in: body + name: data + required: true + schema: + $ref: "#/definitions/api.Configuration" produces: - - application/json + - application/json responses: "201": description: OK @@ -292,85 +303,85 @@ paths: "400": description: Bad Request schema: - $ref: '#/definitions/api.Error' + $ref: "#/definitions/api.Error" summary: Set the REST API configuration. tags: - - General + - General /v1/groups/{number}: get: consumes: - - application/json + - application/json description: List all Signal Groups. parameters: - - description: Registered Phone Number - in: path - name: number - required: true - type: string + - description: Registered Phone Number + in: path + name: number + required: true + type: string produces: - - application/json + - application/json responses: "200": description: OK schema: items: - $ref: '#/definitions/client.GroupEntry' + $ref: "#/definitions/client.GroupEntry" type: array "400": description: Bad Request schema: - $ref: '#/definitions/api.Error' + $ref: "#/definitions/api.Error" summary: List all Signal Groups. tags: - - Groups + - Groups post: consumes: - - application/json + - application/json description: Create a new Signal Group with the specified members. parameters: - - description: Input Data - in: body - name: data - required: true - schema: - $ref: '#/definitions/api.CreateGroupRequest' - - 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.CreateGroupRequest" + - description: Registered Phone Number + in: path + name: number + required: true + type: string produces: - - application/json + - application/json responses: "201": description: Created schema: - $ref: '#/definitions/api.CreateGroupResponse' + $ref: "#/definitions/api.CreateGroupResponse" "400": description: Bad Request schema: - $ref: '#/definitions/api.Error' + $ref: "#/definitions/api.Error" summary: Create a new Signal Group. tags: - - Groups + - Groups /v1/groups/{number}/{groupid}: delete: consumes: - - application/json + - application/json description: Delete the specified 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 + - 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 + - application/json responses: "200": description: OK @@ -379,57 +390,57 @@ paths: "400": description: Bad Request schema: - $ref: '#/definitions/api.Error' + $ref: "#/definitions/api.Error" summary: Delete a Signal Group. tags: - - Groups + - Groups get: consumes: - - application/json + - application/json description: List a specific 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 + - 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 + - application/json responses: "200": description: OK schema: - $ref: '#/definitions/client.GroupEntry' + $ref: "#/definitions/client.GroupEntry" "400": description: Bad Request schema: - $ref: '#/definitions/api.Error' + $ref: "#/definitions/api.Error" summary: List a Signal Group. tags: - - Groups + - Groups /v1/groups/{number}/{groupid}/block: post: consumes: - - application/json + - application/json description: Block the specified 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 + - 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 + - application/json responses: "200": description: OK @@ -438,28 +449,28 @@ paths: "400": description: Bad Request schema: - $ref: '#/definitions/api.Error' + $ref: "#/definitions/api.Error" summary: Block a Signal Group. tags: - - Groups + - Groups /v1/groups/{number}/{groupid}/join: post: consumes: - - application/json + - application/json description: Join the specified 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 + - 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 + - application/json responses: "200": description: OK @@ -468,28 +479,28 @@ paths: "400": description: Bad Request schema: - $ref: '#/definitions/api.Error' + $ref: "#/definitions/api.Error" summary: Join a Signal Group. tags: - - Groups + - Groups /v1/groups/{number}/{groupid}/quit: post: consumes: - - application/json + - application/json description: Quit the specified 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 + - 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 + - application/json responses: "200": description: OK @@ -498,15 +509,15 @@ paths: "400": description: Bad Request schema: - $ref: '#/definitions/api.Error' + $ref: "#/definitions/api.Error" summary: Quit a Signal Group. tags: - - Groups + - Groups /v1/health: get: description: Internally used by the docker container to perform the health check. produces: - - application/json + - application/json responses: "204": description: No Content @@ -514,50 +525,50 @@ paths: type: string summary: API Health Check tags: - - General + - General /v1/identities/{number}: get: description: List all identities for the given number. parameters: - - description: Registered Phone Number - in: path - name: number - required: true - type: string + - description: Registered Phone Number + in: path + name: number + required: true + type: string produces: - - application/json + - application/json responses: "200": description: OK schema: items: - $ref: '#/definitions/client.IdentityEntry' + $ref: "#/definitions/client.IdentityEntry" type: array summary: List Identities tags: - - Identities + - Identities /v1/identities/{number}/trust/{numberToTrust}: put: description: Trust an identity. parameters: - - description: Input Data - in: body - name: data - required: true - schema: - $ref: '#/definitions/api.TrustIdentityRequest' - - description: Registered Phone Number - in: path - name: number - required: true - type: string - - description: Number To Trust - in: path - name: numberToTrust - required: true - type: string + - description: Input Data + in: body + name: data + required: true + schema: + $ref: "#/definitions/api.TrustIdentityRequest" + - description: Registered Phone Number + in: path + name: number + required: true + type: string + - description: Number To Trust + in: path + name: numberToTrust + required: true + type: string produces: - - application/json + - application/json responses: "204": description: No Content @@ -565,24 +576,24 @@ paths: type: string summary: Trust Identity tags: - - Identities + - Identities /v1/profiles/{number}: put: description: Set your name and optional an avatar. parameters: - - description: Profile Data - in: body - name: data - required: true - schema: - $ref: '#/definitions/api.UpdateProfileRequest' - - description: Registered Phone Number - in: path - name: number - required: true - type: string + - description: Profile Data + in: body + name: data + required: true + schema: + $ref: "#/definitions/api.UpdateProfileRequest" + - description: Registered Phone Number + in: path + name: number + required: true + type: string produces: - - application/json + - application/json responses: "204": description: No Content @@ -591,21 +602,21 @@ paths: "400": description: Bad Request schema: - $ref: '#/definitions/api.Error' + $ref: "#/definitions/api.Error" summary: Update Profile. tags: - - Profiles + - Profiles /v1/qrcodelink: get: description: Link device and generate QR code parameters: - - description: Device Name - in: query - name: device_name - required: true - type: string + - description: Device Name + in: query + name: device_name + required: true + type: string produces: - - application/json + - application/json responses: "200": description: Image @@ -614,27 +625,78 @@ paths: "400": description: Bad Request schema: - $ref: '#/definitions/api.Error' + $ref: "#/definitions/api.Error" summary: Link device and generate QR code. tags: - - Devices + - Devices + /v1/reaction/{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: + "204": + description: No Content + schema: + type: string + "400": + description: Bad Request + schema: + $ref: '#/definitions/api.Error' + summary: Send a reaction. + tags: + - Reaction + delete: + consumes: + - application/json + description: Delete a reaction. + parameters: + - description: Reaction + in: body + name: data + required: true + schema: + $ref: '#/definitions/api.Reaction' + produces: + - application/json + responses: + "204": + description: No Content + schema: + type: string + "400": + description: Bad Request + schema: + $ref: '#/definitions/api.Error' + summary: Delete a reaction. + tags: + - Reaction /v1/receive/{number}: get: consumes: - - application/json + - application/json description: Receives Signal Messages from the Signal Network. If you are running the docker container in normal/native mode, this is a GET endpoint. In json-rpc mode this is a websocket endpoint. parameters: - - description: Registered Phone Number - in: path - name: number - required: true - type: string - - description: 'Receive timeout in seconds (default: 1)' - in: query - name: timeout - type: string + - description: Registered Phone Number + in: path + name: number + required: true + type: string + - description: "Receive timeout in seconds (default: 1)" + in: query + name: timeout + type: string produces: - - application/json + - application/json responses: "200": description: OK @@ -645,60 +707,60 @@ paths: "400": description: Bad Request schema: - $ref: '#/definitions/api.Error' + $ref: "#/definitions/api.Error" summary: Receive Signal Messages. tags: - - Messages + - Messages /v1/register/{number}: post: consumes: - - application/json + - application/json description: Register a phone number with the signal network. parameters: - - description: Registered Phone Number - in: path - name: number - required: true - type: string - - description: Additional Settings - in: body - name: data - schema: - $ref: '#/definitions/api.RegisterNumberRequest' + - description: Registered Phone Number + in: path + name: number + required: true + type: string + - description: Additional Settings + in: body + name: data + schema: + $ref: "#/definitions/api.RegisterNumberRequest" produces: - - application/json + - application/json responses: "201": {} "400": description: Bad Request schema: - $ref: '#/definitions/api.Error' + $ref: "#/definitions/api.Error" summary: Register a phone number. tags: - - Devices + - Devices /v1/register/{number}/verify/{token}: post: consumes: - - application/json + - 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: Additional Settings - in: body - name: data - schema: - $ref: '#/definitions/api.VerifyNumberSettings' - - description: Verification Code - in: path - name: token - required: true - type: string + - description: Registered Phone Number + in: path + name: number + required: true + type: string + - description: Additional Settings + in: body + name: data + schema: + $ref: "#/definitions/api.VerifyNumberSettings" + - description: Verification Code + in: path + name: token + required: true + type: string produces: - - application/json + - application/json responses: "201": description: OK @@ -707,25 +769,25 @@ paths: "400": description: Bad Request schema: - $ref: '#/definitions/api.Error' + $ref: "#/definitions/api.Error" summary: Verify a registered phone number. tags: - - Devices + - Devices /v1/send: post: consumes: - - application/json + - application/json deprecated: true description: Send a signal message parameters: - - description: Input Data - in: body - name: data - required: true - schema: - $ref: '#/definitions/api.SendMessageV1' + - description: Input Data + in: body + name: data + required: true + schema: + $ref: "#/definitions/api.SendMessageV1" produces: - - application/json + - application/json responses: "201": description: OK @@ -734,29 +796,29 @@ paths: "400": description: Bad Request schema: - $ref: '#/definitions/api.Error' + $ref: "#/definitions/api.Error" summary: Send a signal message. tags: - - Messages + - Messages /v1/typing-indicator/{number}: delete: consumes: - - application/json + - application/json description: Hide Typing Indicator. parameters: - - description: Registered Phone Number - in: path - name: number - required: true - type: string - - description: Type - in: body - name: data - required: true - schema: - $ref: '#/definitions/api.TypingIndicatorRequest' + - description: Registered Phone Number + in: path + name: number + required: true + type: string + - description: Type + in: body + name: data + required: true + schema: + $ref: "#/definitions/api.TypingIndicatorRequest" produces: - - application/json + - application/json responses: "201": description: Created @@ -765,28 +827,28 @@ paths: "400": description: Bad Request schema: - $ref: '#/definitions/api.Error' + $ref: "#/definitions/api.Error" summary: Hide Typing Indicator. tags: - - Messages + - Messages put: consumes: - - application/json + - application/json description: Show Typing Indicator. parameters: - - description: Registered Phone Number - in: path - name: number - required: true - type: string - - description: Type - in: body - name: data - required: true - schema: - $ref: '#/definitions/api.TypingIndicatorRequest' + - description: Registered Phone Number + in: path + name: number + required: true + type: string + - description: Type + in: body + name: data + required: true + schema: + $ref: "#/definitions/api.TypingIndicatorRequest" produces: - - application/json + - application/json responses: "201": description: Created @@ -795,49 +857,52 @@ paths: "400": description: Bad Request schema: - $ref: '#/definitions/api.Error' + $ref: "#/definitions/api.Error" summary: Show Typing Indicator. tags: - - Messages + - Messages /v2/send: post: consumes: - - application/json + - application/json description: Send a signal message parameters: - - description: Input Data - in: body - name: data - required: true - schema: - $ref: '#/definitions/api.SendMessageV2' + - description: Input Data + in: body + name: data + required: true + schema: + $ref: "#/definitions/api.SendMessageV2" produces: - - application/json + - application/json responses: "201": description: Created schema: - $ref: '#/definitions/api.SendMessageResponse' + $ref: "#/definitions/api.SendMessageResponse" "400": description: Bad Request schema: - $ref: '#/definitions/api.Error' + $ref: "#/definitions/api.Error" summary: Send a signal message. tags: - - Messages + - Messages swagger: "2.0" tags: -- description: Some general endpoints. - 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 -- description: List and Delete Attachments. - name: Attachments -- description: Update Profile. - name: Profiles -- description: List and Trust Identities. - name: Identities + - description: Some general endpoints. + 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 + - description: List and Delete Attachments. + name: Attachments + - description: Update Profile. + name: Profiles + - description: List and Trust Identities. + name: Identities + - description: React to messages. + name: Reaction +" \ No newline at end of file diff --git a/src/main.go b/src/main.go index c6ae4b8..3c27477 100644 --- a/src/main.go +++ b/src/main.go @@ -46,6 +46,9 @@ import ( // @tag.name Identities // @tag.description List and Trust Identities. +// @tag.name Reaction +// @tag.description React to messages. + // @host 127.0.0.1:8080 // @BasePath / func main() { @@ -114,7 +117,6 @@ func main() { } } - jsonRpc2ClientConfigPathPath := *signalCliConfig + "/jsonrpc2.yml" signalClient := client.NewSignalClient(*signalCliConfig, *attachmentTmpDir, *avatarTmpDir, signalCliMode, jsonRpc2ClientConfigPathPath) err = signalClient.Init() @@ -196,6 +198,12 @@ func main() { typingIndicator.PUT(":number", api.SendStartTyping) typingIndicator.DELETE(":number", api.SendStopTyping) } + + reaction := v1.Group("/reaction") + { + reaction.POST(":number", api.SendReaction) + reaction.DELETE(":number", api.RemoveReaction) + } } v2 := router.Group("/v2") @@ -228,7 +236,7 @@ func main() { filename := filepath.Base(path) if strings.HasPrefix(filename, "+") && info.Mode().IsRegular() { log.Debug("AUTO_RECEIVE_SCHEDULE: Calling receive for number ", filename) - resp, err := http.Get("http://127.0.0.1:" + port + "/v1/receive/"+filename) + resp, err := http.Get("http://127.0.0.1:" + port + "/v1/receive/" + filename) if err != nil { log.Error("AUTO_RECEIVE_SCHEDULE: Couldn't call receive for number ", filename, ": ", err.Error()) } @@ -241,7 +249,7 @@ func main() { } type ReceiveResponse struct { - Error string `json:"error"` + Error string `json:"error"` } var receiveResponse ReceiveResponse err = json.Unmarshal(jsonResp, &receiveResponse) @@ -264,8 +272,5 @@ func main() { c.Start() } - router.Run() } - -