Define authenticated and anonymous gRPC services for sending messages
This commit is contained in:
parent
d4031893cc
commit
4a42ff562d
|
@ -0,0 +1,494 @@
|
|||
/*
|
||||
* Copyright 2025 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
option java_multiple_files = true;
|
||||
|
||||
package org.signal.chat.messages;
|
||||
|
||||
import "org/signal/chat/common.proto";
|
||||
import "org/signal/chat/require.proto";
|
||||
|
||||
/**
|
||||
* Provides methods for sending "unsealed sender" messages.
|
||||
*/
|
||||
service Messages {
|
||||
|
||||
option (require.auth) = AUTH_ONLY_AUTHENTICATED;
|
||||
|
||||
/**
|
||||
* Sends an "unsealed sender" message to all devices linked to a single
|
||||
* destination account.
|
||||
*
|
||||
* This RPC may fail with a `NOT_FOUND` status if the destination account was
|
||||
* not found. It may also fail with a `RESOURCE_EXHAUSTED` status if a rate
|
||||
* limit for sending messages has been exceeded, in which case a `retry-after`
|
||||
* header containing an ISO 8601 duration string may be present in the
|
||||
* response trailers.
|
||||
*
|
||||
* Note that message delivery may not succeed even if this RPC returns an `OK`
|
||||
* status; callers must check the response object to verify that the message
|
||||
* was actually accepted and sent.
|
||||
*/
|
||||
rpc SendMessage(SendAuthenticatedSenderMessageRequest) returns (SendMessageResponse) {}
|
||||
|
||||
/**
|
||||
* Sends a "sync" message to all other devices linked to the authenticated
|
||||
* sender's account. This RPC may fail with a `RESOURCE_EXHAUSTED` status if a
|
||||
* rate limit for sending messages has been exceeded, in which case a
|
||||
* `retry-after` header containing an ISO 8601 duration string may be present
|
||||
* in the response trailers.
|
||||
*
|
||||
* Note that message delivery may not succeed even if this RPC returns an `OK`
|
||||
* status; callers must check the response object to verify that the message
|
||||
* was actually accepted and sent.
|
||||
*/
|
||||
rpc SendSyncMessage(SendSyncMessageRequest) returns (SendMessageResponse) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides methods for sending "sealed sender" messages.
|
||||
*/
|
||||
service MessagesAnonymous {
|
||||
|
||||
option (require.auth) = AUTH_ONLY_ANONYMOUS;
|
||||
|
||||
/**
|
||||
* Sends a "sealed sender" message to all devices linked to a single
|
||||
* destination account.
|
||||
*
|
||||
* This RPC may fail with an `UNAUTHENTICATED` status if the given credentials
|
||||
* were not accepted for any reason or if the destination account was not
|
||||
* found while using an unidentified access key (UAK) for authorization. It
|
||||
* may also fail with a `NOT_FOUND` status if the destination account was not
|
||||
* found while using a group send token for authorization. It may also fail
|
||||
* with a `RESOURCE_EXHAUSTED` status if a rate limit for sending messages has
|
||||
* been exceeded, in which case a `retry-after` header containing an ISO 8601
|
||||
* duration string may be present in the response trailers.
|
||||
*
|
||||
* Note that message delivery may not succeed even if this RPC returns an `OK`
|
||||
* status; callers must check the response object to verify that the message
|
||||
* was actually accepted and sent.
|
||||
*/
|
||||
rpc SendSingleRecipientMessage(SendSealedSenderMessageRequest) returns (SendMessageResponse) {}
|
||||
|
||||
/**
|
||||
* Sends a "sealed sender" message with a common payload to all devices linked
|
||||
* to multiple destination accounts.
|
||||
*
|
||||
* This RPC may fail with a `NOT_FOUND` status if one or more destination
|
||||
* accounts were not found. It may also fail with an `UNAUTHENTICATED` status
|
||||
* if the given credentials were not accepted for any reason. It may also fail
|
||||
* with a `RESOURCE_EXHAUSTED` status if a rate limit for sending messages has
|
||||
* been exceeded, in which case a `retry-after` header containing an ISO 8601
|
||||
* duration string may be present in the response trailers.
|
||||
*
|
||||
* Note that message delivery may not succeed even if this RPC returns an `OK`
|
||||
* status; callers must check the response object to verify that the message
|
||||
* was actually accepted and sent.
|
||||
*/
|
||||
rpc SendMultiRecipientMessage(SendMultiRecipientMessageRequest) returns (SendMultiRecipientMessageResponse) {}
|
||||
|
||||
/**
|
||||
* Sends a story message to devices linked to a single destination account.
|
||||
*
|
||||
* This RPC may fail with a `RESOURCE_EXHAUSTED` status if a rate limit for
|
||||
* sending stories has been exceeded, in which case a `retry-after` header
|
||||
* containing an ISO 8601 duration string may be present in the response
|
||||
* trailers.
|
||||
*
|
||||
* Note that message delivery may not succeed even if this RPC returns an `OK`
|
||||
* status; callers must check the response object to verify that the message
|
||||
* was actually accepted and sent.
|
||||
*/
|
||||
rpc SendStory(SendStoryMessageRequest) returns (SendMessageResponse) {}
|
||||
|
||||
/**
|
||||
* Sends a story message with a common payload to devices linked to devices
|
||||
* linked to multiple destination accounts.
|
||||
*
|
||||
* This RPC may fail with a `RESOURCE_EXHAUSTED` status if a rate limit for
|
||||
* sending stories has been exceeded, in which case a `retry-after` header
|
||||
* containing an ISO 8601 duration string may be present in the response
|
||||
* trailers.
|
||||
*
|
||||
* Note that message delivery may not succeed even if this RPC returns an `OK`
|
||||
* status; callers must check the response object to verify that the message
|
||||
* was actually accepted and sent.
|
||||
*/
|
||||
rpc SendMultiRecipientStory(SendMultiRecipientStoryRequest) returns (SendMultiRecipientMessageResponse) {}
|
||||
}
|
||||
|
||||
message IndividualRecipientMessageBundle {
|
||||
|
||||
/**
|
||||
* A message for an individual device linked to a destination account.
|
||||
*/
|
||||
message Message {
|
||||
|
||||
/**
|
||||
* The registration ID for the destination device.
|
||||
*/
|
||||
uint32 registration_id = 1 [(require.range).max = 0x3fff];
|
||||
|
||||
/**
|
||||
* The content of the message to deliver to the destination device.
|
||||
*/
|
||||
bytes payload = 2 [(require.size).max = 262144]; // 256 KiB
|
||||
}
|
||||
|
||||
/**
|
||||
* The time, in milliseconds since the epoch, at which this message was
|
||||
* originally sent from the perspective of the sender.
|
||||
*/
|
||||
uint64 timestamp = 1;
|
||||
|
||||
/**
|
||||
* A map of device IDs to individual messages. Generally, callers must include
|
||||
* one message for each device linked to the destination account. In cases of
|
||||
* "sync messages" where a sender is distributing information to other devices
|
||||
* linked to the sender's account, senders may omit a message for the sending
|
||||
* device.
|
||||
*/
|
||||
map<uint32, Message> messages = 2 [(require.nonEmpty) = true];
|
||||
}
|
||||
|
||||
enum AuthenticatedSenderMessageType {
|
||||
UNSPECIFIED = 0;
|
||||
|
||||
/**
|
||||
* A double-ratchet message represents a "normal," "unsealed-sender" message
|
||||
* encrypted using the Double Ratchet within an established Signal session.
|
||||
*/
|
||||
DOUBLE_RATCHET = 1;
|
||||
|
||||
/**
|
||||
* A prekey message begins a new Signal session. The `content` of a prekey
|
||||
* message is a superset of a double-ratchet message's `content` and
|
||||
* contains the sender's identity public key and information identifying the
|
||||
* pre-keys used in the message's ciphertext.
|
||||
*/
|
||||
PREKEY_MESSAGE = 2;
|
||||
|
||||
/**
|
||||
* A plaintext message is used solely to convey encryption error receipts
|
||||
* and never contains encrypted message content. Encryption error receipts
|
||||
* must be delivered in plaintext because, encryption/decryption of a prior
|
||||
* message failed and there is no reason to believe that
|
||||
* encryption/decryption of subsequent messages with the same key material
|
||||
* would succeed.
|
||||
*
|
||||
* Critically, plaintext messages never have "real" message content
|
||||
* generated by users. Plaintext messages include sender information.
|
||||
*/
|
||||
PLAINTEXT_CONTENT = 3;
|
||||
}
|
||||
|
||||
message SendAuthenticatedSenderMessageRequest {
|
||||
|
||||
/**
|
||||
* The service identifier of the account to which to deliver the message.
|
||||
*/
|
||||
common.ServiceIdentifier destination = 1;
|
||||
|
||||
/**
|
||||
* The type identifier for this message.
|
||||
*/
|
||||
AuthenticatedSenderMessageType type = 2 [(require.specified) = true];
|
||||
|
||||
/**
|
||||
* If true, this message will only be delivered to destination devices that
|
||||
* have an active message delivery channel with a Signal server.
|
||||
*/
|
||||
bool ephemeral = 3;
|
||||
|
||||
/**
|
||||
* Indicates whether this message is urgent and should trigger a high-priority
|
||||
* notification if the destination device does not have an active message
|
||||
* delivery channel with a Signal server
|
||||
*/
|
||||
bool urgent = 4;
|
||||
|
||||
/**
|
||||
* The messages to send to the destination account.
|
||||
*/
|
||||
IndividualRecipientMessageBundle messages = 5;
|
||||
}
|
||||
|
||||
message SendSyncMessageRequest {
|
||||
|
||||
/**
|
||||
* The type identifier for this message.
|
||||
*/
|
||||
AuthenticatedSenderMessageType type = 1 [(require.specified) = true];
|
||||
|
||||
/**
|
||||
* Indicates whether this message is urgent and should trigger a high-priority
|
||||
* notification if the destination device does not have an active message
|
||||
* delivery channel with a Signal server
|
||||
*/
|
||||
bool urgent = 2;
|
||||
|
||||
/**
|
||||
* The messages to send to the destination account.
|
||||
*/
|
||||
IndividualRecipientMessageBundle messages = 3;
|
||||
}
|
||||
|
||||
message SendSealedSenderMessageRequest {
|
||||
|
||||
/**
|
||||
* The service identifier of the account to which to deliver the message.
|
||||
*/
|
||||
common.ServiceIdentifier destination = 1;
|
||||
|
||||
/**
|
||||
* If true, this message will only be delivered to destination devices that
|
||||
* have an active message delivery channel with a Signal server.
|
||||
*/
|
||||
bool ephemeral = 2;
|
||||
|
||||
/**
|
||||
* Indicates whether this message is urgent and should trigger a high-priority
|
||||
* notification if the destination device does not have an active message
|
||||
* delivery channel with a Signal server
|
||||
*/
|
||||
bool urgent = 3;
|
||||
|
||||
/**
|
||||
* The messages to send to the destination account.
|
||||
*/
|
||||
IndividualRecipientMessageBundle messages = 4;
|
||||
|
||||
/**
|
||||
* A means to authorize the request.
|
||||
*/
|
||||
oneof authorization {
|
||||
|
||||
/**
|
||||
* The unidentified access key (UAK) for the destination account.
|
||||
*/
|
||||
bytes unidentified_access_key = 5;
|
||||
|
||||
/**
|
||||
* A group send endorsement token for the destination account.
|
||||
*/
|
||||
bytes group_send_token = 6;
|
||||
}
|
||||
}
|
||||
|
||||
message SendStoryMessageRequest {
|
||||
|
||||
/**
|
||||
* The service identifier of the account to which to deliver the message.
|
||||
*/
|
||||
common.ServiceIdentifier destination = 1;
|
||||
|
||||
/**
|
||||
* Indicates whether this message is urgent and should trigger a high-priority
|
||||
* notification if the destination device does not have an active message
|
||||
* delivery channel with a Signal server
|
||||
*/
|
||||
bool urgent = 2;
|
||||
|
||||
/**
|
||||
* The messages to send to the destination account.
|
||||
*/
|
||||
IndividualRecipientMessageBundle messages = 3;
|
||||
}
|
||||
|
||||
message SendMessageResponse {
|
||||
|
||||
/**
|
||||
* An error preventing message delivery. If not set, then the message(s) in
|
||||
* the original request were sent to all destination devices.
|
||||
*/
|
||||
oneof error {
|
||||
|
||||
/**
|
||||
* A list of discrepancies between the destination devices identified in a
|
||||
* request to send a message and the devices that are actually linked to an
|
||||
* account.
|
||||
*/
|
||||
MismatchedDevices mismatched_devices = 1;
|
||||
|
||||
/**
|
||||
* A description of a challenge callers must complete before sending
|
||||
* additional messages.
|
||||
*/
|
||||
ChallengeRequired challenge_required = 2;
|
||||
}
|
||||
}
|
||||
|
||||
message MultiRecipientMessage {
|
||||
|
||||
/**
|
||||
* The time, in milliseconds since the epoch, at which this message was
|
||||
* originally sent from the perspective of the sender.
|
||||
*/
|
||||
uint64 timestamp = 1;
|
||||
|
||||
/**
|
||||
* The serialized multi-recipient message payload.
|
||||
*/
|
||||
bytes payload = 2 [(require.size).max = 762144]; // 256 KiB payload + (5000 * 100) of overhead
|
||||
}
|
||||
|
||||
message SendMultiRecipientMessageRequest {
|
||||
|
||||
/**
|
||||
* If true, this message will only be delivered to destination devices that
|
||||
* have an active message delivery channel with a Signal server.
|
||||
*/
|
||||
bool ephemeral = 1;
|
||||
|
||||
/**
|
||||
* Indicates whether this message is urgent and should trigger a high-priority
|
||||
* notification if the destination device does not have an active message
|
||||
* delivery channel with a Signal server
|
||||
*/
|
||||
bool urgent = 2;
|
||||
|
||||
/**
|
||||
* The multi-recipient message to send to all destination accounts and
|
||||
* devices.
|
||||
*/
|
||||
MultiRecipientMessage message = 3;
|
||||
|
||||
/**
|
||||
* A group send endorsement token for the destination account.
|
||||
*/
|
||||
bytes group_send_token = 4;
|
||||
}
|
||||
|
||||
message SendMultiRecipientStoryRequest {
|
||||
|
||||
/**
|
||||
* Indicates whether this message is urgent and should trigger a high-priority
|
||||
* notification if the destination device does not have an active message
|
||||
* delivery channel with a Signal server
|
||||
*/
|
||||
bool urgent = 1;
|
||||
|
||||
/**
|
||||
* The multi-recipient story message to send to all destination accounts and
|
||||
* devices.
|
||||
*/
|
||||
MultiRecipientMessage message = 2;
|
||||
}
|
||||
|
||||
message SendMultiRecipientMessageResponse {
|
||||
|
||||
/**
|
||||
* A list of destination service identifiers that could not be resolved to
|
||||
* registered Signal accounts. If `mismatched_devices` is empty, then the
|
||||
* message in the original request was sent to all service identifiers/devices
|
||||
* in the original request except for the destination devices associated with
|
||||
* the service identifiers in this list.
|
||||
*/
|
||||
repeated common.ServiceIdentifier unresolved_recipients = 1;
|
||||
|
||||
/**
|
||||
* An error preventing message delivery. If not set, then the message was sent
|
||||
* to some or all destination accounts/devices identified in the original
|
||||
* request.
|
||||
*/
|
||||
oneof error {
|
||||
|
||||
/**
|
||||
* A list of sets of discrepancies between the destination devices
|
||||
* identified in a request to send a message and the devices that are
|
||||
* actually linked to a destination account.
|
||||
*/
|
||||
MultiRecipientMismatchedDevices mismatched_devices = 2;
|
||||
|
||||
/**
|
||||
* A description of a challenge callers must complete before sending
|
||||
* additional messages.
|
||||
*/
|
||||
ChallengeRequired challenge_required = 3;
|
||||
}
|
||||
}
|
||||
|
||||
message MismatchedDevices {
|
||||
|
||||
/**
|
||||
* The service identifier to which the devices named in this object are
|
||||
* linked.
|
||||
*/
|
||||
common.ServiceIdentifier service_identifier = 1;
|
||||
|
||||
/**
|
||||
* A list of device IDs that are linked to the destination account, but were
|
||||
* not included in the collection of messages bound for the destination
|
||||
* account.
|
||||
*/
|
||||
repeated uint32 missing_devices = 2 [(require.range).max = 0x7f];
|
||||
|
||||
/**
|
||||
* A list of device IDs that were included in the collection of messages bound
|
||||
* for the destination account, but are not currently linked to the
|
||||
* destination account.
|
||||
*/
|
||||
repeated uint32 extra_devices = 3 [(require.range).max = 0x7f];
|
||||
|
||||
/**
|
||||
* A list of device IDs that present in the collection of messages bound for
|
||||
* the destination account and are linked to the destination account, but have
|
||||
* a different registration ID than the registration ID presented by the
|
||||
* sender (indicating that the destination device has likely been replaced by
|
||||
* another device).
|
||||
*/
|
||||
repeated uint32 stale_devices = 4 [(require.range).max = 0x7f];
|
||||
}
|
||||
|
||||
message MultiRecipientMismatchedDevices {
|
||||
|
||||
/**
|
||||
* A list of sets of discrepancies between the destination devices identified
|
||||
* in a request to send a message and the devices that are actually linked to
|
||||
* a destination account.
|
||||
*/
|
||||
repeated MismatchedDevices mismatched_devices = 1;
|
||||
}
|
||||
|
||||
message ChallengeRequired {
|
||||
|
||||
enum ChallengeType {
|
||||
UNSPECIFIED = 0;
|
||||
|
||||
/**
|
||||
* A challenge that callers can fulfill by completing a captcha.
|
||||
*/
|
||||
CAPTCHA = 1;
|
||||
|
||||
/**
|
||||
* A challenge that callers can fulfill by supplying a token delivered via
|
||||
* push notification.
|
||||
*/
|
||||
PUSH_CHALLENGE = 2;
|
||||
};
|
||||
|
||||
/**
|
||||
* An opaque token identifying this challenge request. Clients must generally
|
||||
* submit this token when submitting a challenge response.
|
||||
*/
|
||||
bytes token = 1;
|
||||
|
||||
/**
|
||||
* A list of challenge types callers may choose to complete to resolve the
|
||||
* challenge requirement. May be empty, in which case callers cannot resolve
|
||||
* the challenge by any means other than waiting.
|
||||
*/
|
||||
repeated ChallengeType challenge_options = 2;
|
||||
|
||||
/**
|
||||
* A duration (in seconds) after which the challenge requirement may be
|
||||
* resolved by simply waiting. May not be set if the challenge cannot be
|
||||
* resolved by waiting.
|
||||
*/
|
||||
optional uint64 retry_after_seconds = 3;
|
||||
}
|
Loading…
Reference in New Issue