bring protocol up to date

This commit is contained in:
Finn 2021-11-02 21:26:30 -07:00
parent 28b7d16568
commit 924e9c3767
4 changed files with 376 additions and 73 deletions

View file

@ -2,9 +2,9 @@
"doc_version": "v1", "doc_version": "v1",
"version": { "version": {
"name": "signald", "name": "signald",
"version": "0.14.1-48-7d927883", "version": "0.15.0-23-981b4409",
"branch": "main", "branch": "main",
"commit": "7d92788343f34c08634abfeda06045ae13e18670" "commit": "981b44098da8ddd748832597d5f5bde019197902"
}, },
"info": "This document describes objects that may be used when communicating with signald.", "info": "This document describes objects that may be used when communicating with signald.",
"types": { "types": {
@ -145,7 +145,20 @@
"type": "boolean" "type": "boolean"
} }
}, },
"doc": "indicates when the incoming connection to the signal server has started or stopped" "doc": "prior attempt to indicate signald connectivity state. WebSocketConnectionState messages will be delivered at the same time as well as in other parts of the websocket lifecycle."
},
"WebSocketConnectionState": {
"fields": {
"state": {
"type": "String",
"doc": "One of: DISCONNECTED, CONNECTING, CONNECTED, RECONNECTING, DISCONNECTING, AUTHENTICATION_FAILED, FAILED"
},
"socket": {
"type": "String",
"doc": "One of: UNIDENTIFIED, IDENTIFIED"
}
},
"doc": "indicates when the websocket connection state to the signal server has changed"
}, },
"ClientMessageWrapper": { "ClientMessageWrapper": {
"fields": { "fields": {
@ -164,9 +177,56 @@
"error": { "error": {
"type": "Boolean", "type": "Boolean",
"doc": "true if the incoming message represents an error" "doc": "true if the incoming message represents an error"
},
"account": {
"type": "String",
"doc": "the account this message is from"
} }
}, },
"doc": "Wraps all incoming messages after a v1 subscribe request is issued" "doc": "Wraps all incoming messages sent to the client after a v1 subscribe request is issued"
},
"DuplicateMessageError": {
"fields": {
"message": {
"type": "String"
}
},
"error": true
},
"ProtocolInvalidMessageError": {
"fields": {
"sender": {
"type": "String"
},
"message": {
"type": "String"
},
"sender_device": {
"type": "int"
},
"content_hint": {
"type": "int"
},
"group_id": {
"type": "String"
}
},
"error": true
},
"UntrustedIdentityError": {
"fields": {
"identifier": {
"type": "String"
},
"message": {
"type": "String"
},
"identity_key": {
"type": "IdentityKey",
"version": "v1"
}
},
"error": true
}, },
"SendRequest": { "SendRequest": {
"fields": { "fields": {
@ -208,6 +268,12 @@
"list": true, "list": true,
"type": "JsonPreview", "type": "JsonPreview",
"version": "v1" "version": "v1"
},
"members": {
"list": true,
"type": "JsonAddress",
"version": "v1",
"doc": "Optionally set to a sub-set of group members. Ignored if recipientGroupId isn't specified"
} }
} }
}, },
@ -283,7 +349,15 @@
"type": "String" "type": "String"
} }
}, },
"doc": "an internal error in signald has occured.", "doc": "an internal error in signald has occurred. typically these are things that \"should never happen\" such as issues saving to the local disk, but it is also the default error type and may catch some things that should have their own error type. If you find tht your code is depending on the exception list for any particular behavior, please file an issue so we can pull those errors out to a separate error type: https://gitlab.com/signald/signald/-/issues/new",
"error": true
},
"InvalidRequestError": {
"fields": {
"message": {
"type": "String"
}
},
"error": true "error": true
}, },
"UnknownGroupError": { "UnknownGroupError": {
@ -294,6 +368,14 @@
}, },
"error": true "error": true
}, },
"RateLimitError": {
"fields": {
"message": {
"type": "String"
}
},
"error": true
},
"InvalidRecipientError": { "InvalidRecipientError": {
"fields": { "fields": {
"message": { "message": {
@ -324,6 +406,12 @@
}, },
"timestamp": { "timestamp": {
"type": "long" "type": "long"
},
"members": {
"list": true,
"type": "JsonAddress",
"version": "v1",
"doc": "Optionally set to a sub-set of group members. Ignored if recipientGroupId isn't specified"
} }
}, },
"doc": "react to a previous message" "doc": "react to a previous message"
@ -339,7 +427,7 @@
}, },
"version": { "version": {
"type": "String", "type": "String",
"example": "\"0.14.1-48-7d927883\"" "example": "\"0.15.0-23-981b4409\""
}, },
"branch": { "branch": {
"type": "String", "type": "String",
@ -347,7 +435,7 @@
}, },
"commit": { "commit": {
"type": "String", "type": "String",
"example": "\"7d92788343f34c08634abfeda06045ae13e18670\"" "example": "\"981b44098da8ddd748832597d5f5bde019197902\""
} }
} }
}, },
@ -573,14 +661,6 @@
} }
} }
}, },
"InvalidRequestError": {
"fields": {
"message": {
"type": "String"
}
},
"error": true
},
"InvalidInviteURIError": { "InvalidInviteURIError": {
"fields": { "fields": {
"message": { "message": {
@ -788,21 +868,6 @@
} }
} }
}, },
"UntrustedIdentityError": {
"fields": {
"identifier": {
"type": "String"
},
"message": {
"type": "String"
},
"identity_key": {
"type": "IdentityKey",
"version": "v1"
}
},
"error": true
},
"GetProfileRequest": { "GetProfileRequest": {
"fields": { "fields": {
"account": { "account": {
@ -1058,8 +1123,8 @@
}, },
"uri": { "uri": {
"type": "String", "type": "String",
"doc": "the tsdevice:/ uri provided (typically in qr code form) by the new device", "doc": "the sgnl://linkdevice uri provided (typically in qr code form) by the new device",
"example": "\"tsdevice:/?uuid=jAaZ5lxLfh7zVw5WELd6-Q&pub_key=BfFbjSwmAgpVJBXUdfmSgf61eX3a%2Bq9AoxAVpl1HUap9\"", "example": "\"sgnl://linkdevice?uuid=jAaZ5lxLfh7zVw5WELd6-Q&pub_key=BfFbjSwmAgpVJBXUdfmSgf61eX3a%2Bq9AoxAVpl1HUap9\"",
"required": true "required": true
} }
}, },
@ -1489,6 +1554,12 @@
"timestamp": { "timestamp": {
"type": "long", "type": "long",
"required": true "required": true
},
"members": {
"list": true,
"type": "JsonAddress",
"version": "v1",
"doc": "Optionally set to a sub-set of group members. Ignored if group isn't specified"
} }
}, },
"doc": "delete a message previously sent" "doc": "delete a message previously sent"
@ -1590,6 +1661,21 @@
}, },
"doc": "deny a request to join a group" "doc": "deny a request to join a group"
}, },
"SubmitChallengeRequest": {
"fields": {
"account": {
"type": "String",
"required": true
},
"challenge": {
"type": "String",
"required": true
},
"captcha_token": {
"type": "String"
}
}
},
"JsonDataMessage": { "JsonDataMessage": {
"fields": { "fields": {
"timestamp": { "timestamp": {
@ -1795,6 +1881,26 @@
} }
} }
}, },
"IdentityKey": {
"fields": {
"added": {
"type": "long",
"doc": "the first time this identity key was seen"
},
"safety_number": {
"type": "String",
"example": "\"373453558586758076680580548714989751943247272727416091564451\""
},
"qr_code_data": {
"type": "String",
"doc": "base64-encoded QR code data"
},
"trust_level": {
"type": "String",
"doc": "One of TRUSTED_UNVERIFIED, TRUSTED_VERIFIED or UNTRUSTED"
}
}
},
"JsonQuote": { "JsonQuote": {
"fields": { "fields": {
"id": { "id": {
@ -1888,6 +1994,10 @@
}, },
"identityFailure": { "identityFailure": {
"type": "String" "type": "String"
},
"proof_required_failure": {
"type": "ProofRequiredError",
"version": "v1"
} }
} }
}, },
@ -1986,26 +2096,6 @@
}, },
"doc": "information about a legacy group" "doc": "information about a legacy group"
}, },
"IdentityKey": {
"fields": {
"added": {
"type": "long",
"doc": "the first time this identity key was seen"
},
"safety_number": {
"type": "String",
"example": "\"373453558586758076680580548714989751943247272727416091564451\""
},
"qr_code_data": {
"type": "String",
"doc": "base64-encoded QR code data"
},
"trust_level": {
"type": "String",
"doc": "One of TRUSTED_UNVERIFIED, TRUSTED_VERIFIED or UNTRUSTED"
}
}
},
"Capabilities": { "Capabilities": {
"fields": { "fields": {
"gv2": { "gv2": {
@ -2334,6 +2424,26 @@
} }
} }
}, },
"ProofRequiredError": {
"fields": {
"token": {
"type": "String"
},
"options": {
"list": true,
"type": "String",
"doc": "possible list values are RECAPTCHA and PUSH_CHALLENGE"
},
"message": {
"type": "String"
},
"retry_after": {
"type": "long",
"doc": "value in seconds"
}
},
"error": true
},
"ServerCDN": { "ServerCDN": {
"fields": { "fields": {
"number": { "number": {
@ -3287,9 +3397,15 @@
{ {
"name": "InternalError" "name": "InternalError"
}, },
{
"name": "InvalidRequestError"
},
{ {
"name": "UnknownGroupError" "name": "UnknownGroupError"
}, },
{
"name": "RateLimitError"
},
{ {
"name": "InvalidRecipientError" "name": "InvalidRecipientError"
} }
@ -3320,6 +3436,12 @@
}, },
{ {
"name": "UnknownGroupError" "name": "UnknownGroupError"
},
{
"name": "InvalidRequestError"
},
{
"name": "RateLimitError"
} }
] ]
}, },
@ -3349,6 +3471,9 @@
}, },
{ {
"name": "InternalError" "name": "InternalError"
},
{
"name": "InvalidRequestError"
} }
] ]
}, },
@ -3374,6 +3499,9 @@
}, },
{ {
"name": "GroupVerificationError" "name": "GroupVerificationError"
},
{
"name": "InvalidRequestError"
} }
] ]
}, },
@ -3402,6 +3530,9 @@
}, },
{ {
"name": "InvalidGroupStateError" "name": "InvalidGroupStateError"
},
{
"name": "InvalidRequestError"
} }
] ]
}, },
@ -3421,6 +3552,9 @@
}, },
{ {
"name": "NoSuchAccountError" "name": "NoSuchAccountError"
},
{
"name": "InvalidRequestError"
} }
] ]
}, },
@ -3479,6 +3613,9 @@
}, },
{ {
"name": "NoSuchAccountError" "name": "NoSuchAccountError"
},
{
"name": "InvalidRequestError"
} }
] ]
}, },
@ -3527,6 +3664,9 @@
}, },
{ {
"name": "InvalidBase64Error" "name": "InvalidBase64Error"
},
{
"name": "InvalidRequestError"
} }
] ]
}, },
@ -3600,6 +3740,9 @@
}, },
{ {
"name": "NoSuchAccountError" "name": "NoSuchAccountError"
},
{
"name": "InvalidRequestError"
} }
] ]
}, },
@ -3678,6 +3821,9 @@
}, },
{ {
"name": "GroupVerificationError" "name": "GroupVerificationError"
},
{
"name": "InvalidRequestError"
} }
] ]
}, },
@ -3882,6 +4028,9 @@
}, },
{ {
"name": "UnknownGroupError" "name": "UnknownGroupError"
},
{
"name": "InvalidRequestError"
} }
] ]
}, },
@ -3894,22 +4043,28 @@
"name": "InternalError" "name": "InternalError"
}, },
{ {
"name": "InvalidProxyError" "name": "ServerNotFoundError"
}, },
{ {
"name": "ServerNotFoundError" "name": "InvalidProxyError"
}, },
{ {
"name": "NoSuchAccountError" "name": "NoSuchAccountError"
}, },
{ {
"name": "InvalidRecipientError" "name": "InvalidRequestError"
}, },
{ {
"name": "NoSendPermissionError" "name": "NoSendPermissionError"
}, },
{ {
"name": "UnknownGroupError" "name": "UnknownGroupError"
},
{
"name": "RateLimitError"
},
{
"name": "InvalidRecipientError"
} }
] ]
}, },
@ -4016,6 +4171,9 @@
}, },
{ {
"name": "GroupVerificationError" "name": "GroupVerificationError"
},
{
"name": "InvalidRequestError"
} }
] ]
}, },
@ -4111,6 +4269,12 @@
}, },
{ {
"name": "UnknownGroupError" "name": "UnknownGroupError"
},
{
"name": "InvalidRequestError"
},
{
"name": "RateLimitError"
} }
] ]
}, },
@ -4172,6 +4336,12 @@
}, },
{ {
"name": "NoSendPermissionError" "name": "NoSendPermissionError"
},
{
"name": "InvalidRequestError"
},
{
"name": "RateLimitError"
} }
] ]
}, },
@ -4214,6 +4384,29 @@
{ {
"name": "GroupVerificationError" "name": "GroupVerificationError"
}, },
{
"name": "InternalError"
},
{
"name": "InvalidRequestError"
}
]
},
"submit_challenge": {
"request": "SubmitChallengeRequest",
"errors": [
{
"name": "NoSuchAccountError"
},
{
"name": "InvalidRequestError"
},
{
"name": "ServerNotFoundError"
},
{
"name": "InvalidProxyError"
},
{ {
"name": "InternalError" "name": "InternalError"
} }

View file

@ -39,6 +39,13 @@ func mkerr(response client_protocol.BasicResponse) error {
return err return err
} }
return result return result
case "DuplicateMessageError":
result := DuplicateMessageError{}
err := json.Unmarshal(response.Error, &result)
if err != nil {
return err
}
return result
case "FingerprintVersionMismatchError": case "FingerprintVersionMismatchError":
result := FingerprintVersionMismatchError{} result := FingerprintVersionMismatchError{}
err := json.Unmarshal(response.Error, &result) err := json.Unmarshal(response.Error, &result)
@ -179,6 +186,27 @@ func mkerr(response client_protocol.BasicResponse) error {
return err return err
} }
return result return result
case "ProofRequiredError":
result := ProofRequiredError{}
err := json.Unmarshal(response.Error, &result)
if err != nil {
return err
}
return result
case "ProtocolInvalidMessageError":
result := ProtocolInvalidMessageError{}
err := json.Unmarshal(response.Error, &result)
if err != nil {
return err
}
return result
case "RateLimitError":
result := RateLimitError{}
err := json.Unmarshal(response.Error, &result)
if err != nil {
return err
}
return result
case "ServerNotFoundError": case "ServerNotFoundError":
result := ServerNotFoundError{} result := ServerNotFoundError{}
err := json.Unmarshal(response.Error, &result) err := json.Unmarshal(response.Error, &result)
@ -253,6 +281,14 @@ func (e CaptchaRequiredError) Error() string {
return e.Message return e.Message
} }
type DuplicateMessageError struct {
Message string `json:"message,omitempty" yaml:"message,omitempty"`
}
func (e DuplicateMessageError) Error() string {
return e.Message
}
type FingerprintVersionMismatchError struct { type FingerprintVersionMismatchError struct {
Message string `json:"message,omitempty" yaml:"message,omitempty"` Message string `json:"message,omitempty" yaml:"message,omitempty"`
} }
@ -285,7 +321,7 @@ func (e GroupVerificationError) Error() string {
return e.Message return e.Message
} }
// InternalError: an internal error in signald has occured. // InternalError: an internal error in signald has occurred. typically these are things that "should never happen" such as issues saving to the local disk, but it is also the default error type and may catch some things that should have their own error type. If you find tht your code is depending on the exception list for any particular behavior, please file an issue so we can pull those errors out to a separate error type: https://gitlab.com/signald/signald/-/issues/new
type InternalError struct { type InternalError struct {
Exceptions []string `json:"exceptions,omitempty" yaml:"exceptions,omitempty"` Exceptions []string `json:"exceptions,omitempty" yaml:"exceptions,omitempty"`
Message string `json:"message,omitempty" yaml:"message,omitempty"` Message string `json:"message,omitempty" yaml:"message,omitempty"`
@ -417,6 +453,37 @@ func (e ProfileUnavailableError) Error() string {
return e.Message return e.Message
} }
type ProofRequiredError struct {
Message string `json:"message,omitempty" yaml:"message,omitempty"`
Options []string `json:"options,omitempty" yaml:"options,omitempty"` // possible list values are RECAPTCHA and PUSH_CHALLENGE
RetryAfter int64 `json:"retry_after,omitempty" yaml:"retry_after,omitempty"` // value in seconds
Token string `json:"token,omitempty" yaml:"token,omitempty"`
}
func (e ProofRequiredError) Error() string {
return e.Message
}
type ProtocolInvalidMessageError struct {
ContentHint int32 `json:"content_hint,omitempty" yaml:"content_hint,omitempty"`
GroupId string `json:"group_id,omitempty" yaml:"group_id,omitempty"`
Message string `json:"message,omitempty" yaml:"message,omitempty"`
Sender string `json:"sender,omitempty" yaml:"sender,omitempty"`
SenderDevice int32 `json:"sender_device,omitempty" yaml:"sender_device,omitempty"`
}
func (e ProtocolInvalidMessageError) Error() string {
return e.Message
}
type RateLimitError struct {
Message string `json:"message,omitempty" yaml:"message,omitempty"`
}
func (e RateLimitError) Error() string {
return e.Message
}
type ServerNotFoundError struct { type ServerNotFoundError struct {
Message string `json:"message,omitempty" yaml:"message,omitempty"` Message string `json:"message,omitempty" yaml:"message,omitempty"`
UUID string `json:"uuid,omitempty" yaml:"uuid,omitempty"` UUID string `json:"uuid,omitempty" yaml:"uuid,omitempty"`

View file

@ -1132,6 +1132,31 @@ func (r *SetProfile) Submit(conn *signald.Signald) (err error) {
} }
func (r *SubmitChallengeRequest) Submit(conn *signald.Signald) (err error) {
r.Version = "v1"
r.Type = "submit_challenge"
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 = mkerr(rawResponse)
return
}
return err
}
// Submit: receive incoming messages. After making a subscribe request, incoming messages will be sent to the client encoded as ClientMessageWrapper. Send an unsubscribe request or disconnect from the socket to stop receiving messages. // Submit: receive incoming messages. After making a subscribe request, incoming messages will be sent to the client encoded as ClientMessageWrapper. Send an unsubscribe request or disconnect from the socket to stop receiving messages.
func (r *SubscribeRequest) Submit(conn *signald.Signald) (err error) { func (r *SubscribeRequest) Submit(conn *signald.Signald) (err error) {
r.Version = "v1" r.Version = "v1"

View file

@ -35,7 +35,7 @@ type AccountList struct {
type AddLinkedDeviceRequest struct { type AddLinkedDeviceRequest struct {
Request Request
Account string `json:"account,omitempty" yaml:"account,omitempty"` // The account to interact with 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 Uri string `json:"uri,omitempty" yaml:"uri,omitempty"` // the sgnl://linkdevice uri provided (typically in qr code form) by the new device
} }
// AddServerRequest: add a new server to connect to. Returns the new server's UUID. // AddServerRequest: add a new server to connect to. Returns the new server's UUID.
@ -82,8 +82,9 @@ type Capabilities struct {
Storage bool `json:"storage,omitempty" yaml:"storage,omitempty"` Storage bool `json:"storage,omitempty" yaml:"storage,omitempty"`
} }
// ClientMessageWrapper: Wraps all incoming messages after a v1 subscribe request is issued // ClientMessageWrapper: Wraps all incoming messages sent to the client after a v1 subscribe request is issued
type ClientMessageWrapper struct { type ClientMessageWrapper struct {
Account string `json:"account,omitempty" yaml:"account,omitempty"` // the account this message is from
Data interface{} `json:"data,omitempty" yaml:"data,omitempty"` // the incoming object. The structure will vary from message to message, see `type` and `version` fields Data interface{} `json:"data,omitempty" yaml:"data,omitempty"` // the incoming object. The structure will vary from message to message, see `type` and `version` fields
Error bool `json:"error,omitempty" yaml:"error,omitempty"` // true if the incoming message represents an error Error bool `json:"error,omitempty" yaml:"error,omitempty"` // true if the incoming message represents an error
Type string `json:"type,omitempty" yaml:"type,omitempty"` // the type of object to expect in the `data` field Type string `json:"type,omitempty" yaml:"type,omitempty"` // the type of object to expect in the `data` field
@ -402,6 +403,7 @@ type JsonSendMessageResult struct {
Address *JsonAddress `json:"address,omitempty" yaml:"address,omitempty"` Address *JsonAddress `json:"address,omitempty" yaml:"address,omitempty"`
IdentityFailure string `json:"identityFailure,omitempty" yaml:"identityFailure,omitempty"` IdentityFailure string `json:"identityFailure,omitempty" yaml:"identityFailure,omitempty"`
NetworkFailure bool `json:"networkFailure,omitempty" yaml:"networkFailure,omitempty"` NetworkFailure bool `json:"networkFailure,omitempty" yaml:"networkFailure,omitempty"`
ProofRequiredFailure *ProofRequiredError `json:"proof_required_failure,omitempty" yaml:"proof_required_failure,omitempty"`
Success *SendSuccess `json:"success,omitempty" yaml:"success,omitempty"` Success *SendSuccess `json:"success,omitempty" yaml:"success,omitempty"`
UnregisteredFailure bool `json:"unregisteredFailure,omitempty" yaml:"unregisteredFailure,omitempty"` UnregisteredFailure bool `json:"unregisteredFailure,omitempty" yaml:"unregisteredFailure,omitempty"`
} }
@ -481,7 +483,7 @@ type ListGroupsRequest struct {
Account string `json:"account,omitempty" yaml:"account,omitempty"` Account string `json:"account,omitempty" yaml:"account,omitempty"`
} }
// ListenerState: indicates when the incoming connection to the signal server has started or stopped // ListenerState: prior attempt to indicate signald connectivity state. WebSocketConnectionState messages will be delivered at the same time as well as in other parts of the websocket lifecycle.
type ListenerState struct { type ListenerState struct {
Connected bool `json:"connected,omitempty" yaml:"connected,omitempty"` Connected bool `json:"connected,omitempty" yaml:"connected,omitempty"`
} }
@ -529,6 +531,7 @@ type ProfileList struct {
// ReactRequest: react to a previous message // ReactRequest: react to a previous message
type ReactRequest struct { type ReactRequest struct {
Request Request
Members []*JsonAddress `json:"members,omitempty" yaml:"members,omitempty"` // Optionally set to a sub-set of group members. Ignored if recipientGroupId isn't specified
Reaction *JsonReaction `json:"reaction,omitempty" yaml:"reaction,omitempty"` Reaction *JsonReaction `json:"reaction,omitempty" yaml:"reaction,omitempty"`
RecipientAddress *JsonAddress `json:"recipientAddress,omitempty" yaml:"recipientAddress,omitempty"` RecipientAddress *JsonAddress `json:"recipientAddress,omitempty" yaml:"recipientAddress,omitempty"`
RecipientGroupID string `json:"recipientGroupId,omitempty" yaml:"recipientGroupId,omitempty"` RecipientGroupID string `json:"recipientGroupId,omitempty" yaml:"recipientGroupId,omitempty"`
@ -585,6 +588,7 @@ type RemoteDeleteRequest struct {
Account string `json:"account,omitempty" yaml:"account,omitempty"` // the account to use Account string `json:"account,omitempty" yaml:"account,omitempty"` // the account to use
Address *JsonAddress `json:"address,omitempty" yaml:"address,omitempty"` // the address to send the delete message to. should match address the message to be deleted was sent to. required if group is not set. Address *JsonAddress `json:"address,omitempty" yaml:"address,omitempty"` // the address to send the delete message to. should match address the message to be deleted was sent to. required if group is not set.
Group string `json:"group,omitempty" yaml:"group,omitempty"` // the group to send the delete message to. should match group the message to be deleted was sent to. required if address is not set. Group string `json:"group,omitempty" yaml:"group,omitempty"` // the group to send the delete message to. should match group the message to be deleted was sent to. required if address is not set.
Members []*JsonAddress `json:"members,omitempty" yaml:"members,omitempty"` // Optionally set to a sub-set of group members. Ignored if group isn't specified
Timestamp int64 `json:"timestamp,omitempty" yaml:"timestamp,omitempty"` Timestamp int64 `json:"timestamp,omitempty" yaml:"timestamp,omitempty"`
} }
@ -637,6 +641,7 @@ type SendPaymentRequest struct {
type SendRequest struct { type SendRequest struct {
Request Request
Attachments []*v0.JsonAttachment `json:"attachments,omitempty" yaml:"attachments,omitempty"` Attachments []*v0.JsonAttachment `json:"attachments,omitempty" yaml:"attachments,omitempty"`
Members []*JsonAddress `json:"members,omitempty" yaml:"members,omitempty"` // Optionally set to a sub-set of group members. Ignored if recipientGroupId isn't specified
Mentions []*JsonMention `json:"mentions,omitempty" yaml:"mentions,omitempty"` Mentions []*JsonMention `json:"mentions,omitempty" yaml:"mentions,omitempty"`
MessageBody string `json:"messageBody,omitempty" yaml:"messageBody,omitempty"` MessageBody string `json:"messageBody,omitempty" yaml:"messageBody,omitempty"`
Previews []*JsonPreview `json:"previews,omitempty" yaml:"previews,omitempty"` Previews []*JsonPreview `json:"previews,omitempty" yaml:"previews,omitempty"`
@ -713,6 +718,13 @@ type SetProfile struct {
Name string `json:"name,omitempty" yaml:"name,omitempty"` // New profile name. Set to empty string for no profile name Name string `json:"name,omitempty" yaml:"name,omitempty"` // New profile name. Set to empty string for no profile name
} }
type SubmitChallengeRequest struct {
Request
Account string `json:"account,omitempty" yaml:"account,omitempty"`
CaptchaToken string `json:"captcha_token,omitempty" yaml:"captcha_token,omitempty"`
Challenge string `json:"challenge,omitempty" yaml:"challenge,omitempty"`
}
// SubscribeRequest: receive incoming messages. After making a subscribe request, incoming messages will be sent to the client encoded as ClientMessageWrapper. Send an unsubscribe request or disconnect from the socket to stop receiving messages. // SubscribeRequest: receive incoming messages. After making a subscribe request, incoming messages will be sent to the client encoded as ClientMessageWrapper. Send an unsubscribe request or disconnect from the socket to stop receiving messages.
type SubscribeRequest struct { type SubscribeRequest struct {
Request Request
@ -788,3 +800,9 @@ type VerifyRequest struct {
type VersionRequest struct { type VersionRequest struct {
Request Request
} }
// WebSocketConnectionState: indicates when the websocket connection state to the signal server has changed
type WebSocketConnectionState struct {
Socket string `json:"socket,omitempty" yaml:"socket,omitempty"` // One of: UNIDENTIFIED, IDENTIFIED
State string `json:"state,omitempty" yaml:"state,omitempty"` // One of: DISCONNECTED, CONNECTING, CONNECTED, RECONNECTING, DISCONNECTING, AUTHENTICATION_FAILED, FAILED
}