From c1daa731f330cbf52cffc38ae9af17a74eec1aa5 Mon Sep 17 00:00:00 2001 From: Finn Date: Tue, 23 Mar 2021 03:44:46 -0700 Subject: [PATCH] bump protocol --- protocol.json | 118 +++++++++++++++++++++++-- signald/client-protocol/v1/requests.go | 118 +++++++++++++++++++++++++ signald/client-protocol/v1/structs.go | 39 +++++++- 3 files changed, 267 insertions(+), 8 deletions(-) diff --git a/protocol.json b/protocol.json index 3d5e927..88e4b34 100644 --- a/protocol.json +++ b/protocol.json @@ -2,9 +2,9 @@ "doc_version": "v1", "version": { "name": "signald", - "version": "0.12.0+git2021-03-18rd3ea4b49.57", + "version": "0.12.0+git2021-03-23rb62b8c6c.75", "branch": "main", - "commit": "d3ea4b495025d555370ef3088208e9126f410e36" + "commit": "b62b8c6c693e164b1d9901b110db554c7d730535" }, "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-18rd3ea4b49.57\"" + "example": "\"0.12.0+git2021-03-23rb62b8c6c.75\"" }, "branch": { "type": "String", @@ -173,7 +173,7 @@ }, "commit": { "type": "String", - "example": "\"d3ea4b495025d555370ef3088208e9126f410e36\"" + "example": "\"b62b8c6c693e164b1d9901b110db554c7d730535\"" } } }, @@ -829,9 +829,8 @@ }, "trust_level": { "type": "String", - "doc": "One of TRUSTED_UNVERIFIED, TRUSTED_VERIFIED or UNTRUSTED", - "example": "\"TRUSTED_VERIFIED\"", - "required": true + "doc": "One of TRUSTED_UNVERIFIED, TRUSTED_VERIFIED or UNTRUSTED. Default is TRUSTED_VERIFIED", + "example": "\"TRUSTED_VERIFIED\"" } }, "doc": "Trust another user's safety number using either the QR code data or the safety number text" @@ -847,6 +846,93 @@ }, "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." }, + "TypingRequest": { + "fields": { + "account": { + "type": "String", + "doc": "The account to use", + "example": "\"+12024561414\"", + "required": true + }, + "address": { + "type": "JsonAddress", + "version": "v1" + }, + "group": { + "type": "String", + "example": "\"EdSqI90cS0UomDpgUXOlCoObWvQOXlH5G3Z2d3f4ayE=\"" + }, + "typing": { + "type": "boolean", + "example": "true", + "required": true + }, + "when": { + "type": "long" + } + }, + "doc": "send a typing started or stopped message" + }, + "ResetSessionRequest": { + "fields": { + "account": { + "type": "String", + "doc": "The account to use", + "example": "\"+12024561414\"", + "required": true + }, + "address": { + "type": "JsonAddress", + "version": "v1", + "doc": "the user to reset session with", + "required": true + }, + "timestamp": { + "type": "Long" + } + }, + "doc": "reset a session with a particular user" + }, + "RequestSyncRequest": { + "fields": { + "account": { + "type": "String", + "doc": "The account to use", + "example": "\"+12024561414\"", + "required": true + }, + "groups": { + "type": "boolean", + "doc": "request group sync (default true)" + }, + "configuration": { + "type": "boolean", + "doc": "request configuration sync (default true)" + }, + "contacts": { + "type": "boolean", + "doc": "request contact sync (default true)" + }, + "blocked": { + "type": "boolean", + "doc": "request block list sync (default true)" + } + }, + "doc": "Request other devices on the account send us their group list, syncable config and contact list." + }, + "ListAccountsRequest": { + "fields": {}, + "doc": "return all local accounts" + }, + "AccountList": { + "fields": { + "accounts": { + "list": true, + "type": "Account", + "version": "v1" + } + } + }, "JsonDataMessage": { "fields": { "timestamp": { @@ -1763,6 +1849,24 @@ "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." + }, + "typing": { + "request": "TypingRequest", + "doc": "send a typing started or stopped message" + }, + "reset_session": { + "request": "ResetSessionRequest", + "response": "SendResponse", + "doc": "reset a session with a particular user" + }, + "request_sync": { + "request": "RequestSyncRequest", + "doc": "Request other devices on the account send us their group list, syncable config and contact list." + }, + "list_accounts": { + "request": "ListAccountsRequest", + "response": "AccountList", + "doc": "return all local accounts" } } } diff --git a/signald/client-protocol/v1/requests.go b/signald/client-protocol/v1/requests.go index cac208a..fbe21d6 100644 --- a/signald/client-protocol/v1/requests.go +++ b/signald/client-protocol/v1/requests.go @@ -422,6 +422,39 @@ func (r *LeaveGroupRequest) Submit(conn *signald.Signald) (response GroupInfo, e } +// Submit: return all local accounts +func (r *ListAccountsRequest) Submit(conn *signald.Signald) (response AccountList, err error) { + r.Version = "v1" + r.Type = "list_accounts" + 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 *ListContactsRequest) Submit(conn *signald.Signald) (response ProfileList, err error) { r.Version = "v1" r.Type = "list_contacts" @@ -603,6 +636,65 @@ func (r *RemoveLinkedDeviceRequest) Submit(conn *signald.Signald) (err error) { } +// Submit: Request other devices on the account send us their group list, syncable config and contact list. +func (r *RequestSyncRequest) Submit(conn *signald.Signald) (err error) { + r.Version = "v1" + r.Type = "request_sync" + 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: reset a session with a particular user +func (r *ResetSessionRequest) Submit(conn *signald.Signald) (response SendResponse, err error) { + r.Version = "v1" + r.Type = "reset_session" + 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: Resolve a partial JsonAddress with only a number or UUID to one with both. Anywhere that signald accepts a JsonAddress will except a partial, this is a convenience function for client authors, mostly because signald doesn't resolve all the partials it returns func (r *ResolveAddressRequest) Submit(conn *signald.Signald) (response JsonAddress, err error) { r.Version = "v1" @@ -719,6 +811,32 @@ func (r *TrustRequest) Submit(conn *signald.Signald) (err error) { } +// Submit: send a typing started or stopped message +func (r *TypingRequest) Submit(conn *signald.Signald) (err error) { + r.Version = "v1" + r.Type = "typing" + 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" diff --git a/signald/client-protocol/v1/structs.go b/signald/client-protocol/v1/structs.go index 5c8066d..b59c306 100644 --- a/signald/client-protocol/v1/structs.go +++ b/signald/client-protocol/v1/structs.go @@ -26,6 +26,10 @@ 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. } +type AccountList struct { + Accounts []*Account `json:"accounts,omitempty" yaml:"accounts,omitempty"` +} + // AddLinkedDeviceRequest: Link a new device to a local Signal account type AddLinkedDeviceRequest struct { Request @@ -330,6 +334,11 @@ type LinkingURI struct { Uri string `json:"uri,omitempty" yaml:"uri,omitempty"` } +// ListAccountsRequest: return all local accounts +type ListAccountsRequest struct { + Request +} + type ListContactsRequest struct { Request Account string `json:"account,omitempty" yaml:"account,omitempty"` @@ -391,6 +400,24 @@ type RemoveLinkedDeviceRequest struct { DeviceId int64 `json:"deviceId,omitempty" yaml:"deviceId,omitempty"` // the ID of the device to unlink } +// RequestSyncRequest: Request other devices on the account send us their group list, syncable config and contact list. +type RequestSyncRequest struct { + Request + Account string `json:"account,omitempty" yaml:"account,omitempty"` // The account to use + Blocked bool `json:"blocked,omitempty" yaml:"blocked,omitempty"` // request block list sync (default true) + Configuration bool `json:"configuration,omitempty" yaml:"configuration,omitempty"` // request configuration sync (default true) + Contacts bool `json:"contacts,omitempty" yaml:"contacts,omitempty"` // request contact sync (default true) + Groups bool `json:"groups,omitempty" yaml:"groups,omitempty"` // request group sync (default true) +} + +// ResetSessionRequest: reset a session with a particular user +type ResetSessionRequest struct { + Request + Account string `json:"account,omitempty" yaml:"account,omitempty"` // The account to use + Address *JsonAddress `json:"address,omitempty" yaml:"address,omitempty"` // the user to reset session with + Timestamp int64 `json:"timestamp,omitempty" yaml:"timestamp,omitempty"` +} + // ResolveAddressRequest: Resolve a partial JsonAddress with only a number or UUID to one with both. Anywhere that signald accepts a JsonAddress will except a partial, this is a convenience function for client authors, mostly because signald doesn't resolve all the partials it returns type ResolveAddressRequest struct { Request @@ -431,7 +458,17 @@ type TrustRequest struct { 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 + TrustLevel string `json:"trust_level,omitempty" yaml:"trust_level,omitempty"` // One of TRUSTED_UNVERIFIED, TRUSTED_VERIFIED or UNTRUSTED. Default is TRUSTED_VERIFIED +} + +// TypingRequest: send a typing started or stopped message +type TypingRequest struct { + Request + Account string `json:"account,omitempty" yaml:"account,omitempty"` // The account to use + Address *JsonAddress `json:"address,omitempty" yaml:"address,omitempty"` + Group string `json:"group,omitempty" yaml:"group,omitempty"` + Typing bool `json:"typing,omitempty" yaml:"typing,omitempty"` + When int64 `json:"when,omitempty" yaml:"when,omitempty"` } // UpdateGroupRequest: modify a group. Note that only one modification action may be preformed at once