diff --git a/src/api/api.go b/src/api/api.go index 00fc0cc..4bb27d9 100644 --- a/src/api/api.go +++ b/src/api/api.go @@ -9,8 +9,8 @@ import ( "github.com/gabriel-vasile/mimetype" "github.com/gin-gonic/gin" - log "github.com/sirupsen/logrus" "github.com/gorilla/websocket" + log "github.com/sirupsen/logrus" "github.com/bbernhard/signal-cli-rest-api/client" utils "github.com/bbernhard/signal-cli-rest-api/utils" @@ -29,23 +29,23 @@ const ( type GroupPermissions struct { AddMembers string `json:"add_members" enums:"only-admins,every-member"` - EditGroup string `json:"edit_group" enums:"only-admins,every-member"` + EditGroup string `json:"edit_group" enums:"only-admins,every-member"` } type CreateGroupRequest struct { - Name string `json:"name"` - Members []string `json:"members"` - Description string `json:"description"` - Permissions GroupPermissions `json:"permissions"` - GroupLinkState string `json:"group_link" enums:"disabled,enabled,enabled-with-approval"` + Name string `json:"name"` + Members []string `json:"members"` + Description string `json:"description"` + Permissions GroupPermissions `json:"permissions"` + GroupLinkState string `json:"group_link" enums:"disabled,enabled,enabled-with-approval"` } type LoggingConfiguration struct { - Level string `json:"Level"` + Level string `json:"Level"` } type Configuration struct { - Logging LoggingConfiguration `json:"logging"` + Logging LoggingConfiguration `json:"logging"` } type RegisterNumberRequest struct { @@ -57,6 +57,13 @@ type VerifyNumberSettings struct { Pin string `json:"pin"` } +type Reaction struct { + Recipient string `json:"recipient"` + Reaction string `json:"reaction"` + TargetAuthor string `json:"target_author"` + Timestamp int64 `json:"timestamp"` +} + type SendMessageV1 struct { Number string `json:"number"` Recipients []string `json:"recipients"` @@ -80,8 +87,6 @@ type Error struct { Msg string `json:"error"` } - - type CreateGroupResponse struct { Id string `json:"id"` } @@ -106,12 +111,12 @@ var connectionUpgrader = websocket.Upgrader{ } type Api struct { - signalClient *client.SignalClient + signalClient *client.SignalClient } func NewApi(signalClient *client.SignalClient) *Api { return &Api{ - signalClient: signalClient, + signalClient: signalClient, } } @@ -283,7 +288,6 @@ func (a *Api) SendV2(c *gin.Context) { c.JSON(201, SendMessageResponse{Timestamp: strconv.FormatInt((*timestamps)[0].Timestamp, 10)}) } - func (a *Api) handleSignalReceive(ws *websocket.Conn, number string) { for { data, err := a.signalClient.Receive(number, 0) @@ -404,7 +408,7 @@ func (a *Api) CreateGroup(c *gin.Context) { } if req.GroupLinkState != "" && !utils.StringInSlice(req.GroupLinkState, []string{"enabled", "enabled-with-approval", "disabled"}) { - c.JSON(400, Error{Msg: "Invalid group link provided - only 'enabled', 'enabled-with-approval' and 'disabled' allowed!" }) + c.JSON(400, Error{Msg: "Invalid group link provided - only 'enabled', 'enabled-with-approval' and 'disabled' allowed!"}) return } @@ -557,18 +561,18 @@ func (a *Api) RemoveAttachment(c *gin.Context) { err := a.signalClient.RemoveAttachment(attachment) if err != nil { switch err.(type) { - case *client.InvalidNameError: - c.JSON(400, Error{Msg: err.Error()}) - return - case *client.NotFoundError: - c.JSON(404, Error{Msg: err.Error()}) - return - case *client.InternalError: - c.JSON(500, Error{Msg: err.Error()}) - return - default: - c.JSON(500, Error{Msg: err.Error()}) - return + case *client.InvalidNameError: + c.JSON(400, Error{Msg: err.Error()}) + return + case *client.NotFoundError: + c.JSON(404, Error{Msg: err.Error()}) + return + case *client.InternalError: + c.JSON(500, Error{Msg: err.Error()}) + return + default: + c.JSON(500, Error{Msg: err.Error()}) + return } } @@ -589,18 +593,18 @@ func (a *Api) ServeAttachment(c *gin.Context) { attachmentBytes, err := a.signalClient.GetAttachment(attachment) if err != nil { switch err.(type) { - case *client.InvalidNameError: - c.JSON(400, Error{Msg: err.Error()}) - return - case *client.NotFoundError: - c.JSON(404, Error{Msg: err.Error()}) - return - case *client.InternalError: - c.JSON(500, Error{Msg: err.Error()}) - return - default: - c.JSON(500, Error{Msg: err.Error()}) - return + case *client.InvalidNameError: + c.JSON(400, Error{Msg: err.Error()}) + return + case *client.NotFoundError: + c.JSON(404, Error{Msg: err.Error()}) + return + case *client.InternalError: + c.JSON(500, Error{Msg: err.Error()}) + return + default: + c.JSON(500, Error{Msg: err.Error()}) + return } } @@ -890,6 +894,97 @@ 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 204 {string} OK +// @Failure 400 {object} Error +// @Param data body Reaction true "Reaction" +// @Router /v1/reactions/{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 + } + + number := c.Param("number") + + if req.Recipient == "" { + c.JSON(400, Error{Msg: "Couldn't process request - recipient missing"}) + 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 + } + + if req.Timestamp == 0 { + c.JSON(400, Error{Msg: "Couldn't process request - timestamp missing"}) + return + } + + err = a.signalClient.SendReaction(number, req.Recipient, req.Reaction, req.TargetAuthor, req.Timestamp, false) + if err != nil { + c.JSON(400, Error{Msg: err.Error()}) + return + } + c.Status(http.StatusNoContent) +} + +// @Summary Remove a reaction. +// @Tags Reactions +// @Description Remove a reaction +// @Accept json +// @Produce json +// @Success 204 {string} OK +// @Failure 400 {object} Error +// @Param data body Reaction true "Reaction" +// @Router /v1/reactions/{number} [delete] +func (a *Api) RemoveReaction(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 + } + + number := c.Param("number") + + if req.Recipient == "" { + c.JSON(400, Error{Msg: "Couldn't process request - recipient missing"}) + return + } + + if req.TargetAuthor == "" { + c.JSON(400, Error{Msg: "Couldn't process request - target_author missing"}) + return + } + + if req.Timestamp == 0 { + c.JSON(400, Error{Msg: "Couldn't process request - timestamp missing"}) + return + } + + err = a.signalClient.SendReaction(number, req.Recipient, req.Reaction, req.TargetAuthor, req.Timestamp, true) + if err != nil { + c.JSON(400, Error{Msg: err.Error()}) + return + } + c.Status(http.StatusNoContent) +} + // @Summary Show Typing Indicator. // @Tags Messages // @Description Show Typing Indicator. diff --git a/src/client/client.go b/src/client/client.go index e235ce7..7cbddd9 100644 --- a/src/client/client.go +++ b/src/client/client.go @@ -14,9 +14,10 @@ import ( "strings" "time" - "github.com/cyphar/filepath-securejoin" + securejoin "github.com/cyphar/filepath-securejoin" "github.com/gabriel-vasile/mimetype" "github.com/h2non/filetype" + //"github.com/sourcegraph/jsonrpc2"//"net/rpc/jsonrpc" log "github.com/sirupsen/logrus" @@ -613,8 +614,8 @@ func (s *SignalClient) CreateGroup(number string, name string, members []string, } type Response struct { - GroupId string `json:"groupId"` - Timestamp int64 `json:"timestamp"` + GroupId string `json:"groupId"` + Timestamp int64 `json:"timestamp"` } var resp Response json.Unmarshal([]byte(rawData), &resp) @@ -995,6 +996,69 @@ func (s *SignalClient) QuitGroup(number string, groupId string) error { return err } +func (s *SignalClient) SendReaction(number string, recipient string, emoji string, target_author string, timestamp int64, remove bool) error { + // see https://github.com/AsamK/signal-cli/blob/master/man/signal-cli.1.adoc#sendreaction + var err error + recp := recipient + isGroup := false + if strings.HasPrefix(recipient, groupPrefix) { + isGroup = true + recp, err = ConvertGroupIdToInternalGroupId(recipient) + if err != nil { + 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 { + Recipient string `json:"recipient,omitempty"` + GroupId string `json:"group-id,omitempty"` + Emoji string `json:"emoji"` + TargetAuthor string `json:"target-author"` + Timestamp int64 `json:"target-timestamp"` + Remove bool `json:"remove,omitempty"` + } + request := Request{} + if !isGroup { + request.Recipient = recp + } else { + request.GroupId = recp + } + request.Emoji = emoji + request.TargetAuthor = target_author + request.Timestamp = timestamp + if remove { + request.Remove = remove + } + jsonRpc2Client, err := s.getJsonRpc2Client(number) + if err != nil { + return err + } + _, err = jsonRpc2Client.getRaw("sendReaction", request) + return err + } + + cmd := []string{ + "--config", s.signalCliConfig, + "-u", number, + "sendReaction", + } + if !isGroup { + cmd = append(cmd, recp) + } else { + cmd = append(cmd, []string{"-g", recp}...) + } + cmd = append(cmd, []string{"-e", emoji, "-a", target_author, "-t", strconv.FormatInt(timestamp, 10)}...) + if remove { + cmd = append(cmd, "-r") + } + _, err = runSignalCli(true, cmd, "", s.signalCliMode) + return err +} + func (s *SignalClient) SendStartTyping(number string, recipient string) error { var err error recp := recipient @@ -1010,7 +1074,7 @@ func (s *SignalClient) SendStartTyping(number string, recipient string) error { if s.signalCliMode == JsonRpc { type Request struct { Recipient string `json:"recipient,omitempty"` - GroupId string `json:"group-id,omitempty"` + GroupId string `json:"group-id,omitempty"` } request := Request{} if !isGroup { @@ -1052,8 +1116,8 @@ func (s *SignalClient) SendStopTyping(number string, recipient string) error { if s.signalCliMode == JsonRpc { type Request struct { Recipient string `json:"recipient,omitempty"` - GroupId string `json:"group-id,omitempty"` - Stop bool `json:"stop"` + GroupId string `json:"group-id,omitempty"` + Stop bool `json:"stop"` } request := Request{Stop: true} if !isGroup { diff --git a/src/docs/swagger.json b/src/docs/swagger.json index 79e3b55..61f34a2 100644 --- a/src/docs/swagger.json +++ b/src/docs/swagger.json @@ -679,6 +679,101 @@ } } }, + "/v1/reactions/{number}": { + "post": { + "description": "React to a message.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Reactions" + ], + "summary": "Send a reaction.", + "parameters": [ + { + "description": "Reactions", + "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": [ + "Reactions" + ], + "summary": "Delete a reaction.", + "parameters": [ + { + "description": "Reactions", + "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": "Reactions" } ] } \ No newline at end of file diff --git a/src/docs/swagger.yaml b/src/docs/swagger.yaml index 018087e..aa00a0a 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: "204": 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: "204": description: No Content @@ -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: "204": description: No Content @@ -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: "204": description: No Content @@ -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/reactions/{number}: + post: + consumes: + - application/json + description: React to a message. + parameters: + - description: Reactions + 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: + - Reactions + delete: + consumes: + - application/json + description: Delete a reaction. + parameters: + - description: Reactions + 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: + - Reactions /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: "204": description: No Content @@ -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: "204": description: No Content @@ -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: Reactions +" \ No newline at end of file diff --git a/src/main.go b/src/main.go index c6ae4b8..7dd9bbf 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 Reactions +// @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) } + + reactions := v1.Group("/reactions") + { + reactions.POST(":number", api.SendReaction) + reactions.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() } - -