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
This commit is contained in:
CramMK
2020-01-09 15:59:01 +01:00
parent 3c21cf6f4a
commit 3ee205e6bc
12 changed files with 355 additions and 106 deletions

View File

@@ -10,15 +10,18 @@ bindgen = "0.50"
protoc-rust = "2.8.1" protoc-rust = "2.8.1"
[lib] [lib]
crate-type = ["dylib"] crate-type = ["rlib","dylib"]
[dependencies] [dependencies]
diesel = { version = "1.4.2", features=["sqlite"] }
cryptobox = { git = "https://github.com/wireapp/cryptobox.git", branch = "develop" } cryptobox = { git = "https://github.com/wireapp/cryptobox.git", branch = "develop" }
proteus = { git = "https://github.com/wireapp/proteus", 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" protobuf = "2.8.1"
chrono = { version = "0.4", features = ["serde"] }
uuid = { version = "0.7", features = ["serde", "v4"] } uuid = { version = "0.7", features = ["serde", "v4"] }
base64 = "0.10.1" 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"] }

View File

@@ -1,7 +1,7 @@
use std::path::PathBuf;
use std::env; use std::env;
use std::io::prelude::*;
use std::fs::File; use std::fs::File;
use std::io::prelude::*;
use std::path::PathBuf;
use protoc_rust::Customize; use protoc_rust::Customize;
@@ -14,7 +14,8 @@ typedef struct _WireServerRec {
int x; int x;
} WireServerRec; } WireServerRec;
#define STRUCT_SERVER_REC WireServerRec".to_string(); #define STRUCT_SERVER_REC WireServerRec"
.to_string();
let mut recs = File::create("recs.h").unwrap(); let mut recs = File::create("recs.h").unwrap();
recs.write_all(server_rec.as_bytes()).unwrap(); recs.write_all(server_rec.as_bytes()).unwrap();
@@ -33,8 +34,7 @@ typedef struct _WireServerRec {
bindings bindings
.write_to_file("src/irssi/bindgen_output.rs") .write_to_file("src/irssi/bindgen_output.rs")
.expect("Couldn't write bindings!"); .expect("Couldn't write bindings!");
} } else {
else {
eprintln!("Skipping C binding generation"); eprintln!("Skipping C binding generation");
} }
@@ -48,9 +48,9 @@ typedef struct _WireServerRec {
customize: Customize { customize: Customize {
..Default::default() ..Default::default()
}, },
}).expect("Couln't generate code from protobuffers for wire api"); })
} .expect("Couln't generate code from protobuffers for wire api");
else { } else {
eprintln!("Skipping protobuf generation"); eprintln!("Skipping protobuf generation");
} }
} }

17
examples/auth.rs Normal file
View File

@@ -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<dyn std::error::Error>> {
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(())
}

View File

@@ -1,28 +1,31 @@
use std::os::raw::c_int;
use std::ffi::CString; use std::ffi::CString;
use std::os::raw::c_int;
mod irssi; mod irssi;
mod net; pub mod net;
use irssi::bindings::*; use irssi::bindings::*;
#[no_mangle] #[no_mangle]
pub extern fn wire_core_abicheck(version: *mut c_int) { pub extern "C" fn wire_core_abicheck(version: *mut c_int) {
unsafe { unsafe {
*version = 23; *version = 24;
} }
} }
#[no_mangle] #[no_mangle]
pub extern fn wire_core_init() { pub extern "C" fn wire_core_init() {
println!("HEY"); println!("HEY");
unsafe { 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] #[no_mangle]
pub extern fn wire_core_deinit() { pub extern "C" fn wire_core_deinit() {
println!("BYE"); println!("BYE");
} }

View File

@@ -1 +1,2 @@
pub mod protos; pub mod protos;
pub mod wire_api;

View File

@@ -1 +1 @@
pub mod wire_api; pub mod wire_websocket;

View File

@@ -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 // @generated
// https://github.com/Manishearth/rust-clippy/issues/702 // https://github.com/Manishearth/rust-clippy/issues/702
@@ -17,14 +17,14 @@
#![allow(unsafe_code)] #![allow(unsafe_code)]
#![allow(unused_imports)] #![allow(unused_imports)]
#![allow(unused_results)] #![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::Message as Message_imported_for_functions;
use protobuf::ProtobufEnum as ProtobufEnum_imported_for_functions; use protobuf::ProtobufEnum as ProtobufEnum_imported_for_functions;
/// Generated files are compatible only with the same version /// Generated files are compatible only with the same version
/// of protobuf runtime. /// 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)] #[derive(PartialEq,Clone,Default)]
pub struct GenericMessage { pub struct GenericMessage {
@@ -10612,89 +10612,89 @@ impl ::protobuf::reflect::ProtobufValue for LegalHoldStatus {
} }
static file_descriptor_proto_data: &'static [u8] = b"\ static file_descriptor_proto_data: &'static [u8] = b"\
\n\x0ewire-api.proto\"\xf3\x05\n\x0eGenericMessage\x12\x1d\n\nmessage_id\ \n\x14wire_websocket.proto\"\xf3\x05\n\x0eGenericMessage\x12\x1d\n\nmess\
\x18\x01\x20\x02(\tR\tmessageId\x12\x1b\n\x04text\x18\x02\x20\x01(\x0b2\ 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\ \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\ 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\ \x05knock\x12\x1e\n\x05asset\x18\x05\x20\x01(\x0b2\x06.AssetH\0R\x05asse\
tRead\x12$\n\x07cleared\x18\x07\x20\x01(\x0b2\x08.ClearedH\0R\x07cleared\ t\x12'\n\x08location\x18\x06\x20\x01(\x0b2\t.LocationH\0R\x08locationB\t\
\x12'\n\x08external\x18\x08\x20\x01(\x0b2\t.ExternalH\0R\x08external\x12\ \n\x07content\"\x9f\x02\n\x04Text\x12\x18\n\x07content\x18\x01\x20\x02(\
3\n\x0cclientAction\x18\t\x20\x01(\x0e2\r.ClientActionH\0R\x0cclientActi\ \tR\x07content\x12/\n\x0clink_preview\x18\x03\x20\x03(\x0b2\x0c.LinkPrev\
on\x12$\n\x07calling\x18\n\x20\x01(\x0b2\x08.CallingH\0R\x07calling\x12\ iewR\x0blinkPreview\x12$\n\x08mentions\x18\x04\x20\x03(\x0b2\x08.Mention\
\x1e\n\x05asset\x18\x0b\x20\x01(\x0b2\x06.AssetH\0R\x05asset\x12&\n\x06h\ R\x08mentions\x12\x1c\n\x05quote\x18\x05\x20\x01(\x0b2\x06.QuoteR\x05quo\
idden\x18\x0c\x20\x01(\x0b2\x0c.MessageHideH\0R\x06hidden\x12'\n\x08loca\ te\x12A\n\x19expects_read_confirmation\x18\x06\x20\x01(\x08:\x05falseR\
tion\x18\r\x20\x01(\x0b2\t.LocationH\0R\x08location\x12*\n\x07deleted\ \x17expectsReadConfirmation\x12E\n\x11legal_hold_status\x18\x07\x20\x01(\
\x18\x0e\x20\x01(\x0b2\x0e.MessageDeleteH\0R\x07deleted\x12&\n\x06edited\ \x0e2\x10.LegalHoldStatus:\x07UNKNOWNR\x0flegalHoldStatus\"\xb5\x01\n\
\x18\x0f\x20\x01(\x0b2\x0c.MessageEditH\0R\x06edited\x123\n\x0cconfirmat\ \x05Knock\x12\"\n\thot_knock\x18\x01\x20\x02(\x08:\x05falseR\x08hotKnock\
ion\x18\x10\x20\x01(\x0b2\r.ConfirmationH\0R\x0cconfirmation\x12'\n\x08r\ \x12A\n\x19expects_read_confirmation\x18\x02\x20\x01(\x08:\x05falseR\x17\
eaction\x18\x11\x20\x01(\x0b2\t.ReactionH\0R\x08reaction\x12*\n\tephemer\ expectsReadConfirmation\x12E\n\x11legal_hold_status\x18\x03\x20\x01(\x0e\
al\x18\x12\x20\x01(\x0b2\n.EphemeralH\0R\tephemeral\x123\n\x0cavailabili\ 2\x10.LegalHoldStatus:\x07UNKNOWNR\x0flegalHoldStatus\"\x8f\x02\n\x0bLin\
ty\x18\x13\x20\x01(\x0b2\r.AvailabilityH\0R\x0cavailabilityB\t\n\x07cont\ kPreview\x12\x10\n\x03url\x18\x01\x20\x02(\tR\x03url\x12\x1d\n\nurl_offs\
ent\"k\n\x0cAvailability\x12&\n\x04type\x18\x01\x20\x02(\x0e2\x12.Availa\ et\x18\x02\x20\x02(\x05R\turlOffset\x12$\n\x07article\x18\x03\x20\x01(\
bility.TypeR\x04type\"3\n\x04Type\x12\x08\n\x04NONE\x10\0\x12\r\n\tAVAIL\ \x0b2\x08.ArticleH\0R\x07article\x12#\n\rpermanent_url\x18\x05\x20\x01(\
ABLE\x10\x01\x12\x08\n\x04AWAY\x10\x02\x12\x08\n\x04BUSY\x10\x03\"\xf1\ \tR\x0cpermanentUrl\x12\x14\n\x05title\x18\x06\x20\x01(\tR\x05title\x12\
\x01\n\tEphemeral\x12.\n\x13expire_after_millis\x18\x01\x20\x02(\x03R\ \x18\n\x07summary\x18\x07\x20\x01(\tR\x07summary\x12\x1c\n\x05image\x18\
\x11expireAfterMillis\x12\x1b\n\x04text\x18\x02\x20\x01(\x0b2\x05.TextH\ \x08\x20\x01(\x0b2\x06.AssetR\x05image\x12\x1e\n\x05tweet\x18\t\x20\x01(\
\0R\x04text\x12#\n\x05image\x18\x03\x20\x01(\x0b2\x0b.ImageAssetH\0R\x05\ \x0b2\x06.TweetH\x01R\x05tweetB\t\n\x07previewB\x0b\n\tmeta_data\";\n\
image\x12\x1e\n\x05knock\x18\x04\x20\x01(\x0b2\x06.KnockH\0R\x05knock\ \x05Tweet\x12\x16\n\x06author\x18\x01\x20\x01(\tR\x06author\x12\x1a\n\
\x12\x1e\n\x05asset\x18\x05\x20\x01(\x0b2\x06.AssetH\0R\x05asset\x12'\n\ \x08username\x18\x02\x20\x01(\tR\x08username\"|\n\x07Article\x12#\n\rper\
\x08location\x18\x06\x20\x01(\x0b2\t.LocationH\0R\x08locationB\t\n\x07co\ manent_url\x18\x01\x20\x02(\tR\x0cpermanentUrl\x12\x14\n\x05title\x18\
ntent\"\x9f\x02\n\x04Text\x12\x18\n\x07content\x18\x01\x20\x02(\tR\x07co\ \x02\x20\x01(\tR\x05title\x12\x18\n\x07summary\x18\x03\x20\x01(\tR\x07su\
ntent\x12/\n\x0clink_preview\x18\x03\x20\x03(\x0b2\x0c.LinkPreviewR\x0bl\ mmary\x12\x1c\n\x05image\x18\x04\x20\x01(\x0b2\x06.AssetR\x05image\"b\n\
inkPreview\x12$\n\x08mentions\x18\x04\x20\x03(\x0b2\x08.MentionR\x08ment\ \x07Mention\x12\x14\n\x05start\x18\x01\x20\x02(\x05R\x05start\x12\x16\n\
ions\x12\x1c\n\x05quote\x18\x05\x20\x01(\x0b2\x06.QuoteR\x05quote\x12A\n\ \x06length\x18\x02\x20\x02(\x05R\x06length\x12\x19\n\x07user_id\x18\x03\
\x19expects_read_confirmation\x18\x06\x20\x01(\x08:\x05falseR\x17expects\ \x20\x01(\tH\0R\x06userIdB\x0e\n\x0cmention_type\"c\n\x08LastRead\x12'\n\
ReadConfirmation\x12E\n\x11legal_hold_status\x18\x07\x20\x01(\x0e2\x10.L\ \x0fconversation_id\x18\x01\x20\x02(\tR\x0econversationId\x12.\n\x13last\
egalHoldStatus:\x07UNKNOWNR\x0flegalHoldStatus\"\xb5\x01\n\x05Knock\x12\ _read_timestamp\x18\x02\x20\x02(\x03R\x11lastReadTimestamp\"_\n\x07Clear\
\"\n\thot_knock\x18\x01\x20\x02(\x08:\x05falseR\x08hotKnock\x12A\n\x19ex\ ed\x12'\n\x0fconversation_id\x18\x01\x20\x02(\tR\x0econversationId\x12+\
pects_read_confirmation\x18\x02\x20\x01(\x08:\x05falseR\x17expectsReadCo\ \n\x11cleared_timestamp\x18\x02\x20\x02(\x03R\x10clearedTimestamp\"U\n\
nfirmation\x12E\n\x11legal_hold_status\x18\x03\x20\x01(\x0e2\x10.LegalHo\ \x0bMessageHide\x12'\n\x0fconversation_id\x18\x01\x20\x02(\tR\x0econvers\
ldStatus:\x07UNKNOWNR\x0flegalHoldStatus\"\x8f\x02\n\x0bLinkPreview\x12\ ationId\x12\x1d\n\nmessage_id\x18\x02\x20\x02(\tR\tmessageId\".\n\rMessa\
\x10\n\x03url\x18\x01\x20\x02(\tR\x03url\x12\x1d\n\nurl_offset\x18\x02\ geDelete\x12\x1d\n\nmessage_id\x18\x01\x20\x02(\tR\tmessageId\"g\n\x0bMe\
\x20\x02(\x05R\turlOffset\x12$\n\x07article\x18\x03\x20\x01(\x0b2\x08.Ar\ ssageEdit\x120\n\x14replacing_message_id\x18\x01\x20\x02(\tR\x12replacin\
ticleH\0R\x07article\x12#\n\rpermanent_url\x18\x05\x20\x01(\tR\x0cperman\ gMessageId\x12\x1b\n\x04text\x18\x02\x20\x01(\x0b2\x05.TextH\0R\x04textB\
entUrl\x12\x14\n\x05title\x18\x06\x20\x01(\tR\x05title\x12\x18\n\x07summ\ \t\n\x07content\"g\n\x05Quote\x12*\n\x11quoted_message_id\x18\x01\x20\
ary\x18\x07\x20\x01(\tR\x07summary\x12\x1c\n\x05image\x18\x08\x20\x01(\ \x02(\tR\x0fquotedMessageId\x122\n\x15quoted_message_sha256\x18\x02\x20\
\x0b2\x06.AssetR\x05image\x12\x1e\n\x05tweet\x18\t\x20\x01(\x0b2\x06.Twe\ \x01(\x0cR\x13quotedMessageSha256\"\xab\x01\n\x0cConfirmation\x12&\n\x04\
etH\x01R\x05tweetB\t\n\x07previewB\x0b\n\tmeta_data\";\n\x05Tweet\x12\ type\x18\x02\x20\x02(\x0e2\x12.Confirmation.TypeR\x04type\x12(\n\x10firs\
\x16\n\x06author\x18\x01\x20\x01(\tR\x06author\x12\x1a\n\x08username\x18\ t_message_id\x18\x01\x20\x02(\tR\x0efirstMessageId\x12(\n\x10more_messag\
\x02\x20\x01(\tR\x08username\"|\n\x07Article\x12#\n\rpermanent_url\x18\ e_ids\x18\x03\x20\x03(\tR\x0emoreMessageIds\"\x1f\n\x04Type\x12\r\n\tDEL\
\x01\x20\x02(\tR\x0cpermanentUrl\x12\x14\n\x05title\x18\x02\x20\x01(\tR\ IVERED\x10\0\x12\x08\n\x04READ\x10\x01\"\xf6\x01\n\x08Location\x12\x1c\n\
\x05title\x12\x18\n\x07summary\x18\x03\x20\x01(\tR\x07summary\x12\x1c\n\ \tlongitude\x18\x01\x20\x02(\x02R\tlongitude\x12\x1a\n\x08latitude\x18\
\x05image\x18\x04\x20\x01(\x0b2\x06.AssetR\x05image\"b\n\x07Mention\x12\ \x02\x20\x02(\x02R\x08latitude\x12\x12\n\x04name\x18\x03\x20\x01(\tR\x04\
\x14\n\x05start\x18\x01\x20\x02(\x05R\x05start\x12\x16\n\x06length\x18\ name\x12\x12\n\x04zoom\x18\x04\x20\x01(\x05R\x04zoom\x12A\n\x19expects_r\
\x02\x20\x02(\x05R\x06length\x12\x19\n\x07user_id\x18\x03\x20\x01(\tH\0R\ ead_confirmation\x18\x05\x20\x01(\x08:\x05falseR\x17expectsReadConfirmat\
\x06userIdB\x0e\n\x0cmention_type\"c\n\x08LastRead\x12'\n\x0fconversatio\ ion\x12E\n\x11legal_hold_status\x18\x06\x20\x01(\x0e2\x10.LegalHoldStatu\
n_id\x18\x01\x20\x02(\tR\x0econversationId\x12.\n\x13last_read_timestamp\ s:\x07UNKNOWNR\x0flegalHoldStatus\"\xa9\x02\n\nImageAsset\x12\x10\n\x03t\
\x18\x02\x20\x02(\x03R\x11lastReadTimestamp\"_\n\x07Cleared\x12'\n\x0fco\ ag\x18\x01\x20\x02(\tR\x03tag\x12\x14\n\x05width\x18\x02\x20\x02(\x05R\
nversation_id\x18\x01\x20\x02(\tR\x0econversationId\x12+\n\x11cleared_ti\ \x05width\x12\x16\n\x06height\x18\x03\x20\x02(\x05R\x06height\x12%\n\x0e\
mestamp\x18\x02\x20\x02(\x03R\x10clearedTimestamp\"U\n\x0bMessageHide\ original_width\x18\x04\x20\x02(\x05R\roriginalWidth\x12'\n\x0foriginal_h\
\x12'\n\x0fconversation_id\x18\x01\x20\x02(\tR\x0econversationId\x12\x1d\ eight\x18\x05\x20\x02(\x05R\x0eoriginalHeight\x12\x1b\n\tmime_type\x18\
\n\nmessage_id\x18\x02\x20\x02(\tR\tmessageId\".\n\rMessageDelete\x12\ \x06\x20\x02(\tR\x08mimeType\x12\x12\n\x04size\x18\x07\x20\x02(\x05R\x04\
\x1d\n\nmessage_id\x18\x01\x20\x02(\tR\tmessageId\"g\n\x0bMessageEdit\ size\x12\x17\n\x07otr_key\x18\x08\x20\x01(\x0cR\x06otrKey\x12\x17\n\x07m\
\x120\n\x14replacing_message_id\x18\x01\x20\x02(\tR\x12replacingMessageI\ ac_key\x18\t\x20\x01(\x0cR\x06macKey\x12\x10\n\x03mac\x18\n\x20\x01(\x0c\
d\x12\x1b\n\x04text\x18\x02\x20\x01(\x0b2\x05.TextH\0R\x04textB\t\n\x07c\ R\x03mac\x12\x16\n\x06sha256\x18\x0b\x20\x01(\x0cR\x06sha256\"\xa4\n\n\
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\
\x05Asset\x12+\n\x08original\x18\x01\x20\x01(\x0b2\x0f.Asset.OriginalR\ \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\ \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.\ ploadedH\0R\x0bnotUploaded\x12/\n\x08uploaded\x18\x04\x20\x01(\x0b2\x11.\

103
src/net/wire_api/auth.rs Normal file
View File

@@ -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<HttpsConnector<HttpConnector>>,
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<AuthResponse, ApiError> {
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)
}
}

View File

@@ -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<bool>,
conversations: Option<Vec<Conversation>>,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct Conversation {
access: Option<Access>,
creator: Option<String>,
access_role: Option<String>,
members: Option<ConversationMembers>,
name: Option<String>,
team: Option<String>,
id: Option<String>,
r#type: Option<u32>,
receipt_mode: Option<u32>,
last_event_time: String,
message_timer: Option<u32>,
last_event: Option<String>,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct Access {
#[serde(rename = "0")]
_0: Option<String>,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct ConversationMembers {
#[serde(rename = "self")]
self_: Option<Member>,
others: Option<Vec<OtherMember>>,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct Member {
hidden_ref: Option<String>,
stauts: Option<u32>,
service: Option<ServiceRef>,
otr_muted_ref: Option<String>,
conversation_role: Option<String>,
status_time: Option<String>,
hidden: Option<bool>,
status_ref: Option<String>,
id: Option<String>,
otr_archived: Option<bool>,
otr_muted_status: Option<String>,
otr_muted: Option<bool>,
otr_archived_ref: Option<String>,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct OtherMember {
status: Option<u32>,
conversation_role: Option<String>,
id: Option<String>,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct ServiceRef {
id: String,
provider: String,
}
impl WireClient {
pub async fn fetch_conversations(
&mut self,
auth_response: &AuthResponse,
) -> Result<Conversations, ApiError> {
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)
}
}

View File

@@ -0,0 +1,5 @@
#[derive(Debug)]
pub enum ApiError {
JsonParseError(Box<dyn std::error::Error>),
HttpError(hyper::error::Error),
}

3
src/net/wire_api/mod.rs Normal file
View File

@@ -0,0 +1,3 @@
pub mod auth;
pub mod conversations;
pub mod error;