From b888c4e40de5a1dc8780e8aa0e0b4743e5accba4 Mon Sep 17 00:00:00 2001 From: Ruben De Smet Date: Thu, 18 Jun 2020 16:04:34 +0200 Subject: [PATCH] Add Signal protobuf files and compile them to Rust. It would be cleaner to yield the compiled files OUT_DIR, but that gets ugly very fast because of https://github.com/rust-lang/rust/issues/48250. --- libsignal-service/.gitignore | 1 + libsignal-service/Cargo.toml | 6 + libsignal-service/build.rs | 25 ++ libsignal-service/protobuf/Provisioning.proto | 36 ++ .../protobuf/SignalService.proto | 422 ++++++++++++++++++ .../protobuf/StickerResources.proto | 24 + .../protobuf/WebSocketResources.proto | 39 ++ libsignal-service/src/lib.rs | 2 + libsignal-service/src/proto.rs | 1 + 9 files changed, 556 insertions(+) create mode 100644 libsignal-service/.gitignore create mode 100644 libsignal-service/build.rs create mode 100644 libsignal-service/protobuf/Provisioning.proto create mode 100644 libsignal-service/protobuf/SignalService.proto create mode 100644 libsignal-service/protobuf/StickerResources.proto create mode 100644 libsignal-service/protobuf/WebSocketResources.proto create mode 100644 libsignal-service/src/proto.rs diff --git a/libsignal-service/.gitignore b/libsignal-service/.gitignore new file mode 100644 index 000000000..5116d3fb3 --- /dev/null +++ b/libsignal-service/.gitignore @@ -0,0 +1 @@ +src/proto/*.rs diff --git a/libsignal-service/Cargo.toml b/libsignal-service/Cargo.toml index d9a324a5f..ade0ece0b 100644 --- a/libsignal-service/Cargo.toml +++ b/libsignal-service/Cargo.toml @@ -12,7 +12,13 @@ failure = "0.1.5" async-trait = "0.1.30" url = "2.1.1" thiserror = "1.0" +serde = {version = "1.0", features=["derive"]} +serde_json = "1.0" +prost = "0.6" [dev-dependencies] structopt = "0.2.17" tokio = { version = "0.2", features=["macros"] } + +[build-dependencies] +prost-build = "0.6" diff --git a/libsignal-service/build.rs b/libsignal-service/build.rs new file mode 100644 index 000000000..34f873820 --- /dev/null +++ b/libsignal-service/build.rs @@ -0,0 +1,25 @@ +use std::path::Path; + +fn main() { + let protobuf = Path::new(env!("CARGO_MANIFEST_DIR")).join("protobuf"); + + let input: Vec<_> = protobuf + .read_dir() + .expect("protobuf directory") + .filter_map(|entry| { + let entry = entry.expect("readable protobuf directory"); + let path = entry.path(); + if Some("proto") + == path.extension().and_then(std::ffi::OsStr::to_str) + { + assert!(path.is_file()); + println!("cargo:rerun-if-changed={}", path.to_str().unwrap()); + Some(path) + } else { + None + } + }) + .collect(); + + prost_build::compile_protos(&input, &[protobuf]).unwrap(); +} diff --git a/libsignal-service/protobuf/Provisioning.proto b/libsignal-service/protobuf/Provisioning.proto new file mode 100644 index 000000000..1f1e452d9 --- /dev/null +++ b/libsignal-service/protobuf/Provisioning.proto @@ -0,0 +1,36 @@ +/** + * Copyright (C) 2014-2016 Open Whisper Systems + * + * Licensed according to the LICENSE file in this repository. + */ +syntax = "proto2"; + +package signalservice; + +option java_package = "org.whispersystems.signalservice.internal.push"; +option java_outer_classname = "ProvisioningProtos"; + +message ProvisionEnvelope { + optional bytes publicKey = 1; + optional bytes body = 2; // Encrypted ProvisionMessage +} + +message ProvisionMessage { + optional bytes identityKeyPublic = 1; + optional bytes identityKeyPrivate = 2; + optional string number = 3; + optional string uuid = 8; + optional string provisioningCode = 4; + optional string userAgent = 5; + optional bytes profileKey = 6; + optional bool readReceipts = 7; + optional uint32 provisioningVersion = 9; +} + +enum ProvisioningVersion { + option allow_alias = true; + + INITIAL = 0; + TABLET_SUPPORT = 1; + CURRENT = 1; +} diff --git a/libsignal-service/protobuf/SignalService.proto b/libsignal-service/protobuf/SignalService.proto new file mode 100644 index 000000000..9e34b9ba9 --- /dev/null +++ b/libsignal-service/protobuf/SignalService.proto @@ -0,0 +1,422 @@ +/** + * Copyright (C) 2014-2016 Open Whisper Systems + * + * Licensed according to the LICENSE file in this repository. + */ +syntax = "proto2"; + +package signalservice; + +option java_package = "org.whispersystems.signalservice.internal.push"; +option java_outer_classname = "SignalServiceProtos"; + +message Envelope { + enum Type { + UNKNOWN = 0; + CIPHERTEXT = 1; + KEY_EXCHANGE = 2; + PREKEY_BUNDLE = 3; + RECEIPT = 5; + UNIDENTIFIED_SENDER = 6; + } + + optional Type type = 1; + optional string sourceE164 = 2; + optional string sourceUuid = 11; + optional uint32 sourceDevice = 7; + optional string relay = 3; + optional uint64 timestamp = 5; + optional bytes legacyMessage = 6; // Contains an encrypted DataMessage + optional bytes content = 8; // Contains an encrypted Content + optional string serverGuid = 9; + optional uint64 serverTimestamp = 10; +} + +message Content { + optional DataMessage dataMessage = 1; + optional SyncMessage syncMessage = 2; + optional CallMessage callMessage = 3; + optional NullMessage nullMessage = 4; + optional ReceiptMessage receiptMessage = 5; + optional TypingMessage typingMessage = 6; +} + +message CallMessage { + message Offer { + optional uint64 id = 1; + optional string description = 2; + } + + message Answer { + optional uint64 id = 1; + optional string description = 2; + } + + message IceUpdate { + optional uint64 id = 1; + optional string sdpMid = 2; + optional uint32 sdpMLineIndex = 3; + optional string sdp = 4; + } + + message Busy { + optional uint64 id = 1; + } + + message Hangup { + optional uint64 id = 1; + } + + + optional Offer offer = 1; + optional Answer answer = 2; + repeated IceUpdate iceUpdate = 3; + optional Hangup hangup = 4; + optional Busy busy = 5; +} + +message DataMessage { + enum Flags { + END_SESSION = 1; + EXPIRATION_TIMER_UPDATE = 2; + PROFILE_KEY_UPDATE = 4; + } + + message Quote { + message QuotedAttachment { + optional string contentType = 1; + optional string fileName = 2; + optional AttachmentPointer thumbnail = 3; + } + + optional uint64 id = 1; + optional string authorE164 = 2; + optional string authorUuid = 5; + optional string text = 3; + repeated QuotedAttachment attachments = 4; + } + + message Contact { + message Name { + optional string givenName = 1; + optional string familyName = 2; + optional string prefix = 3; + optional string suffix = 4; + optional string middleName = 5; + optional string displayName = 6; + } + + message Phone { + enum Type { + HOME = 1; + MOBILE = 2; + WORK = 3; + CUSTOM = 4; + } + + optional string value = 1; + optional Type type = 2; + optional string label = 3; + } + + message Email { + enum Type { + HOME = 1; + MOBILE = 2; + WORK = 3; + CUSTOM = 4; + } + + optional string value = 1; + optional Type type = 2; + optional string label = 3; + } + + message PostalAddress { + enum Type { + HOME = 1; + WORK = 2; + CUSTOM = 3; + } + + optional Type type = 1; + optional string label = 2; + optional string street = 3; + optional string pobox = 4; + optional string neighborhood = 5; + optional string city = 6; + optional string region = 7; + optional string postcode = 8; + optional string country = 9; + } + + message Avatar { + optional AttachmentPointer avatar = 1; + optional bool isProfile = 2; + } + + optional Name name = 1; + repeated Phone number = 3; + repeated Email email = 4; + repeated PostalAddress address = 5; + optional Avatar avatar = 6; + optional string organization = 7; + } + + message Preview { + optional string url = 1; + optional string title = 2; + optional AttachmentPointer image = 3; + } + + message Sticker { + optional bytes packId = 1; + optional bytes packKey = 2; + optional uint32 stickerId = 3; + optional AttachmentPointer data = 4; + } + + enum ProtocolVersion { + option allow_alias = true; + + INITIAL = 0; + MESSAGE_TIMERS = 1; + VIEW_ONCE = 2; + VIEW_ONCE_VIDEO = 3; + CURRENT = 3; + } + + optional string body = 1; + repeated AttachmentPointer attachments = 2; + optional GroupContext group = 3; + optional uint32 flags = 4; + optional uint32 expireTimer = 5; + optional bytes profileKey = 6; + optional uint64 timestamp = 7; + optional Quote quote = 8; + repeated Contact contact = 9; + repeated Preview preview = 10; + optional Sticker sticker = 11; + optional uint32 requiredProtocolVersion = 12; + optional bool isViewOnce = 14; +} + +message NullMessage { + optional bytes padding = 1; +} + +message ReceiptMessage { + enum Type { + DELIVERY = 0; + READ = 1; + } + + optional Type type = 1; + repeated uint64 timestamp = 2; +} + +message TypingMessage { + enum Action { + STARTED = 0; + STOPPED = 1; + } + + optional uint64 timestamp = 1; + optional Action action = 2; + optional bytes groupId = 3; +} + +message Verified { + enum State { + DEFAULT = 0; + VERIFIED = 1; + UNVERIFIED = 2; + } + + optional string destinationE164 = 1; + optional string destinationUuid = 5; + optional bytes identityKey = 2; + optional State state = 3; + optional bytes nullMessage = 4; +} + +message SyncMessage { + message Sent { + message UnidentifiedDeliveryStatus { + optional string destinationE164 = 1; + optional string destinationUuid = 3; + optional bool unidentified = 2; + } + + optional string destinationE164 = 1; + optional string destinationUuid = 7; + optional uint64 timestamp = 2; + optional DataMessage message = 3; + optional uint64 expirationStartTimestamp = 4; + repeated UnidentifiedDeliveryStatus unidentifiedStatus = 5; + optional bool isRecipientUpdate = 6 [default = false]; + } + + message Contacts { + optional AttachmentPointer blob = 1; + optional bool complete = 2 [default = false]; + } + + message Groups { + optional AttachmentPointer blob = 1; + } + + message Blocked { + repeated string numbers = 1; + repeated string uuids = 3; + repeated bytes groupIds = 2; + } + + message Request { + enum Type { + UNKNOWN = 0; + CONTACTS = 1; + GROUPS = 2; + BLOCKED = 3; + CONFIGURATION = 4; + } + + optional Type type = 1; + } + + message Read { + optional string senderE164 = 1; + optional string senderUuid = 3; + optional uint64 timestamp = 2; + } + + message Configuration { + optional bool readReceipts = 1; + optional bool unidentifiedDeliveryIndicators = 2; + optional bool typingIndicators = 3; + optional bool linkPreviews = 4; + optional uint32 provisioningVersion = 5; + } + + message StickerPackOperation { + enum Type { + INSTALL = 0; + REMOVE = 1; + } + + optional bytes packId = 1; + optional bytes packKey = 2; + optional Type type = 3; + } + + message ViewOnceOpen { + optional string senderE164 = 1; + optional string senderUuid = 3; + optional uint64 timestamp = 2; + } + + + message FetchLatest { + enum Type { + UNKNOWN = 0; + LOCAL_PROFILE = 1; + STORAGE_MANIFEST = 2; + } + + optional Type type = 1; + } + + + optional Sent sent = 1; + optional Contacts contacts = 2; + optional Groups groups = 3; + optional Request request = 4; + repeated Read read = 5; + optional Blocked blocked = 6; + optional Verified verified = 7; + optional Configuration configuration = 9; + optional bytes padding = 8; + repeated StickerPackOperation stickerPackOperation = 10; + optional ViewOnceOpen viewOnceOpen = 11; + optional FetchLatest fetchLatest = 12; +} + +message AttachmentPointer { + enum Flags { + VOICE_MESSAGE = 1; + } + + optional fixed64 id = 1; + optional string contentType = 2; + optional bytes key = 3; + optional uint32 size = 4; + optional bytes thumbnail = 5; + optional bytes digest = 6; + optional string fileName = 7; + optional uint32 flags = 8; + optional uint32 width = 9; + optional uint32 height = 10; + optional string caption = 11; + optional string blurHash = 12; +} + +message GroupContext { + enum Type { + UNKNOWN = 0; + UPDATE = 1; + DELIVER = 2; + QUIT = 3; + REQUEST_INFO = 4; + } + + message Member { + optional string uuid = 1; + optional string e164 = 2; + } + + optional bytes id = 1; + optional Type type = 2; + optional string name = 3; + repeated string membersE164 = 4; + repeated Member members = 6; + optional AttachmentPointer avatar = 5; +} + +message ContactDetails { + message Avatar { + optional string contentType = 1; + optional uint32 length = 2; + } + + optional string number = 1; + optional string uuid = 9; + optional string name = 2; + optional Avatar avatar = 3; + optional string color = 4; + optional Verified verified = 5; + optional bytes profileKey = 6; + optional bool blocked = 7; + optional uint32 expireTimer = 8; +} + +message GroupDetails { + message Avatar { + optional string contentType = 1; + optional uint32 length = 2; + } + + message Member { + optional string uuid = 1; + optional string e164 = 2; + } + + optional bytes id = 1; + optional string name = 2; + repeated string membersE164 = 3; + repeated Member members = 9; + optional Avatar avatar = 4; + optional bool active = 5 [default = true]; + optional uint32 expireTimer = 6; + optional string color = 7; + optional bool blocked = 8; +} diff --git a/libsignal-service/protobuf/StickerResources.proto b/libsignal-service/protobuf/StickerResources.proto new file mode 100644 index 000000000..409360883 --- /dev/null +++ b/libsignal-service/protobuf/StickerResources.proto @@ -0,0 +1,24 @@ +/** + * Copyright (C) 2019 Open Whisper Systems + * + * Licensed according to the LICENSE file in this repository. + */ +syntax = "proto2"; + +package signalservice; + +option java_package = "org.whispersystems.signalservice.internal.sticker"; +option java_outer_classname = "StickerProtos"; + +message Pack { + message Sticker { + optional uint32 id = 1; + optional string emoji = 2; + } + + optional string title = 1; + optional string author = 2; + optional Sticker cover = 3; + repeated Sticker stickers = 4; +} + diff --git a/libsignal-service/protobuf/WebSocketResources.proto b/libsignal-service/protobuf/WebSocketResources.proto new file mode 100644 index 000000000..46ea45326 --- /dev/null +++ b/libsignal-service/protobuf/WebSocketResources.proto @@ -0,0 +1,39 @@ +/** + * Copyright (C) 2014-2016 Open Whisper Systems + * + * Licensed according to the LICENSE file in this repository. + */ +syntax = "proto2"; + +package signalservice; + +option java_package = "org.whispersystems.signalservice.internal.websocket"; +option java_outer_classname = "WebSocketProtos"; + +message WebSocketRequestMessage { + optional string verb = 1; + optional string path = 2; + optional bytes body = 3; + repeated string headers = 5; + optional uint64 id = 4; +} + +message WebSocketResponseMessage { + optional uint64 id = 1; + optional uint32 status = 2; + optional string message = 3; + repeated string headers = 5; + optional bytes body = 4; +} + +message WebSocketMessage { + enum Type { + UNKNOWN = 0; + REQUEST = 1; + RESPONSE = 2; + } + + optional Type type = 1; + optional WebSocketRequestMessage request = 2; + optional WebSocketResponseMessage response = 3; +} \ No newline at end of file diff --git a/libsignal-service/src/lib.rs b/libsignal-service/src/lib.rs index 92e28f133..c53925476 100644 --- a/libsignal-service/src/lib.rs +++ b/libsignal-service/src/lib.rs @@ -3,6 +3,8 @@ pub mod configuration; pub mod push_service; pub mod receiver; +mod proto; + pub use crate::account_manager::AccountManager; pub const USER_AGENT: &'static str = diff --git a/libsignal-service/src/proto.rs b/libsignal-service/src/proto.rs new file mode 100644 index 000000000..af7dd6d2f --- /dev/null +++ b/libsignal-service/src/proto.rs @@ -0,0 +1 @@ +include!(concat!(env!("OUT_DIR"), "/signalservice.rs"));