From f6e6cf4a14baa876d427d5d68fd518e846e79306 Mon Sep 17 00:00:00 2001 From: Finn Date: Mon, 7 Jun 2021 19:32:14 -0700 Subject: [PATCH] Update protocol --- protocol.json | 152 +++++++++++++++++++++---- signald/client-protocol/v0/structs.go | 7 -- signald/client-protocol/v1/requests.go | 125 ++++++++++++++++++++ signald/client-protocol/v1/structs.go | 47 +++++++- 4 files changed, 300 insertions(+), 31 deletions(-) diff --git a/protocol.json b/protocol.json index 88e4b34..e93369e 100644 --- a/protocol.json +++ b/protocol.json @@ -2,9 +2,9 @@ "doc_version": "v1", "version": { "name": "signald", - "version": "0.12.0+git2021-03-23rb62b8c6c.75", + "version": "0.13.1+git2021-05-25re38e8fc8.8", "branch": "main", - "commit": "b62b8c6c693e164b1d9901b110db554c7d730535" + "commit": "e38e8fc88a659df3d65f2db5dfd5f19b1a181747" }, "info": "This document describes objects that may be used when communicating with signald.", "types": { @@ -165,7 +165,7 @@ }, "version": { "type": "String", - "example": "\"0.12.0+git2021-03-23rb62b8c6c.75\"" + "example": "\"0.13.1+git2021-05-25re38e8fc8.8\"" }, "branch": { "type": "String", @@ -173,7 +173,7 @@ }, "commit": { "type": "String", - "example": "\"b62b8c6c693e164b1d9901b110db554c7d730535\"" + "example": "\"e38e8fc88a659df3d65f2db5dfd5f19b1a181747\"" } } }, @@ -207,6 +207,9 @@ "type": "String", "example": "\"Parkdale Run Club\"" }, + "description": { + "type": "String" + }, "avatar": { "type": "String", "doc": "path to the group's avatar on local disk, if available", @@ -313,7 +316,7 @@ "devices": { "list": true, "type": "DeviceInfo", - "version": "v0" + "version": "v1" } } }, @@ -522,6 +525,9 @@ "doc": "List of messages to mark as read", "example": "1615576442475", "required": true + }, + "when": { + "type": "Long" } } }, @@ -752,7 +758,7 @@ }, "captcha": { "type": "String", - "doc": "See https://gitlab.com/signald/signald/-/wikis/Captchas" + "doc": "See https://signald.org/articles/captcha/" } }, "doc": "begin the account registration process by requesting a phone number verification code. when the code is received, submit it with a verify request" @@ -842,6 +848,10 @@ "doc": "The account to delete", "example": "\"+12024561414\"", "required": true + }, + "server": { + "type": "boolean", + "doc": "delete account information from the server as well (default false)" } }, "doc": "delete all account data signald has on disk, and optionally delete the account from the server as well. Note that this is not \"unlink\" and will delete the entire account, even from a linked device." @@ -933,6 +943,85 @@ } } }, + "GroupLinkInfoRequest": { + "fields": { + "account": { + "type": "String", + "doc": "The account to use", + "example": "\"+12024561414\"", + "required": true + }, + "uri": { + "type": "String", + "doc": "the signald.group link", + "example": "\"https://signal.group/#CjQKINH_GZhXhfifTcnBkaKTNRxW-hHKnGSq-cJNyPVqHRp8EhDUB7zjKNEl0NaULhsqJCX3\"", + "required": true + } + }, + "doc": "Get information about a group from a signal.group link" + }, + "UpdateContactRequest": { + "fields": { + "account": { + "type": "String", + "required": true + }, + "address": { + "type": "JsonAddress", + "version": "v1", + "required": true + }, + "name": { + "type": "String" + }, + "color": { + "type": "String" + }, + "inbox_position": { + "type": "Integer" + } + }, + "doc": "update information about a local contact" + }, + "SetExpirationRequest": { + "fields": { + "account": { + "type": "String", + "doc": "The account to use", + "example": "\"+12024561414\"", + "required": true + }, + "address": { + "type": "JsonAddress", + "version": "v1" + }, + "group": { + "type": "String", + "example": "\"EdSqI90cS0UomDpgUXOlCoObWvQOXlH5G3Z2d3f4ayE=\"" + }, + "expiration": { + "type": "int", + "example": "604800", + "required": true + } + }, + "doc": "Set the message expiration timer for a thread. Expiration must be specified in seconds, set to 0 to disable timer" + }, + "SetDeviceNameRequest": { + "fields": { + "account": { + "type": "String", + "doc": "The account to set the device name of", + "example": "\"+12024561414\"", + "required": true + }, + "device_name": { + "type": "String", + "doc": "The device name" + } + }, + "doc": "set this device's name. This will show up on the mobile device on the same account under " + }, "JsonDataMessage": { "fields": { "timestamp": { @@ -1201,6 +1290,22 @@ } } }, + "DeviceInfo": { + "fields": { + "id": { + "type": "long" + }, + "name": { + "type": "String" + }, + "created": { + "type": "long" + }, + "lastSeen": { + "type": "long" + } + } + }, "JsonGroupInfo": { "fields": { "groupId": { @@ -1484,22 +1589,6 @@ } } }, - "DeviceInfo": { - "fields": { - "id": { - "type": "long" - }, - "name": { - "type": "String" - }, - "created": { - "type": "long" - }, - "lastSeen": { - "type": "long" - } - } - }, "SharedContact": { "fields": { "name": { @@ -1867,6 +1956,25 @@ "request": "ListAccountsRequest", "response": "AccountList", "doc": "return all local accounts" + }, + "group_link_info": { + "request": "GroupLinkInfoRequest", + "response": "JsonGroupJoinInfo", + "doc": "Get information about a group from a signal.group link" + }, + "update_contact": { + "request": "UpdateContactRequest", + "response": "Profile", + "doc": "update information about a local contact" + }, + "set_expiration": { + "request": "SetExpirationRequest", + "response": "SendResponse", + "doc": "Set the message expiration timer for a thread. Expiration must be specified in seconds, set to 0 to disable timer" + }, + "set_device_name": { + "request": "SetDeviceNameRequest", + "doc": "set this device's name. This will show up on the mobile device on the same account under " } } } diff --git a/signald/client-protocol/v0/structs.go b/signald/client-protocol/v0/structs.go index c1ba208..6c8f18a 100644 --- a/signald/client-protocol/v0/structs.go +++ b/signald/client-protocol/v0/structs.go @@ -25,13 +25,6 @@ type ConfigurationMessage struct { UnidentifiedDeliveryIndicators *Optional `json:"unidentifiedDeliveryIndicators,omitempty" yaml:"unidentifiedDeliveryIndicators,omitempty"` } -type DeviceInfo struct { - Created int64 `json:"created,omitempty" yaml:"created,omitempty"` - ID int64 `json:"id,omitempty" yaml:"id,omitempty"` - LastSeen int64 `json:"lastSeen,omitempty" yaml:"lastSeen,omitempty"` - Name string `json:"name,omitempty" yaml:"name,omitempty"` -} - type HangupMessage struct { DeviceId int32 `json:"deviceId,omitempty" yaml:"deviceId,omitempty"` ID int64 `json:"id,omitempty" yaml:"id,omitempty"` diff --git a/signald/client-protocol/v1/requests.go b/signald/client-protocol/v1/requests.go index fbe21d6..77a99aa 100644 --- a/signald/client-protocol/v1/requests.go +++ b/signald/client-protocol/v1/requests.go @@ -357,6 +357,39 @@ func (r *GetProfileRequest) Submit(conn *signald.Signald) (response Profile, err } +// Submit: Get information about a group from a signal.group link +func (r *GroupLinkInfoRequest) Submit(conn *signald.Signald) (response JsonGroupJoinInfo, err error) { + r.Version = "v1" + r.Type = "group_link_info" + if r.ID == "" { + r.ID = signald.GenerateID() + } + err = conn.RawRequest(r) + if err != nil { + log.Println("signald-go: error submitting request to signald") + return + } + + responseChannel := conn.GetResponseListener(r.ID) + defer conn.CloseResponseListener(r.ID) + + rawResponse := <-responseChannel + if rawResponse.Error != nil { + err = fmt.Errorf("signald error: %s", string(rawResponse.Error)) + return + } + + err = json.Unmarshal(rawResponse.Data, &response) + if err != nil { + rawResponseJson, _ := rawResponse.Data.MarshalJSON() + log.Println("signald-go: error unmarshalling response from signald of type", rawResponse.Type, string(rawResponseJson)) + return + } + + return response, nil + +} + // Submit: Join a group using the a signal.group URL. Note that you must have a profile name set to join groups. func (r *JoinGroupRequest) Submit(conn *signald.Signald) (response JsonGroupJoinInfo, err error) { r.Version = "v1" @@ -760,6 +793,65 @@ func (r *SendRequest) Submit(conn *signald.Signald) (response SendResponse, err } +// Submit: set this device's name. This will show up on the mobile device on the same account under +func (r *SetDeviceNameRequest) Submit(conn *signald.Signald) (err error) { + r.Version = "v1" + r.Type = "set_device_name" + if r.ID == "" { + r.ID = signald.GenerateID() + } + err = conn.RawRequest(r) + if err != nil { + log.Println("signald-go: error submitting request to signald") + return + } + + responseChannel := conn.GetResponseListener(r.ID) + defer conn.CloseResponseListener(r.ID) + + rawResponse := <-responseChannel + if rawResponse.Error != nil { + err = fmt.Errorf("signald error: %s", string(rawResponse.Error)) + return + } + + return err + +} + +// Submit: Set the message expiration timer for a thread. Expiration must be specified in seconds, set to 0 to disable timer +func (r *SetExpirationRequest) Submit(conn *signald.Signald) (response SendResponse, err error) { + r.Version = "v1" + r.Type = "set_expiration" + if r.ID == "" { + r.ID = signald.GenerateID() + } + err = conn.RawRequest(r) + if err != nil { + log.Println("signald-go: error submitting request to signald") + return + } + + responseChannel := conn.GetResponseListener(r.ID) + defer conn.CloseResponseListener(r.ID) + + rawResponse := <-responseChannel + if rawResponse.Error != nil { + err = fmt.Errorf("signald error: %s", string(rawResponse.Error)) + return + } + + err = json.Unmarshal(rawResponse.Data, &response) + if err != nil { + rawResponseJson, _ := rawResponse.Data.MarshalJSON() + log.Println("signald-go: error unmarshalling response from signald of type", rawResponse.Type, string(rawResponseJson)) + return + } + + return response, nil + +} + func (r *SetProfile) Submit(conn *signald.Signald) (err error) { r.Version = "v1" r.Type = "set_profile" @@ -837,6 +929,39 @@ func (r *TypingRequest) Submit(conn *signald.Signald) (err error) { } +// Submit: update information about a local contact +func (r *UpdateContactRequest) Submit(conn *signald.Signald) (response Profile, err error) { + r.Version = "v1" + r.Type = "update_contact" + if r.ID == "" { + r.ID = signald.GenerateID() + } + err = conn.RawRequest(r) + if err != nil { + log.Println("signald-go: error submitting request to signald") + return + } + + responseChannel := conn.GetResponseListener(r.ID) + defer conn.CloseResponseListener(r.ID) + + rawResponse := <-responseChannel + if rawResponse.Error != nil { + err = fmt.Errorf("signald error: %s", string(rawResponse.Error)) + return + } + + err = json.Unmarshal(rawResponse.Data, &response) + if err != nil { + rawResponseJson, _ := rawResponse.Data.MarshalJSON() + log.Println("signald-go: error unmarshalling response from signald of type", rawResponse.Type, string(rawResponseJson)) + return + } + + return response, nil + +} + // Submit: modify a group. Note that only one modification action may be preformed at once func (r *UpdateGroupRequest) Submit(conn *signald.Signald) (response GroupInfo, err error) { r.Version = "v1" diff --git a/signald/client-protocol/v1/structs.go b/signald/client-protocol/v1/structs.go index b59c306..bf10616 100644 --- a/signald/client-protocol/v1/structs.go +++ b/signald/client-protocol/v1/structs.go @@ -65,6 +65,14 @@ type CreateGroupRequest struct { type DeleteAccountRequest struct { Request Account string `json:"account,omitempty" yaml:"account,omitempty"` // The account to delete + Server bool `json:"server,omitempty" yaml:"server,omitempty"` // delete account information from the server as well (default false) +} + +type DeviceInfo struct { + Created int64 `json:"created,omitempty" yaml:"created,omitempty"` + ID int64 `json:"id,omitempty" yaml:"id,omitempty"` + LastSeen int64 `json:"lastSeen,omitempty" yaml:"lastSeen,omitempty"` + Name string `json:"name,omitempty" yaml:"name,omitempty"` } type FinishLinkRequest struct { @@ -120,6 +128,13 @@ type GroupInfo struct { V2 *JsonGroupV2Info `json:"v2,omitempty" yaml:"v2,omitempty"` } +// GroupLinkInfoRequest: Get information about a group from a signal.group link +type GroupLinkInfoRequest struct { + Request + Account string `json:"account,omitempty" yaml:"account,omitempty"` // The account to use + Uri string `json:"uri,omitempty" yaml:"uri,omitempty"` // the signald.group link +} + type GroupList struct { Groups []*JsonGroupV2Info `json:"groups,omitempty" yaml:"groups,omitempty"` LegacyGroups []*JsonGroupInfo `json:"legacyGroups,omitempty" yaml:"legacyGroups,omitempty"` @@ -201,6 +216,7 @@ type JsonGroupJoinInfo struct { type JsonGroupV2Info struct { AccessControl *GroupAccessControl `json:"accessControl,omitempty" yaml:"accessControl,omitempty"` // current access control settings for this group Avatar string `json:"avatar,omitempty" yaml:"avatar,omitempty"` // path to the group's avatar on local disk, if available + Description string `json:"description,omitempty" yaml:"description,omitempty"` ID string `json:"id,omitempty" yaml:"id,omitempty"` InviteLink string `json:"inviteLink,omitempty" yaml:"inviteLink,omitempty"` // the signal.group link, if applicable MemberDetail []*GroupMember `json:"memberDetail,omitempty" yaml:"memberDetail,omitempty"` // detailed member list @@ -326,7 +342,7 @@ type LeaveGroupRequest struct { } type LinkedDevices struct { - Devices []*v0.DeviceInfo `json:"devices,omitempty" yaml:"devices,omitempty"` + Devices []*DeviceInfo `json:"devices,omitempty" yaml:"devices,omitempty"` } type LinkingURI struct { @@ -355,6 +371,7 @@ type MarkReadRequest struct { Account string `json:"account,omitempty" yaml:"account,omitempty"` // The account to interact with Timestamps []int64 `json:"timestamps,omitempty" yaml:"timestamps,omitempty"` // List of messages to mark as read To *JsonAddress `json:"to,omitempty" yaml:"to,omitempty"` // The address that sent the message being marked as read + When int64 `json:"when,omitempty" yaml:"when,omitempty"` } // Profile: Information about a Signal user @@ -389,7 +406,7 @@ type ReactRequest struct { type RegisterRequest struct { Request Account string `json:"account,omitempty" yaml:"account,omitempty"` // the e164 phone number to register with - Captcha string `json:"captcha,omitempty" yaml:"captcha,omitempty"` // See https://gitlab.com/signald/signald/-/wikis/Captchas + Captcha string `json:"captcha,omitempty" yaml:"captcha,omitempty"` // See https://signald.org/articles/captcha/ Voice bool `json:"voice,omitempty" yaml:"voice,omitempty"` // set to true to request a voice call instead of an SMS for verification } @@ -442,6 +459,22 @@ type SendResponse struct { Timestamp int64 `json:"timestamp,omitempty" yaml:"timestamp,omitempty"` } +// SetDeviceNameRequest: set this device's name. This will show up on the mobile device on the same account under +type SetDeviceNameRequest struct { + Request + Account string `json:"account,omitempty" yaml:"account,omitempty"` // The account to set the device name of + DeviceName string `json:"device_name,omitempty" yaml:"device_name,omitempty"` // The device name +} + +// SetExpirationRequest: Set the message expiration timer for a thread. Expiration must be specified in seconds, set to 0 to disable timer +type SetExpirationRequest struct { + Request + Account string `json:"account,omitempty" yaml:"account,omitempty"` // The account to use + Address *JsonAddress `json:"address,omitempty" yaml:"address,omitempty"` + Expiration int32 `json:"expiration,omitempty" yaml:"expiration,omitempty"` + Group string `json:"group,omitempty" yaml:"group,omitempty"` +} + type SetProfile struct { Request About string `json:"about,omitempty" yaml:"about,omitempty"` @@ -471,6 +504,16 @@ type TypingRequest struct { When int64 `json:"when,omitempty" yaml:"when,omitempty"` } +// UpdateContactRequest: update information about a local contact +type UpdateContactRequest struct { + Request + Account string `json:"account,omitempty" yaml:"account,omitempty"` + Address *JsonAddress `json:"address,omitempty" yaml:"address,omitempty"` + Color string `json:"color,omitempty" yaml:"color,omitempty"` + InboxPosition int32 `json:"inbox_position,omitempty" yaml:"inbox_position,omitempty"` + Name string `json:"name,omitempty" yaml:"name,omitempty"` +} + // UpdateGroupRequest: modify a group. Note that only one modification action may be preformed at once type UpdateGroupRequest struct { Request