diff --git a/src/api/api.go b/src/api/api.go index d0a476a..2462129 100644 --- a/src/api/api.go +++ b/src/api/api.go @@ -163,6 +163,10 @@ type SendMessageResponse struct { Timestamp string `json:"timestamp"` } +type RemoteDeleteResponse struct { + Timestamp string `json:"timestamp"` +} + type TrustModeRequest struct { TrustMode string `json:"trust_mode"` } @@ -209,6 +213,11 @@ type SetPinRequest struct { Pin string `json:"pin"` } +type RemoteDeleteRequest struct { + Recipient string `json:"recipient"` + Timestamp int64 `json:"timestamp"` +} + type Api struct { signalClient *client.SignalClient wsMutex sync.Mutex @@ -2322,3 +2331,40 @@ func (a *Api) RemovePin(c *gin.Context) { c.Status(204) } + +// @Summary Delete a signal message. +// @Tags Messages +// @Description Delete a signal message +// @Accept json +// @Produce json +// @Success 201 {object} RemoteDeleteResponse +// @Failure 400 {object} Error +// @Param number path string true "Registered Phone Number" +// @Param data body RemoteDeleteRequest true "Type" +// @Router /v1/remote-delete/{number} [delete] +func (a *Api) RemoteDelete(c *gin.Context) { + var req RemoteDeleteRequest + err := c.BindJSON(&req) + if err != nil { + c.JSON(400, Error{Msg: "Couldn't process request - invalid request"}) + return + } + + number, err := url.PathUnescape(c.Param("number")) + if err != nil { + c.JSON(400, Error{Msg: "Couldn't process request - malformed number"}) + return + } + if number == "" { + c.JSON(400, Error{Msg: "Couldn't process request - number missing"}) + return + } + + timestamp, err := a.signalClient.RemoteDelete(number, req.Recipient, req.Timestamp) + + if err != nil { + c.JSON(400, Error{Msg: err.Error()}) + return + } + c.JSON(201, RemoteDeleteResponse{Timestamp: strconv.FormatInt(timestamp.Timestamp, 10)}) +} diff --git a/src/client/client.go b/src/client/client.go index d38fd47..cf55d14 100644 --- a/src/client/client.go +++ b/src/client/client.go @@ -163,6 +163,10 @@ type SendResponse struct { Timestamp int64 `json:"timestamp"` } +type RemoteDeleteResponse struct { + Timestamp int64 `json:"timestamp"` +} + type About struct { SupportedApiVersions []string `json:"versions"` BuildNr int `json:"build"` @@ -2530,3 +2534,78 @@ func (s *SignalClient) RemovePin(number string) error { } return nil } + +func (s *SignalClient) RemoteDelete(number string, recipient string, timestamp int64) (RemoteDeleteResponse, error) { + // see https://github.com/AsamK/signal-cli/blob/master/man/signal-cli.1.adoc#remotedelete + var err error + var resp RemoteDeleteResponse + var rawData string + + recp := recipient + isGroup := false + + recipientType, err := getRecipientType(recipient) + if err != nil { + return resp, err + } + + if recipientType == ds.Group { + isGroup = true + recp, err = ConvertGroupIdToInternalGroupId(recipient) + if err != nil { + return resp, errors.New("Invalid group id") + } + } else if recipientType != ds.Number && recipientType != ds.Username { + return resp, errors.New("Invalid recipient type") + } + + if s.signalCliMode == JsonRpc { + type Request struct { + Recipient string `json:"recipient,omitempty"` + GroupId string `json:"group-id,omitempty"` + Timestamp int64 `json:"target-timestamp"` + } + request := Request{} + if !isGroup { + request.Recipient = recp + } else { + request.GroupId = recp + } + request.Timestamp = timestamp + + jsonRpc2Client, err := s.getJsonRpc2Client() + if err != nil { + return resp, err + } + rawData, err = jsonRpc2Client.getRaw("remoteDelete", &number, request) + if err != nil { + return resp, err + } + + err = json.Unmarshal([]byte(rawData), &resp) + if err != nil { + return resp, errors.New("Couldn't process request - invalid signal-cli response") + } + + return resp, err + } else { + cmd := []string{ + "--config", s.signalCliConfig, + "-a", number, + "remoteDelete", + } + if !isGroup { + cmd = append(cmd, recp) + } else { + cmd = append(cmd, []string{"-g", recp}...) + } + cmd = append(cmd, []string{"-t", strconv.FormatInt(timestamp, 10)}...) + rawData, err = s.cliClient.Execute(true, cmd, "") + if err != nil { + return resp, err + } + + resp.Timestamp, err = strconv.ParseInt(strings.TrimSuffix(rawData, "\n"), 10, 64) + return resp, err + } +} diff --git a/src/docs/docs.go b/src/docs/docs.go index e81bcbb..c8ca455 100644 --- a/src/docs/docs.go +++ b/src/docs/docs.go @@ -1854,6 +1854,53 @@ const docTemplate = `{ } } }, + "/v1/remote-delete/{number}": { + "delete": { + "description": "Delete a signal message", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Messages" + ], + "summary": "Delete a signal message.", + "parameters": [ + { + "type": "string", + "description": "Registered Phone Number", + "name": "number", + "in": "path", + "required": true + }, + { + "description": "Type", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/api.RemoteDeleteRequest" + } + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/api.RemoteDeleteResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/api.Error" + } + } + } + } + }, "/v1/search/{number}": { "get": { "description": "Check if one or more phone numbers are registered with the Signal Service.", @@ -2394,6 +2441,25 @@ const docTemplate = `{ } } }, + "api.RemoteDeleteRequest": { + "type": "object", + "properties": { + "recipient": { + "type": "string" + }, + "timestamp": { + "type": "integer" + } + } + }, + "api.RemoteDeleteResponse": { + "type": "object", + "properties": { + "timestamp": { + "type": "string" + } + } + }, "api.SearchResponse": { "type": "object", "properties": { diff --git a/src/docs/swagger.json b/src/docs/swagger.json index e8b1a45..ba1d52f 100644 --- a/src/docs/swagger.json +++ b/src/docs/swagger.json @@ -1851,6 +1851,53 @@ } } }, + "/v1/remote-delete/{number}": { + "delete": { + "description": "Delete a signal message", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Messages" + ], + "summary": "Delete a signal message.", + "parameters": [ + { + "type": "string", + "description": "Registered Phone Number", + "name": "number", + "in": "path", + "required": true + }, + { + "description": "Type", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/api.RemoteDeleteRequest" + } + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/api.RemoteDeleteResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/api.Error" + } + } + } + } + }, "/v1/search/{number}": { "get": { "description": "Check if one or more phone numbers are registered with the Signal Service.", @@ -2391,6 +2438,25 @@ } } }, + "api.RemoteDeleteRequest": { + "type": "object", + "properties": { + "recipient": { + "type": "string" + }, + "timestamp": { + "type": "integer" + } + } + }, + "api.RemoteDeleteResponse": { + "type": "object", + "properties": { + "timestamp": { + "type": "string" + } + } + }, "api.SearchResponse": { "type": "object", "properties": { diff --git a/src/docs/swagger.yaml b/src/docs/swagger.yaml index 5638db2..9263b8c 100644 --- a/src/docs/swagger.yaml +++ b/src/docs/swagger.yaml @@ -121,6 +121,18 @@ definitions: use_voice: type: boolean type: object + api.RemoteDeleteRequest: + properties: + recipient: + type: string + timestamp: + type: integer + type: object + api.RemoteDeleteResponse: + properties: + timestamp: + type: string + type: object api.SearchResponse: properties: number: @@ -1706,6 +1718,37 @@ paths: summary: Verify a registered phone number. tags: - Devices + /v1/remote-delete/{number}: + delete: + consumes: + - application/json + description: Delete a signal message + 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.RemoteDeleteRequest' + produces: + - application/json + responses: + "201": + description: Created + schema: + $ref: '#/definitions/api.RemoteDeleteResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/api.Error' + summary: Delete a signal message. + tags: + - Messages /v1/search/{number}: get: consumes: diff --git a/src/main.go b/src/main.go index e9d0eb5..499b605 100644 --- a/src/main.go +++ b/src/main.go @@ -279,6 +279,11 @@ func main() { typingIndicator.DELETE(":number", api.SendStopTyping) } + remoteDelete := v1.Group("remote-delete") + { + remoteDelete.DELETE(":number", api.RemoteDelete) + } + reactions := v1.Group("/reactions") { reactions.POST(":number", api.SendReaction)