Update protocol

This commit is contained in:
Finn 2021-03-18 17:08:05 -07:00
parent 90334fb82d
commit 1eab1e7890
3 changed files with 440 additions and 16 deletions

View file

@ -2,9 +2,9 @@
"doc_version": "v1",
"version": {
"name": "signald",
"version": "0.12.0+git2021-02-26r10a16d18.43",
"version": "0.12.0+git2021-03-18rd3ea4b49.57",
"branch": "main",
"commit": "10a16d18fed05327ac723a0dc561bf2800115f6f"
"commit": "d3ea4b495025d555370ef3088208e9126f410e36"
},
"info": "This document describes objects that may be used when communicating with signald.",
"types": {
@ -34,7 +34,7 @@
},
"timestamp": {
"type": "long",
"example": "1614362423771"
"example": "1615576442475"
},
"timestampISO": {
"type": "String"
@ -44,7 +44,7 @@
},
"serverDeliveredTimestamp": {
"type": "long",
"example": "161436242377180"
"example": "161557644247580"
},
"hasLegacyMessage": {
"type": "boolean"
@ -124,7 +124,7 @@
},
"timestamp": {
"type": "long",
"example": "1614362423771"
"example": "1615576442475"
}
}
},
@ -165,7 +165,7 @@
},
"version": {
"type": "String",
"example": "\"0.12.0+git2021-02-26r10a16d18.43\""
"example": "\"0.12.0+git2021-03-18rd3ea4b49.57\""
},
"branch": {
"type": "String",
@ -173,7 +173,7 @@
},
"commit": {
"type": "String",
"example": "\"10a16d18fed05327ac723a0dc561bf2800115f6f\""
"example": "\"d3ea4b495025d555370ef3088208e9126f410e36\""
}
}
},
@ -460,6 +460,12 @@
"type": "String",
"doc": "Path to new profile avatar file, if the avatar should be updated",
"example": "\"/tmp/image.jpg\""
},
"about": {
"type": "String"
},
"emoji": {
"type": "String"
}
}
},
@ -514,7 +520,7 @@
"list": true,
"type": "Long",
"doc": "List of messages to mark as read",
"example": "1614362423771",
"example": "1615576442475",
"required": true
}
}
@ -561,6 +567,12 @@
"type": "String",
"doc": "color of the chat with this user"
},
"about": {
"type": "String"
},
"emoji": {
"type": "String"
},
"profile_name": {
"type": "String",
"doc": "The user's Signal profile name"
@ -637,7 +649,8 @@
"members": {
"list": true,
"type": "JsonAddress",
"version": "v1"
"version": "v1",
"required": true
},
"timer": {
"type": "int",
@ -708,12 +721,138 @@
},
"doc": "A local account in signald"
},
"AddLinkedDeviceRequest": {
"fields": {
"account": {
"type": "String",
"doc": "The account to interact with",
"example": "\"+12024561414\"",
"required": true
},
"uri": {
"type": "String",
"doc": "the tsdevice:/ uri provided (typically in qr code form) by the new device",
"example": "\"tsdevice:/?uuid=jAaZ5lxLfh7zVw5WELd6-Q&pub_key=BfFbjSwmAgpVJBXUdfmSgf61eX3a%2Bq9AoxAVpl1HUap9\"",
"required": true
}
},
"doc": "Link a new device to a local Signal account"
},
"RegisterRequest": {
"fields": {
"account": {
"type": "String",
"doc": "the e164 phone number to register with",
"example": "\"+12024561414\"",
"required": true
},
"voice": {
"type": "boolean",
"doc": "set to true to request a voice call instead of an SMS for verification"
},
"captcha": {
"type": "String",
"doc": "See https://gitlab.com/signald/signald/-/wikis/Captchas"
}
},
"doc": "begin the account registration process by requesting a phone number verification code. when the code is received, submit it with a verify request"
},
"VerifyRequest": {
"fields": {
"account": {
"type": "String",
"doc": "the e164 phone number being verified",
"example": "\"+12024561414\"",
"required": true
},
"code": {
"type": "String",
"doc": "the verification code, dash (-) optional",
"example": "\"555555\"",
"required": true
}
},
"doc": "verify an account's phone number with a code after registering, completing the account creation process"
},
"GetIdentitiesRequest": {
"fields": {
"account": {
"type": "String",
"doc": "The account to interact with",
"example": "\"+12024561414\"",
"required": true
},
"address": {
"type": "JsonAddress",
"version": "v1",
"doc": "address to get keys for",
"required": true
}
},
"doc": "Get information about a known keys for a particular address"
},
"IdentityKeyList": {
"fields": {
"address": {
"type": "JsonAddress",
"version": "v1"
},
"identities": {
"list": true,
"type": "IdentityKey",
"version": "v1"
}
},
"doc": "a list of identity keys associated with a particular address"
},
"TrustRequest": {
"fields": {
"account": {
"type": "String",
"doc": "The account to interact with",
"example": "\"+12024561414\"",
"required": true
},
"address": {
"type": "JsonAddress",
"version": "v1",
"doc": "The user to query identity keys for",
"required": true
},
"safety_number": {
"type": "String",
"doc": "required if qr_code_data is absent"
},
"qr_code_data": {
"type": "String",
"doc": "base64-encoded QR code data. required if safety_number is absent"
},
"trust_level": {
"type": "String",
"doc": "One of TRUSTED_UNVERIFIED, TRUSTED_VERIFIED or UNTRUSTED",
"example": "\"TRUSTED_VERIFIED\"",
"required": true
}
},
"doc": "Trust another user's safety number using either the QR code data or the safety number text"
},
"DeleteAccountRequest": {
"fields": {
"account": {
"type": "String",
"doc": "The account to delete",
"example": "\"+12024561414\"",
"required": true
}
},
"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."
},
"JsonDataMessage": {
"fields": {
"timestamp": {
"type": "long",
"doc": "the timestamp that the message was sent at, according to the sender's device. This is used to uniquely identify this message for things like reactions and quotes.",
"example": "1614362423771"
"example": "1615576442475"
},
"attachments": {
"list": true,
@ -850,7 +989,7 @@
"id": {
"type": "long",
"doc": "the client timestamp of the message being quoted",
"example": "1614362423771"
"example": "1615576442475"
},
"author": {
"type": "JsonAddress",
@ -938,7 +1077,7 @@
"targetSentTimestamp": {
"type": "long",
"doc": "the client timestamp of the message being reacted to",
"example": "1614362423771"
"example": "1615576442475"
}
}
},
@ -1010,6 +1149,25 @@
}
}
},
"IdentityKey": {
"fields": {
"added": {
"type": "long",
"doc": "the first time this identity key was seen"
},
"safety_number": {
"type": "String"
},
"qr_code_data": {
"type": "String",
"doc": "base64-encoded QR code data"
},
"trust_level": {
"type": "String",
"doc": "One of TRUSTED_UNVERIFIED, TRUSTED_VERIFIED or UNTRUSTED"
}
}
},
"JsonSentTranscriptMessage": {
"fields": {
"destination": {
@ -1018,7 +1176,7 @@
},
"timestamp": {
"type": "long",
"example": "1614362423771"
"example": "1615576442475"
},
"expirationStartTimestamp": {
"type": "long"
@ -1056,7 +1214,7 @@
},
"timestamp": {
"type": "long",
"example": "1614362423771"
"example": "1615576442475"
}
}
},
@ -1068,7 +1226,7 @@
},
"timestamp": {
"type": "long",
"example": "1614362423771"
"example": "1615576442475"
}
}
},
@ -1578,6 +1736,33 @@
"finish_link": {
"request": "FinishLinkRequest",
"response": "Account"
},
"add_device": {
"request": "AddLinkedDeviceRequest",
"doc": "Link a new device to a local Signal account"
},
"register": {
"request": "RegisterRequest",
"response": "Account",
"doc": "begin the account registration process by requesting a phone number verification code. when the code is received, submit it with a verify request"
},
"verify": {
"request": "VerifyRequest",
"response": "Account",
"doc": "verify an account's phone number with a code after registering, completing the account creation process"
},
"get_identities": {
"request": "GetIdentitiesRequest",
"response": "IdentityKeyList",
"doc": "Get information about a known keys for a particular address"
},
"trust": {
"request": "TrustRequest",
"doc": "Trust another user's safety number using either the QR code data or the safety number text"
},
"delete_account": {
"request": "DeleteAccountRequest",
"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."
}
}
}

View file

@ -43,6 +43,32 @@ func (r *AcceptInvitationRequest) Submit(conn *signald.Signald) (response JsonGr
}
// Submit: Link a new device to a local Signal account
func (r *AddLinkedDeviceRequest) Submit(conn *signald.Signald) (err error) {
r.Version = "v1"
r.Type = "add_device"
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: approve a request to join a group
func (r *ApproveMembershipRequest) Submit(conn *signald.Signald) (response JsonGroupV2Info, err error) {
r.Version = "v1"
@ -108,6 +134,32 @@ func (r *CreateGroupRequest) Submit(conn *signald.Signald) (response JsonGroupV2
}
// Submit: 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.
func (r *DeleteAccountRequest) Submit(conn *signald.Signald) (err error) {
r.Version = "v1"
r.Type = "delete_account"
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
}
func (r *FinishLinkRequest) Submit(conn *signald.Signald) (response Account, err error) {
r.Version = "v1"
r.Type = "finish_link"
@ -206,6 +258,39 @@ func (r *GetGroupRequest) Submit(conn *signald.Signald) (response JsonGroupV2Inf
}
// Submit: Get information about a known keys for a particular address
func (r *GetIdentitiesRequest) Submit(conn *signald.Signald) (response IdentityKeyList, err error) {
r.Version = "v1"
r.Type = "get_identities"
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: list all linked devices on a Signal account
func (r *GetLinkedDevicesRequest) Submit(conn *signald.Signald) (response LinkedDevices, err error) {
r.Version = "v1"
@ -459,6 +544,39 @@ func (r *ReactRequest) Submit(conn *signald.Signald) (response SendResponse, err
}
// Submit: begin the account registration process by requesting a phone number verification code. when the code is received, submit it with a verify request
func (r *RegisterRequest) Submit(conn *signald.Signald) (response Account, err error) {
r.Version = "v1"
r.Type = "register"
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: Remove a linked device from the Signal account. Only allowed when the local device id is 1
func (r *RemoveLinkedDeviceRequest) Submit(conn *signald.Signald) (err error) {
r.Version = "v1"
@ -575,6 +693,32 @@ func (r *SetProfile) Submit(conn *signald.Signald) (err error) {
}
// Submit: Trust another user's safety number using either the QR code data or the safety number text
func (r *TrustRequest) Submit(conn *signald.Signald) (err error) {
r.Version = "v1"
r.Type = "trust"
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: 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"
@ -608,6 +752,39 @@ func (r *UpdateGroupRequest) Submit(conn *signald.Signald) (response GroupInfo,
}
// Submit: verify an account's phone number with a code after registering, completing the account creation process
func (r *VerifyRequest) Submit(conn *signald.Signald) (response Account, err error) {
r.Version = "v1"
r.Type = "verify"
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 *VersionRequest) Submit(conn *signald.Signald) (response JsonVersionMessage, err error) {
r.Version = "v1"
r.Type = "version"

View file

@ -26,6 +26,13 @@ type Account struct {
DeviceId int32 `json:"device_id,omitempty" yaml:"device_id,omitempty"` // The Signal device ID. Official Signal mobile clients (iPhone and Android) have device ID = 1, while linked devices such as Signal Desktop or Signal iPad have higher device IDs.
}
// AddLinkedDeviceRequest: Link a new device to a local Signal account
type AddLinkedDeviceRequest struct {
Request
Account string `json:"account,omitempty" yaml:"account,omitempty"` // The account to interact with
Uri string `json:"uri,omitempty" yaml:"uri,omitempty"` // the tsdevice:/ uri provided (typically in qr code form) by the new device
}
// ApproveMembershipRequest: approve a request to join a group
type ApproveMembershipRequest struct {
Request
@ -50,6 +57,12 @@ type CreateGroupRequest struct {
Title string `json:"title,omitempty" yaml:"title,omitempty"`
}
// DeleteAccountRequest: 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.
type DeleteAccountRequest struct {
Request
Account string `json:"account,omitempty" yaml:"account,omitempty"` // The account to delete
}
type FinishLinkRequest struct {
Request
DeviceName string `json:"device_name,omitempty" yaml:"device_name,omitempty"`
@ -69,6 +82,13 @@ type GetGroupRequest struct {
Revision int32 `json:"revision,omitempty" yaml:"revision,omitempty"` // the latest known revision, default value (-1) forces fetch from server
}
// GetIdentitiesRequest: Get information about a known keys for a particular address
type GetIdentitiesRequest struct {
Request
Account string `json:"account,omitempty" yaml:"account,omitempty"` // The account to interact with
Address *JsonAddress `json:"address,omitempty" yaml:"address,omitempty"` // address to get keys for
}
// GetLinkedDevicesRequest: list all linked devices on a Signal account
type GetLinkedDevicesRequest struct {
Request
@ -107,6 +127,19 @@ type GroupMember struct {
UUID string `json:"uuid,omitempty" yaml:"uuid,omitempty"`
}
type IdentityKey struct {
Added int64 `json:"added,omitempty" yaml:"added,omitempty"` // the first time this identity key was seen
QrCodeData string `json:"qr_code_data,omitempty" yaml:"qr_code_data,omitempty"` // base64-encoded QR code data
SafetyNumber string `json:"safety_number,omitempty" yaml:"safety_number,omitempty"`
TrustLevel string `json:"trust_level,omitempty" yaml:"trust_level,omitempty"` // One of TRUSTED_UNVERIFIED, TRUSTED_VERIFIED or UNTRUSTED
}
// IdentityKeyList: a list of identity keys associated with a particular address
type IdentityKeyList struct {
Address *JsonAddress `json:"address,omitempty" yaml:"address,omitempty"`
Identities []*IdentityKey `json:"identities,omitempty" yaml:"identities,omitempty"`
}
// JoinGroupRequest: Join a group using the a signal.group URL. Note that you must have a profile name set to join groups.
type JoinGroupRequest struct {
Request
@ -317,10 +350,12 @@ type MarkReadRequest struct {
// Profile: Information about a Signal user
type Profile struct {
About string `json:"about,omitempty" yaml:"about,omitempty"`
Address *JsonAddress `json:"address,omitempty" yaml:"address,omitempty"`
Avatar string `json:"avatar,omitempty" yaml:"avatar,omitempty"` // path to avatar on local disk
Capabilities *Capabilities `json:"capabilities,omitempty" yaml:"capabilities,omitempty"`
Color string `json:"color,omitempty" yaml:"color,omitempty"` // color of the chat with this user
Emoji string `json:"emoji,omitempty" yaml:"emoji,omitempty"`
ExpirationTime int32 `json:"expiration_time,omitempty" yaml:"expiration_time,omitempty"`
InboxPosition int32 `json:"inbox_position,omitempty" yaml:"inbox_position,omitempty"`
Name string `json:"name,omitempty" yaml:"name,omitempty"` // The user's name from local contact names if available, or if not in contact list their Signal profile name
@ -341,6 +376,14 @@ type ReactRequest struct {
Username string `json:"username,omitempty" yaml:"username,omitempty"`
}
// RegisterRequest: begin the account registration process by requesting a phone number verification code. when the code is received, submit it with a verify request
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
Voice bool `json:"voice,omitempty" yaml:"voice,omitempty"` // set to true to request a voice call instead of an SMS for verification
}
// RemoveLinkedDeviceRequest: Remove a linked device from the Signal account. Only allowed when the local device id is 1
type RemoveLinkedDeviceRequest struct {
Request
@ -374,11 +417,23 @@ type SendResponse struct {
type SetProfile struct {
Request
About string `json:"about,omitempty" yaml:"about,omitempty"`
Account string `json:"account,omitempty" yaml:"account,omitempty"` // The phone number of the account to use
AvatarFile string `json:"avatarFile,omitempty" yaml:"avatarFile,omitempty"` // Path to new profile avatar file, if the avatar should be updated
Emoji string `json:"emoji,omitempty" yaml:"emoji,omitempty"`
Name string `json:"name,omitempty" yaml:"name,omitempty"` // New profile name. Set to empty string for no profile name
}
// TrustRequest: Trust another user's safety number using either the QR code data or the safety number text
type TrustRequest struct {
Request
Account string `json:"account,omitempty" yaml:"account,omitempty"` // The account to interact with
Address *JsonAddress `json:"address,omitempty" yaml:"address,omitempty"` // The user to query identity keys for
QrCodeData string `json:"qr_code_data,omitempty" yaml:"qr_code_data,omitempty"` // base64-encoded QR code data. required if safety_number is absent
SafetyNumber string `json:"safety_number,omitempty" yaml:"safety_number,omitempty"` // required if qr_code_data is absent
TrustLevel string `json:"trust_level,omitempty" yaml:"trust_level,omitempty"` // One of TRUSTED_UNVERIFIED, TRUSTED_VERIFIED or UNTRUSTED
}
// UpdateGroupRequest: modify a group. Note that only one modification action may be preformed at once
type UpdateGroupRequest struct {
Request
@ -394,6 +449,13 @@ type UpdateGroupRequest struct {
UpdateTimer int32 `json:"updateTimer,omitempty" yaml:"updateTimer,omitempty"` // update the group timer.
}
// VerifyRequest: verify an account's phone number with a code after registering, completing the account creation process
type VerifyRequest struct {
Request
Account string `json:"account,omitempty" yaml:"account,omitempty"` // the e164 phone number being verified
Code string `json:"code,omitempty" yaml:"code,omitempty"` // the verification code, dash (-) optional
}
type VersionRequest struct {
Request
}