From 3ee205e6bcad28193cc1116f3d85a80eebe24a21 Mon Sep 17 00:00:00 2001 From: CramMK Date: Thu, 9 Jan 2020 15:59:01 +0100 Subject: [PATCH] Add API calls and their infrastructure - Add dependencies - Add authentification (email, password) - Add token request - Fetch /self - Fetch /conversations - Add infrastructure for above - Add auth example --- Cargo.toml | 13 +- build.rs | 16 +- examples/auth.rs | 17 ++ src/lib.rs | 19 +- src/net/mod.rs | 1 + src/net/protos/mod.rs | 2 +- .../protos/{wire_api.rs => wire_websocket.rs} | 168 +++++++++--------- src/net/wire_api/auth.rs | 103 +++++++++++ src/net/wire_api/conversations.rs | 114 ++++++++++++ src/net/wire_api/error.rs | 5 + src/net/wire_api/mod.rs | 3 + wire-api.proto => wire_websocket.proto | 0 12 files changed, 355 insertions(+), 106 deletions(-) create mode 100644 examples/auth.rs rename src/net/protos/{wire_api.rs => wire_websocket.rs} (98%) create mode 100644 src/net/wire_api/auth.rs create mode 100644 src/net/wire_api/conversations.rs create mode 100644 src/net/wire_api/error.rs create mode 100644 src/net/wire_api/mod.rs rename wire-api.proto => wire_websocket.proto (100%) diff --git a/Cargo.toml b/Cargo.toml index 89da1b9..f9661fb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,15 +10,18 @@ bindgen = "0.50" protoc-rust = "2.8.1" [lib] -crate-type = ["dylib"] +crate-type = ["rlib","dylib"] [dependencies] -diesel = { version = "1.4.2", features=["sqlite"] } cryptobox = { git = "https://github.com/wireapp/cryptobox.git", branch = "develop" } proteus = { git = "https://github.com/wireapp/proteus", branch = "develop" } -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" protobuf = "2.8.1" -chrono = { version = "0.4", features = ["serde"] } uuid = { version = "0.7", features = ["serde", "v4"] } base64 = "0.10.1" +tungstenite = "0.9.2" +hyper = "0.13.1" +hyper-tls = "0.4.0" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +tokio = { version = "0.2.6", features = ["full"] } + diff --git a/build.rs b/build.rs index 7fbdf34..6b18ffe 100644 --- a/build.rs +++ b/build.rs @@ -1,7 +1,7 @@ -use std::path::PathBuf; use std::env; -use std::io::prelude::*; use std::fs::File; +use std::io::prelude::*; +use std::path::PathBuf; use protoc_rust::Customize; @@ -14,7 +14,8 @@ typedef struct _WireServerRec { int x; } WireServerRec; -#define STRUCT_SERVER_REC WireServerRec".to_string(); +#define STRUCT_SERVER_REC WireServerRec" + .to_string(); let mut recs = File::create("recs.h").unwrap(); recs.write_all(server_rec.as_bytes()).unwrap(); @@ -33,8 +34,7 @@ typedef struct _WireServerRec { bindings .write_to_file("src/irssi/bindgen_output.rs") .expect("Couldn't write bindings!"); - } - else { + } else { eprintln!("Skipping C binding generation"); } @@ -48,9 +48,9 @@ typedef struct _WireServerRec { customize: Customize { ..Default::default() }, - }).expect("Couln't generate code from protobuffers for wire api"); - } - else { + }) + .expect("Couln't generate code from protobuffers for wire api"); + } else { eprintln!("Skipping protobuf generation"); } } diff --git a/examples/auth.rs b/examples/auth.rs new file mode 100644 index 0000000..fa958b6 --- /dev/null +++ b/examples/auth.rs @@ -0,0 +1,17 @@ +use irssi_wire::net::wire_api::auth::*; +use irssi_wire::net::wire_api::conversations::*; + +#[tokio::main] +async fn main() -> Result<(), Box> { + let mut client = WireClient::new( + String::from("marco_thomas@genua.de"), + String::from("MarcMK1337#"), + Config::Default, + ); + + let auth_response = client.authentification().await.unwrap(); + + let conversations = client.fetch_conversations(&auth_response).await.unwrap(); + + Ok(()) +} diff --git a/src/lib.rs b/src/lib.rs index b8ee9ea..a5c3585 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,28 +1,31 @@ -use std::os::raw::c_int; use std::ffi::CString; +use std::os::raw::c_int; mod irssi; -mod net; +pub mod net; use irssi::bindings::*; #[no_mangle] -pub extern fn wire_core_abicheck(version: *mut c_int) { +pub extern "C" fn wire_core_abicheck(version: *mut c_int) { unsafe { - *version = 23; + *version = 24; } } #[no_mangle] -pub extern fn wire_core_init() { +pub extern "C" fn wire_core_init() { println!("HEY"); unsafe { - module_register_full(CString::new("wire").unwrap().as_ptr(), CString::new("core").unwrap().as_ptr(), CString::new("wire/core").unwrap().as_ptr()); + module_register_full( + CString::new("wire").unwrap().as_ptr(), + CString::new("core").unwrap().as_ptr(), + CString::new("wire/core").unwrap().as_ptr(), + ); } } #[no_mangle] -pub extern fn wire_core_deinit() { +pub extern "C" fn wire_core_deinit() { println!("BYE"); } - diff --git a/src/net/mod.rs b/src/net/mod.rs index 80d1a01..29d6dfa 100644 --- a/src/net/mod.rs +++ b/src/net/mod.rs @@ -1 +1,2 @@ pub mod protos; +pub mod wire_api; diff --git a/src/net/protos/mod.rs b/src/net/protos/mod.rs index 1e9223d..0746210 100644 --- a/src/net/protos/mod.rs +++ b/src/net/protos/mod.rs @@ -1 +1 @@ -pub mod wire_api; +pub mod wire_websocket; diff --git a/src/net/protos/wire_api.rs b/src/net/protos/wire_websocket.rs similarity index 98% rename from src/net/protos/wire_api.rs rename to src/net/protos/wire_websocket.rs index 40ef1f6..76294ff 100644 --- a/src/net/protos/wire_api.rs +++ b/src/net/protos/wire_websocket.rs @@ -1,4 +1,4 @@ -// This file is generated by rust-protobuf 2.8.1. Do not edit +// This file is generated by rust-protobuf 2.10.0. Do not edit // @generated // https://github.com/Manishearth/rust-clippy/issues/702 @@ -17,14 +17,14 @@ #![allow(unsafe_code)] #![allow(unused_imports)] #![allow(unused_results)] -//! Generated file from `wire-api.proto` +//! Generated file from `wire_websocket.proto` use protobuf::Message as Message_imported_for_functions; use protobuf::ProtobufEnum as ProtobufEnum_imported_for_functions; /// Generated files are compatible only with the same version /// of protobuf runtime. -const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_8_1; +const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_10_0; #[derive(PartialEq,Clone,Default)] pub struct GenericMessage { @@ -10612,89 +10612,89 @@ impl ::protobuf::reflect::ProtobufValue for LegalHoldStatus { } static file_descriptor_proto_data: &'static [u8] = b"\ - \n\x0ewire-api.proto\"\xf3\x05\n\x0eGenericMessage\x12\x1d\n\nmessage_id\ - \x18\x01\x20\x02(\tR\tmessageId\x12\x1b\n\x04text\x18\x02\x20\x01(\x0b2\ + \n\x14wire_websocket.proto\"\xf3\x05\n\x0eGenericMessage\x12\x1d\n\nmess\ + age_id\x18\x01\x20\x02(\tR\tmessageId\x12\x1b\n\x04text\x18\x02\x20\x01(\ + \x0b2\x05.TextH\0R\x04text\x12#\n\x05image\x18\x03\x20\x01(\x0b2\x0b.Ima\ + geAssetH\0R\x05image\x12\x1e\n\x05knock\x18\x04\x20\x01(\x0b2\x06.KnockH\ + \0R\x05knock\x12'\n\x08lastRead\x18\x06\x20\x01(\x0b2\t.LastReadH\0R\x08\ + lastRead\x12$\n\x07cleared\x18\x07\x20\x01(\x0b2\x08.ClearedH\0R\x07clea\ + red\x12'\n\x08external\x18\x08\x20\x01(\x0b2\t.ExternalH\0R\x08external\ + \x123\n\x0cclientAction\x18\t\x20\x01(\x0e2\r.ClientActionH\0R\x0cclient\ + Action\x12$\n\x07calling\x18\n\x20\x01(\x0b2\x08.CallingH\0R\x07calling\ + \x12\x1e\n\x05asset\x18\x0b\x20\x01(\x0b2\x06.AssetH\0R\x05asset\x12&\n\ + \x06hidden\x18\x0c\x20\x01(\x0b2\x0c.MessageHideH\0R\x06hidden\x12'\n\ + \x08location\x18\r\x20\x01(\x0b2\t.LocationH\0R\x08location\x12*\n\x07de\ + leted\x18\x0e\x20\x01(\x0b2\x0e.MessageDeleteH\0R\x07deleted\x12&\n\x06e\ + dited\x18\x0f\x20\x01(\x0b2\x0c.MessageEditH\0R\x06edited\x123\n\x0cconf\ + irmation\x18\x10\x20\x01(\x0b2\r.ConfirmationH\0R\x0cconfirmation\x12'\n\ + \x08reaction\x18\x11\x20\x01(\x0b2\t.ReactionH\0R\x08reaction\x12*\n\tep\ + hemeral\x18\x12\x20\x01(\x0b2\n.EphemeralH\0R\tephemeral\x123\n\x0cavail\ + ability\x18\x13\x20\x01(\x0b2\r.AvailabilityH\0R\x0cavailabilityB\t\n\ + \x07content\"k\n\x0cAvailability\x12&\n\x04type\x18\x01\x20\x02(\x0e2\ + \x12.Availability.TypeR\x04type\"3\n\x04Type\x12\x08\n\x04NONE\x10\0\x12\ + \r\n\tAVAILABLE\x10\x01\x12\x08\n\x04AWAY\x10\x02\x12\x08\n\x04BUSY\x10\ + \x03\"\xf1\x01\n\tEphemeral\x12.\n\x13expire_after_millis\x18\x01\x20\ + \x02(\x03R\x11expireAfterMillis\x12\x1b\n\x04text\x18\x02\x20\x01(\x0b2\ \x05.TextH\0R\x04text\x12#\n\x05image\x18\x03\x20\x01(\x0b2\x0b.ImageAss\ etH\0R\x05image\x12\x1e\n\x05knock\x18\x04\x20\x01(\x0b2\x06.KnockH\0R\ - \x05knock\x12'\n\x08lastRead\x18\x06\x20\x01(\x0b2\t.LastReadH\0R\x08las\ - tRead\x12$\n\x07cleared\x18\x07\x20\x01(\x0b2\x08.ClearedH\0R\x07cleared\ - \x12'\n\x08external\x18\x08\x20\x01(\x0b2\t.ExternalH\0R\x08external\x12\ - 3\n\x0cclientAction\x18\t\x20\x01(\x0e2\r.ClientActionH\0R\x0cclientActi\ - on\x12$\n\x07calling\x18\n\x20\x01(\x0b2\x08.CallingH\0R\x07calling\x12\ - \x1e\n\x05asset\x18\x0b\x20\x01(\x0b2\x06.AssetH\0R\x05asset\x12&\n\x06h\ - idden\x18\x0c\x20\x01(\x0b2\x0c.MessageHideH\0R\x06hidden\x12'\n\x08loca\ - tion\x18\r\x20\x01(\x0b2\t.LocationH\0R\x08location\x12*\n\x07deleted\ - \x18\x0e\x20\x01(\x0b2\x0e.MessageDeleteH\0R\x07deleted\x12&\n\x06edited\ - \x18\x0f\x20\x01(\x0b2\x0c.MessageEditH\0R\x06edited\x123\n\x0cconfirmat\ - ion\x18\x10\x20\x01(\x0b2\r.ConfirmationH\0R\x0cconfirmation\x12'\n\x08r\ - eaction\x18\x11\x20\x01(\x0b2\t.ReactionH\0R\x08reaction\x12*\n\tephemer\ - al\x18\x12\x20\x01(\x0b2\n.EphemeralH\0R\tephemeral\x123\n\x0cavailabili\ - ty\x18\x13\x20\x01(\x0b2\r.AvailabilityH\0R\x0cavailabilityB\t\n\x07cont\ - ent\"k\n\x0cAvailability\x12&\n\x04type\x18\x01\x20\x02(\x0e2\x12.Availa\ - bility.TypeR\x04type\"3\n\x04Type\x12\x08\n\x04NONE\x10\0\x12\r\n\tAVAIL\ - ABLE\x10\x01\x12\x08\n\x04AWAY\x10\x02\x12\x08\n\x04BUSY\x10\x03\"\xf1\ - \x01\n\tEphemeral\x12.\n\x13expire_after_millis\x18\x01\x20\x02(\x03R\ - \x11expireAfterMillis\x12\x1b\n\x04text\x18\x02\x20\x01(\x0b2\x05.TextH\ - \0R\x04text\x12#\n\x05image\x18\x03\x20\x01(\x0b2\x0b.ImageAssetH\0R\x05\ - image\x12\x1e\n\x05knock\x18\x04\x20\x01(\x0b2\x06.KnockH\0R\x05knock\ - \x12\x1e\n\x05asset\x18\x05\x20\x01(\x0b2\x06.AssetH\0R\x05asset\x12'\n\ - \x08location\x18\x06\x20\x01(\x0b2\t.LocationH\0R\x08locationB\t\n\x07co\ - ntent\"\x9f\x02\n\x04Text\x12\x18\n\x07content\x18\x01\x20\x02(\tR\x07co\ - ntent\x12/\n\x0clink_preview\x18\x03\x20\x03(\x0b2\x0c.LinkPreviewR\x0bl\ - inkPreview\x12$\n\x08mentions\x18\x04\x20\x03(\x0b2\x08.MentionR\x08ment\ - ions\x12\x1c\n\x05quote\x18\x05\x20\x01(\x0b2\x06.QuoteR\x05quote\x12A\n\ - \x19expects_read_confirmation\x18\x06\x20\x01(\x08:\x05falseR\x17expects\ - ReadConfirmation\x12E\n\x11legal_hold_status\x18\x07\x20\x01(\x0e2\x10.L\ - egalHoldStatus:\x07UNKNOWNR\x0flegalHoldStatus\"\xb5\x01\n\x05Knock\x12\ - \"\n\thot_knock\x18\x01\x20\x02(\x08:\x05falseR\x08hotKnock\x12A\n\x19ex\ - pects_read_confirmation\x18\x02\x20\x01(\x08:\x05falseR\x17expectsReadCo\ - nfirmation\x12E\n\x11legal_hold_status\x18\x03\x20\x01(\x0e2\x10.LegalHo\ - ldStatus:\x07UNKNOWNR\x0flegalHoldStatus\"\x8f\x02\n\x0bLinkPreview\x12\ - \x10\n\x03url\x18\x01\x20\x02(\tR\x03url\x12\x1d\n\nurl_offset\x18\x02\ - \x20\x02(\x05R\turlOffset\x12$\n\x07article\x18\x03\x20\x01(\x0b2\x08.Ar\ - ticleH\0R\x07article\x12#\n\rpermanent_url\x18\x05\x20\x01(\tR\x0cperman\ - entUrl\x12\x14\n\x05title\x18\x06\x20\x01(\tR\x05title\x12\x18\n\x07summ\ - ary\x18\x07\x20\x01(\tR\x07summary\x12\x1c\n\x05image\x18\x08\x20\x01(\ - \x0b2\x06.AssetR\x05image\x12\x1e\n\x05tweet\x18\t\x20\x01(\x0b2\x06.Twe\ - etH\x01R\x05tweetB\t\n\x07previewB\x0b\n\tmeta_data\";\n\x05Tweet\x12\ - \x16\n\x06author\x18\x01\x20\x01(\tR\x06author\x12\x1a\n\x08username\x18\ - \x02\x20\x01(\tR\x08username\"|\n\x07Article\x12#\n\rpermanent_url\x18\ - \x01\x20\x02(\tR\x0cpermanentUrl\x12\x14\n\x05title\x18\x02\x20\x01(\tR\ - \x05title\x12\x18\n\x07summary\x18\x03\x20\x01(\tR\x07summary\x12\x1c\n\ - \x05image\x18\x04\x20\x01(\x0b2\x06.AssetR\x05image\"b\n\x07Mention\x12\ - \x14\n\x05start\x18\x01\x20\x02(\x05R\x05start\x12\x16\n\x06length\x18\ - \x02\x20\x02(\x05R\x06length\x12\x19\n\x07user_id\x18\x03\x20\x01(\tH\0R\ - \x06userIdB\x0e\n\x0cmention_type\"c\n\x08LastRead\x12'\n\x0fconversatio\ - n_id\x18\x01\x20\x02(\tR\x0econversationId\x12.\n\x13last_read_timestamp\ - \x18\x02\x20\x02(\x03R\x11lastReadTimestamp\"_\n\x07Cleared\x12'\n\x0fco\ - nversation_id\x18\x01\x20\x02(\tR\x0econversationId\x12+\n\x11cleared_ti\ - mestamp\x18\x02\x20\x02(\x03R\x10clearedTimestamp\"U\n\x0bMessageHide\ - \x12'\n\x0fconversation_id\x18\x01\x20\x02(\tR\x0econversationId\x12\x1d\ - \n\nmessage_id\x18\x02\x20\x02(\tR\tmessageId\".\n\rMessageDelete\x12\ - \x1d\n\nmessage_id\x18\x01\x20\x02(\tR\tmessageId\"g\n\x0bMessageEdit\ - \x120\n\x14replacing_message_id\x18\x01\x20\x02(\tR\x12replacingMessageI\ - d\x12\x1b\n\x04text\x18\x02\x20\x01(\x0b2\x05.TextH\0R\x04textB\t\n\x07c\ - ontent\"g\n\x05Quote\x12*\n\x11quoted_message_id\x18\x01\x20\x02(\tR\x0f\ - quotedMessageId\x122\n\x15quoted_message_sha256\x18\x02\x20\x01(\x0cR\ - \x13quotedMessageSha256\"\xab\x01\n\x0cConfirmation\x12&\n\x04type\x18\ - \x02\x20\x02(\x0e2\x12.Confirmation.TypeR\x04type\x12(\n\x10first_messag\ - e_id\x18\x01\x20\x02(\tR\x0efirstMessageId\x12(\n\x10more_message_ids\ - \x18\x03\x20\x03(\tR\x0emoreMessageIds\"\x1f\n\x04Type\x12\r\n\tDELIVERE\ - D\x10\0\x12\x08\n\x04READ\x10\x01\"\xf6\x01\n\x08Location\x12\x1c\n\tlon\ - gitude\x18\x01\x20\x02(\x02R\tlongitude\x12\x1a\n\x08latitude\x18\x02\ - \x20\x02(\x02R\x08latitude\x12\x12\n\x04name\x18\x03\x20\x01(\tR\x04name\ - \x12\x12\n\x04zoom\x18\x04\x20\x01(\x05R\x04zoom\x12A\n\x19expects_read_\ - confirmation\x18\x05\x20\x01(\x08:\x05falseR\x17expectsReadConfirmation\ - \x12E\n\x11legal_hold_status\x18\x06\x20\x01(\x0e2\x10.LegalHoldStatus:\ - \x07UNKNOWNR\x0flegalHoldStatus\"\xa9\x02\n\nImageAsset\x12\x10\n\x03tag\ - \x18\x01\x20\x02(\tR\x03tag\x12\x14\n\x05width\x18\x02\x20\x02(\x05R\x05\ - width\x12\x16\n\x06height\x18\x03\x20\x02(\x05R\x06height\x12%\n\x0eorig\ - inal_width\x18\x04\x20\x02(\x05R\roriginalWidth\x12'\n\x0foriginal_heigh\ - t\x18\x05\x20\x02(\x05R\x0eoriginalHeight\x12\x1b\n\tmime_type\x18\x06\ - \x20\x02(\tR\x08mimeType\x12\x12\n\x04size\x18\x07\x20\x02(\x05R\x04size\ - \x12\x17\n\x07otr_key\x18\x08\x20\x01(\x0cR\x06otrKey\x12\x17\n\x07mac_k\ - ey\x18\t\x20\x01(\x0cR\x06macKey\x12\x10\n\x03mac\x18\n\x20\x01(\x0cR\ - \x03mac\x12\x16\n\x06sha256\x18\x0b\x20\x01(\x0cR\x06sha256\"\xa4\n\n\ + \x05knock\x12\x1e\n\x05asset\x18\x05\x20\x01(\x0b2\x06.AssetH\0R\x05asse\ + t\x12'\n\x08location\x18\x06\x20\x01(\x0b2\t.LocationH\0R\x08locationB\t\ + \n\x07content\"\x9f\x02\n\x04Text\x12\x18\n\x07content\x18\x01\x20\x02(\ + \tR\x07content\x12/\n\x0clink_preview\x18\x03\x20\x03(\x0b2\x0c.LinkPrev\ + iewR\x0blinkPreview\x12$\n\x08mentions\x18\x04\x20\x03(\x0b2\x08.Mention\ + R\x08mentions\x12\x1c\n\x05quote\x18\x05\x20\x01(\x0b2\x06.QuoteR\x05quo\ + te\x12A\n\x19expects_read_confirmation\x18\x06\x20\x01(\x08:\x05falseR\ + \x17expectsReadConfirmation\x12E\n\x11legal_hold_status\x18\x07\x20\x01(\ + \x0e2\x10.LegalHoldStatus:\x07UNKNOWNR\x0flegalHoldStatus\"\xb5\x01\n\ + \x05Knock\x12\"\n\thot_knock\x18\x01\x20\x02(\x08:\x05falseR\x08hotKnock\ + \x12A\n\x19expects_read_confirmation\x18\x02\x20\x01(\x08:\x05falseR\x17\ + expectsReadConfirmation\x12E\n\x11legal_hold_status\x18\x03\x20\x01(\x0e\ + 2\x10.LegalHoldStatus:\x07UNKNOWNR\x0flegalHoldStatus\"\x8f\x02\n\x0bLin\ + kPreview\x12\x10\n\x03url\x18\x01\x20\x02(\tR\x03url\x12\x1d\n\nurl_offs\ + et\x18\x02\x20\x02(\x05R\turlOffset\x12$\n\x07article\x18\x03\x20\x01(\ + \x0b2\x08.ArticleH\0R\x07article\x12#\n\rpermanent_url\x18\x05\x20\x01(\ + \tR\x0cpermanentUrl\x12\x14\n\x05title\x18\x06\x20\x01(\tR\x05title\x12\ + \x18\n\x07summary\x18\x07\x20\x01(\tR\x07summary\x12\x1c\n\x05image\x18\ + \x08\x20\x01(\x0b2\x06.AssetR\x05image\x12\x1e\n\x05tweet\x18\t\x20\x01(\ + \x0b2\x06.TweetH\x01R\x05tweetB\t\n\x07previewB\x0b\n\tmeta_data\";\n\ + \x05Tweet\x12\x16\n\x06author\x18\x01\x20\x01(\tR\x06author\x12\x1a\n\ + \x08username\x18\x02\x20\x01(\tR\x08username\"|\n\x07Article\x12#\n\rper\ + manent_url\x18\x01\x20\x02(\tR\x0cpermanentUrl\x12\x14\n\x05title\x18\ + \x02\x20\x01(\tR\x05title\x12\x18\n\x07summary\x18\x03\x20\x01(\tR\x07su\ + mmary\x12\x1c\n\x05image\x18\x04\x20\x01(\x0b2\x06.AssetR\x05image\"b\n\ + \x07Mention\x12\x14\n\x05start\x18\x01\x20\x02(\x05R\x05start\x12\x16\n\ + \x06length\x18\x02\x20\x02(\x05R\x06length\x12\x19\n\x07user_id\x18\x03\ + \x20\x01(\tH\0R\x06userIdB\x0e\n\x0cmention_type\"c\n\x08LastRead\x12'\n\ + \x0fconversation_id\x18\x01\x20\x02(\tR\x0econversationId\x12.\n\x13last\ + _read_timestamp\x18\x02\x20\x02(\x03R\x11lastReadTimestamp\"_\n\x07Clear\ + ed\x12'\n\x0fconversation_id\x18\x01\x20\x02(\tR\x0econversationId\x12+\ + \n\x11cleared_timestamp\x18\x02\x20\x02(\x03R\x10clearedTimestamp\"U\n\ + \x0bMessageHide\x12'\n\x0fconversation_id\x18\x01\x20\x02(\tR\x0econvers\ + ationId\x12\x1d\n\nmessage_id\x18\x02\x20\x02(\tR\tmessageId\".\n\rMessa\ + geDelete\x12\x1d\n\nmessage_id\x18\x01\x20\x02(\tR\tmessageId\"g\n\x0bMe\ + ssageEdit\x120\n\x14replacing_message_id\x18\x01\x20\x02(\tR\x12replacin\ + gMessageId\x12\x1b\n\x04text\x18\x02\x20\x01(\x0b2\x05.TextH\0R\x04textB\ + \t\n\x07content\"g\n\x05Quote\x12*\n\x11quoted_message_id\x18\x01\x20\ + \x02(\tR\x0fquotedMessageId\x122\n\x15quoted_message_sha256\x18\x02\x20\ + \x01(\x0cR\x13quotedMessageSha256\"\xab\x01\n\x0cConfirmation\x12&\n\x04\ + type\x18\x02\x20\x02(\x0e2\x12.Confirmation.TypeR\x04type\x12(\n\x10firs\ + t_message_id\x18\x01\x20\x02(\tR\x0efirstMessageId\x12(\n\x10more_messag\ + e_ids\x18\x03\x20\x03(\tR\x0emoreMessageIds\"\x1f\n\x04Type\x12\r\n\tDEL\ + IVERED\x10\0\x12\x08\n\x04READ\x10\x01\"\xf6\x01\n\x08Location\x12\x1c\n\ + \tlongitude\x18\x01\x20\x02(\x02R\tlongitude\x12\x1a\n\x08latitude\x18\ + \x02\x20\x02(\x02R\x08latitude\x12\x12\n\x04name\x18\x03\x20\x01(\tR\x04\ + name\x12\x12\n\x04zoom\x18\x04\x20\x01(\x05R\x04zoom\x12A\n\x19expects_r\ + ead_confirmation\x18\x05\x20\x01(\x08:\x05falseR\x17expectsReadConfirmat\ + ion\x12E\n\x11legal_hold_status\x18\x06\x20\x01(\x0e2\x10.LegalHoldStatu\ + s:\x07UNKNOWNR\x0flegalHoldStatus\"\xa9\x02\n\nImageAsset\x12\x10\n\x03t\ + ag\x18\x01\x20\x02(\tR\x03tag\x12\x14\n\x05width\x18\x02\x20\x02(\x05R\ + \x05width\x12\x16\n\x06height\x18\x03\x20\x02(\x05R\x06height\x12%\n\x0e\ + original_width\x18\x04\x20\x02(\x05R\roriginalWidth\x12'\n\x0foriginal_h\ + eight\x18\x05\x20\x02(\x05R\x0eoriginalHeight\x12\x1b\n\tmime_type\x18\ + \x06\x20\x02(\tR\x08mimeType\x12\x12\n\x04size\x18\x07\x20\x02(\x05R\x04\ + size\x12\x17\n\x07otr_key\x18\x08\x20\x01(\x0cR\x06otrKey\x12\x17\n\x07m\ + ac_key\x18\t\x20\x01(\x0cR\x06macKey\x12\x10\n\x03mac\x18\n\x20\x01(\x0c\ + R\x03mac\x12\x16\n\x06sha256\x18\x0b\x20\x01(\x0cR\x06sha256\"\xa4\n\n\ \x05Asset\x12+\n\x08original\x18\x01\x20\x01(\x0b2\x0f.Asset.OriginalR\ \x08original\x127\n\x0cnot_uploaded\x18\x03\x20\x01(\x0e2\x12.Asset.NotU\ ploadedH\0R\x0bnotUploaded\x12/\n\x08uploaded\x18\x04\x20\x01(\x0b2\x11.\ diff --git a/src/net/wire_api/auth.rs b/src/net/wire_api/auth.rs new file mode 100644 index 0000000..619208f --- /dev/null +++ b/src/net/wire_api/auth.rs @@ -0,0 +1,103 @@ +use hyper::body::Buf; +use hyper::client::connect::HttpConnector; +use hyper::{header, Body, Client, Method, Request}; +use hyper_tls::HttpsConnector; +use serde::{Deserialize, Serialize}; + +use crate::net::wire_api::error::ApiError; + +const USER_AGENT: &str = "irssi"; +const CONTENT_TYPE: &str = "application/json"; + +#[derive(Debug, Clone)] +pub struct ConnectionUrls { + pub websocket: String, + pub rest_url: String, +} + +#[derive(Debug, Clone)] +pub enum Config { + Default, + Custom(ConnectionUrls), +} + +impl Config { + pub fn fetch(&mut self) -> ConnectionUrls { + match self { + Config::Default => ConnectionUrls { + websocket: String::from("wss://prod-nginz-ssl.wire.com"), + rest_url: String::from("https://prod-nginz-https.wire.com"), + }, + Config::Custom(urls) => urls.clone(), + } + } +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct LoginInfo { + email: String, + password: String, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct AuthResponse { + expires_in: u32, + token_type: String, + user: String, + access_token: String, +} + +impl AuthResponse { + pub fn token_string(&self) -> String { + [&self.token_type, " ", &self.access_token].concat() + } +} + +pub struct WireClient { + login_info: LoginInfo, + pub client: Client>, + pub config: Config, +} + +impl WireClient { + pub fn new(email: String, password: String, config: Config) -> WireClient { + let https_client = Client::builder().build::<_, hyper::Body>(HttpsConnector::new()); + WireClient { + login_info: LoginInfo { email, password }, + client: https_client, + config: config, + } + } + + pub async fn authentification(&mut self) -> Result { + let endpoint = [ + self.config.fetch().rest_url, + "/login?persist=true".to_string(), + ] + .concat(); + let json = serde_json::to_string(&self.login_info).unwrap(); + + let auth_request = Request::builder() + .method(Method::POST) + .uri(endpoint) + .header(header::CONTENT_TYPE, CONTENT_TYPE) + .header(header::USER_AGENT, USER_AGENT) + .body(Body::from(json)) + .unwrap(); + + let auth_result = self + .client + .request(auth_request) + .await + .map_err(|e| ApiError::HttpError(e))?; + + let auth_body = hyper::body::aggregate(auth_result) + .await + .map_err(|e| ApiError::HttpError(e))?; + + let auth_response = serde_json::from_reader(auth_body.bytes()) + .map_err(|e| ApiError::JsonParseError(Box::new(e)))?; + + Ok(auth_response) + } +} diff --git a/src/net/wire_api/conversations.rs b/src/net/wire_api/conversations.rs new file mode 100644 index 0000000..28123a6 --- /dev/null +++ b/src/net/wire_api/conversations.rs @@ -0,0 +1,114 @@ +use hyper::body::Buf; +use hyper::client::connect::HttpConnector; +use hyper::{header, Body, Client, Method, Request}; +use hyper_tls::HttpsConnector; +use serde::{Deserialize, Serialize}; + +use crate::net::wire_api::auth::{AuthResponse, Config, WireClient}; +use crate::net::wire_api::error::ApiError; + +const CONTENT_TYPE: &str = "application/json"; +const USER_AGENT: &str = "irssi"; + +#[derive(Serialize, Deserialize, Debug)] +pub struct Conversations { + has_more: Option, + conversations: Option>, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct Conversation { + access: Option, + creator: Option, + access_role: Option, + members: Option, + name: Option, + team: Option, + id: Option, + r#type: Option, + receipt_mode: Option, + last_event_time: String, + message_timer: Option, + last_event: Option, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct Access { + #[serde(rename = "0")] + _0: Option, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct ConversationMembers { + #[serde(rename = "self")] + self_: Option, + others: Option>, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct Member { + hidden_ref: Option, + stauts: Option, + service: Option, + otr_muted_ref: Option, + conversation_role: Option, + status_time: Option, + hidden: Option, + status_ref: Option, + id: Option, + otr_archived: Option, + otr_muted_status: Option, + otr_muted: Option, + otr_archived_ref: Option, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct OtherMember { + status: Option, + conversation_role: Option, + id: Option, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct ServiceRef { + id: String, + provider: String, +} + +impl WireClient { + pub async fn fetch_conversations( + &mut self, + auth_response: &AuthResponse, + ) -> Result { + let endpoint = [ + self.config.fetch().rest_url, + String::from("/conversations?size=500"), + ] + .concat(); + let auth_token = auth_response.token_string(); + + let fetch_request = Request::builder() + .method(Method::GET) + .uri(endpoint) + .header(header::CONTENT_TYPE, CONTENT_TYPE) + .header(header::USER_AGENT, USER_AGENT) + .header(header::AUTHORIZATION, auth_token) + .body(Body::empty()) + .unwrap(); + + let fetch_result = self + .client + .request(fetch_request) + .await + .map_err(|e| ApiError::HttpError(e))?; + + let fetch_body = hyper::body::aggregate(fetch_result) + .await + .map_err(|e| ApiError::HttpError(e))?; + + let fetch_response = serde_json::from_reader(fetch_body.bytes()) + .map_err(|e| ApiError::JsonParseError(Box::new(e)))?; + + Ok(fetch_response) + } +} diff --git a/src/net/wire_api/error.rs b/src/net/wire_api/error.rs new file mode 100644 index 0000000..1e809ab --- /dev/null +++ b/src/net/wire_api/error.rs @@ -0,0 +1,5 @@ +#[derive(Debug)] +pub enum ApiError { + JsonParseError(Box), + HttpError(hyper::error::Error), +} diff --git a/src/net/wire_api/mod.rs b/src/net/wire_api/mod.rs new file mode 100644 index 0000000..9db02b3 --- /dev/null +++ b/src/net/wire_api/mod.rs @@ -0,0 +1,3 @@ +pub mod auth; +pub mod conversations; +pub mod error; diff --git a/wire-api.proto b/wire_websocket.proto similarity index 100% rename from wire-api.proto rename to wire_websocket.proto