diff --git a/protocol.json b/protocol.json index c2a3c7d..055f8d9 100644 --- a/protocol.json +++ b/protocol.json @@ -2,9 +2,9 @@ "doc_version": "v1", "version": { "name": "signald", - "version": "0.12.0+git2021-02-12r1f18d539.24", + "version": "0.12.0+git2021-02-18r64bd433c.35", "branch": "main", - "commit": "1f18d539bb0d09ea51948e9559ab5e04ca9359a5" + "commit": "64bd433c25d9f66523171d53aa7a26ec921a6473" }, "info": "This document describes objects that may be used when communicating with signald.", "types": { @@ -34,7 +34,7 @@ }, "timestamp": { "type": "long", - "example": "1613092537706" + "example": "1613632213480" }, "timestampISO": { "type": "String" @@ -44,7 +44,7 @@ }, "serverDeliveredTimestamp": { "type": "long", - "example": "161309253770680" + "example": "161363221348080" }, "hasLegacyMessage": { "type": "boolean" @@ -124,7 +124,7 @@ }, "timestamp": { "type": "long", - "example": "1613092537706" + "example": "1613632213480" } } }, @@ -165,7 +165,7 @@ }, "version": { "type": "String", - "example": "\"0.12.0+git2021-02-12r1f18d539.24\"" + "example": "\"0.12.0+git2021-02-18r64bd433c.35\"" }, "branch": { "type": "String", @@ -173,7 +173,7 @@ }, "commit": { "type": "String", - "example": "\"1f18d539bb0d09ea51948e9559ab5e04ca9359a5\"" + "example": "\"64bd433c25d9f66523171d53aa7a26ec921a6473\"" } } }, @@ -517,7 +517,7 @@ "list": true, "type": "Long", "doc": "List of messages to mark as read", - "example": "1613092537706", + "example": "1613632213480", "required": true } } @@ -669,12 +669,44 @@ } } }, + "GenerateLinkingURIRequest": { + "fields": {}, + "doc": "Generate a linking URI. Typically this is QR encoded and scanned by the primary device. Submit the returned session_id with a finish_link request." + }, + "FinishLinkRequest": { + "fields": { + "device_name": { + "type": "String" + }, + "session_id": { + "type": "String" + } + } + }, + "Account": { + "fields": { + "address": { + "type": "JsonAddress", + "version": "v1", + "doc": "The address of this account" + }, + "device_id": { + "type": "int", + "doc": "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." + }, + "account_id": { + "type": "String", + "doc": "The primary identifier on the account, included with all requests to signald for this account. Previously called 'username'" + } + }, + "doc": "A local account in signald" + }, "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": "1613092537706" + "example": "1613632213480" }, "attachments": { "list": true, @@ -811,7 +843,7 @@ "id": { "type": "long", "doc": "the client timestamp of the message being quoted", - "example": "1613092537706" + "example": "1613632213480" }, "author": { "type": "JsonAddress", @@ -899,7 +931,7 @@ "targetSentTimestamp": { "type": "long", "doc": "the client timestamp of the message being reacted to", - "example": "1613092537706" + "example": "1613632213480" } } }, @@ -979,7 +1011,7 @@ }, "timestamp": { "type": "long", - "example": "1613092537706" + "example": "1613632213480" }, "expirationStartTimestamp": { "type": "long" @@ -1017,7 +1049,7 @@ }, "timestamp": { "type": "long", - "example": "1613092537706" + "example": "1613632213480" } } }, @@ -1029,7 +1061,7 @@ }, "timestamp": { "type": "long", - "example": "1613092537706" + "example": "1613632213480" } } }, @@ -1803,6 +1835,15 @@ "leave_group": { "request": "LeaveGroupRequest", "response": "GroupInfo" + }, + "generate_linking_uri": { + "request": "GenerateLinkingURIRequest", + "response": "String", + "doc": "Generate a linking URI. Typically this is QR encoded and scanned by the primary device. Submit the returned session_id with a finish_link request." + }, + "finish_link": { + "request": "FinishLinkRequest", + "response": "Account" } }, "v1alpha1": { diff --git a/signald/client-protocol/v0/structs.go b/signald/client-protocol/v0/structs.go index 23cc58a..c1ba208 100644 --- a/signald/client-protocol/v0/structs.go +++ b/signald/client-protocol/v0/structs.go @@ -48,7 +48,7 @@ type IceUpdateMessage struct { type JsonAccount struct { DeviceId int32 `json:"deviceId,omitempty" yaml:"deviceId,omitempty"` Filename string `json:"filename,omitempty" yaml:"filename,omitempty"` - Has_keys bool `json:"has_keys,omitempty" yaml:"has_keys,omitempty"` + HasKeys bool `json:"has_keys,omitempty" yaml:"has_keys,omitempty"` Registered bool `json:"registered,omitempty" yaml:"registered,omitempty"` Subscribed bool `json:"subscribed,omitempty" yaml:"subscribed,omitempty"` Username string `json:"username,omitempty" yaml:"username,omitempty"` diff --git a/signald/client-protocol/v1/requests.go b/signald/client-protocol/v1/requests.go index ca9a239..62f39b8 100644 --- a/signald/client-protocol/v1/requests.go +++ b/signald/client-protocol/v1/requests.go @@ -108,6 +108,71 @@ func (r *CreateGroupRequest) Submit(conn *signald.Signald) (response JsonGroupV2 } +func (r *FinishLinkRequest) Submit(conn *signald.Signald) (response Account, err error) { + r.Version = "v1" + r.Type = "finish_link" + 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: Generate a linking URI. Typically this is QR encoded and scanned by the primary device. Submit the returned session_id with a finish_link request. +func (r *GenerateLinkingURIRequest) Submit(conn *signald.Signald) (response string, err error) { + r.Version = "v1" + r.Type = "generate_linking_uri" + 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: Query the server for the latest state of a known group func (r *GetGroupRequest) Submit(conn *signald.Signald) (response JsonGroupV2Info, err error) { r.Version = "v1" diff --git a/signald/client-protocol/v1/structs.go b/signald/client-protocol/v1/structs.go index 3551ef2..afc6aad 100644 --- a/signald/client-protocol/v1/structs.go +++ b/signald/client-protocol/v1/structs.go @@ -19,6 +19,13 @@ type AcceptInvitationRequest struct { GroupID string `json:"groupID,omitempty" yaml:"groupID,omitempty"` } +// Account: A local account in signald +type Account struct { + AccountId string `json:"account_id,omitempty" yaml:"account_id,omitempty"` // The primary identifier on the account, included with all requests to signald for this account. Previously called 'username' + Address *JsonAddress `json:"address,omitempty" yaml:"address,omitempty"` // The address of this account + 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. +} + // ApproveMembershipRequest: approve a request to join a group type ApproveMembershipRequest struct { Request @@ -35,12 +42,23 @@ type Capabilities struct { type CreateGroupRequest struct { Request - Account string `json:"account,omitempty" yaml:"account,omitempty"` // The account to interact with - Avatar string `json:"avatar,omitempty" yaml:"avatar,omitempty"` - Member_role string `json:"member_role,omitempty" yaml:"member_role,omitempty"` // The role of all members other than the group creator. Options are ADMINISTRATOR or DEFAULT (case insensitive) - Members []*JsonAddress `json:"members,omitempty" yaml:"members,omitempty"` - Timer int32 `json:"timer,omitempty" yaml:"timer,omitempty"` // the message expiration timer - Title string `json:"title,omitempty" yaml:"title,omitempty"` + Account string `json:"account,omitempty" yaml:"account,omitempty"` // The account to interact with + Avatar string `json:"avatar,omitempty" yaml:"avatar,omitempty"` + MemberRole string `json:"member_role,omitempty" yaml:"member_role,omitempty"` // The role of all members other than the group creator. Options are ADMINISTRATOR or DEFAULT (case insensitive) + Members []*JsonAddress `json:"members,omitempty" yaml:"members,omitempty"` + Timer int32 `json:"timer,omitempty" yaml:"timer,omitempty"` // the message expiration timer + Title string `json:"title,omitempty" yaml:"title,omitempty"` +} + +type FinishLinkRequest struct { + Request + DeviceName string `json:"device_name,omitempty" yaml:"device_name,omitempty"` + SessionId string `json:"session_id,omitempty" yaml:"session_id,omitempty"` +} + +// GenerateLinkingURIRequest: Generate a linking URI. Typically this is QR encoded and scanned by the primary device. Submit the returned session_id with a finish_link request. +type GenerateLinkingURIRequest struct { + Request } // GetGroupRequest: Query the server for the latest state of a known group @@ -84,9 +102,9 @@ type GroupList struct { } type GroupMember struct { - Joined_revision int32 `json:"joined_revision,omitempty" yaml:"joined_revision,omitempty"` - Role string `json:"role,omitempty" yaml:"role,omitempty"` // possible values are: UNKNOWN, DEFAULT, ADMINISTRATOR and UNRECOGNIZED - UUID string `json:"uuid,omitempty" yaml:"uuid,omitempty"` + JoinedRevision int32 `json:"joined_revision,omitempty" yaml:"joined_revision,omitempty"` + Role string `json:"role,omitempty" yaml:"role,omitempty"` // possible values are: UNKNOWN, DEFAULT, ADMINISTRATOR and UNRECOGNIZED + UUID string `json:"uuid,omitempty" yaml:"uuid,omitempty"` } // JoinGroupRequest: Join a group using the a signal.group URL. Note that you must have a profile name set to join groups. diff --git a/tools/generator/main.go b/tools/generator/main.go index ad10640..996f929 100644 --- a/tools/generator/main.go +++ b/tools/generator/main.go @@ -64,9 +64,6 @@ var fieldNameMap = map[string]string{ "id": "ID", "recipientGroupId": "RecipientGroupID", "uuid": "UUID", - "expiration_time": "ExpirationTime", - "inbox_position": "InboxPosition", - "profile_name": "ProfileName", "gv1-migration": "Gv1Migration", } @@ -89,7 +86,11 @@ func (d *DataType) fixForVersion(field, version string) { if ok { d.FieldName = fieldName } else { - d.FieldName = strings.Title(field) + components := strings.Split(field, "_") + for i, c := range components { + components[i] = strings.Title(c) + } + d.FieldName = strings.Join(components, "") } } @@ -115,6 +116,9 @@ func main() { if a.Response != "" { inputs.Responses = true } + if r, ok := typeMap[a.Response]; ok { + a.Response = r + } } inputs.Actions = actions outputDir := fmt.Sprintf("signald/client-protocol/%s", version)