diff options
Diffstat (limited to 'filamento/src/caps.rs')
-rw-r--r-- | filamento/src/caps.rs | 117 |
1 files changed, 105 insertions, 12 deletions
diff --git a/filamento/src/caps.rs b/filamento/src/caps.rs index a0709eb..49d05ba 100644 --- a/filamento/src/caps.rs +++ b/filamento/src/caps.rs @@ -13,10 +13,41 @@ use stanza::{ use tracing::trace; use crate::{ - disco::{Identity, Info, identity::Category}, - error::{CapsDecodeError, CapsEncodeError, HashNodeConversionError}, + disco::{ + Identity, Info, + identity::{self, Category}, + }, + error::{CapsDecodeError, CapsEncodeError, CapsNodeConversionError, HashNodeConversionError}, }; +pub const CLIENT_URI: &str = "https://bunny.garden/filamento"; + +// <c xmlns="http://jabber.org/protocol/caps" hash="sha-1" ver="mSavc/SLnHm8zazs5RlcbD/iXoc=" node="https://bunny.garden/filamento"/> +pub fn c() -> C { + caps(CLIENT_URI.to_string(), client_info().into()).unwrap() +} + +pub fn caps_node() -> String { + caps_to_node(c()) +} + +pub fn client_info() -> Info { + Info { + node: None, + features: vec![ + "http://jabber.org/protocol/disco#items".to_string(), + "http://jabber.org/protocol/disco#info".to_string(), + "http://jabber.org/protocol/caps".to_string(), + "http://jabber.org/protocol/nick".to_string(), + "http://jabber.org/protocol/nick+notify".to_string(), + ], + identities: vec![Identity { + name: Some("filamento 0.1.0".to_string()), + category: Category::Client(identity::Client::PC), + }], + } +} + pub fn caps(node: String, query: info::Query) -> Result<xep_0115::C, CapsEncodeError> { let mut string = String::new(); @@ -113,7 +144,7 @@ pub fn caps(node: String, query: info::Query) -> Result<xep_0115::C, CapsEncodeE }) } -pub fn caps2(query: info::Query) -> xep_0390::C { +pub fn encode_caps2(query: info::Query) -> String { let mut string = String::new(); // features string @@ -181,6 +212,16 @@ pub fn caps2(query: info::Query) -> xep_0390::C { let extensions_string = extensions.concat(); string.push_str(&extensions_string); string.push('\x1c'); + string +} + +pub fn encode_info_base64(info: info::Query) -> String { + let string = encode_caps2(info); + BASE64_STANDARD.encode(string) +} + +pub fn caps2(query: info::Query) -> xep_0390::C { + let string = encode_caps2(query); let mut sha256 = Sha256::new(); @@ -209,7 +250,7 @@ pub fn caps2(query: info::Query) -> xep_0390::C { } /// takes a base64 encoded cached caps string and converts it into a disco info result -pub fn info(info: String) -> Result<Info, CapsDecodeError> { +pub fn decode_info_base64(info: String) -> Result<Info, CapsDecodeError> { let info = String::from_utf8(BASE64_STANDARD.decode(info)?)?; let mut strings = info.split_terminator('\x1c'); @@ -255,6 +296,22 @@ pub fn info(info: String) -> Result<Info, CapsDecodeError> { }) } +pub fn caps_to_node(caps: C) -> String { + caps.node + "#" + caps.ver.as_str() +} + +pub fn node_to_caps(node: String) -> Result<C, CapsNodeConversionError> { + let (node, ver) = node + .rsplit_once('#') + .ok_or(CapsNodeConversionError::MissingHashtag)?; + Ok(C { + ext: None, + hash: "sha-1".to_string(), + node: node.to_string(), + ver: ver.to_string(), + }) +} + pub fn hash_to_node(hash: xep_0300::Hash) -> String { let mut string = String::from("urn:xmpp:caps#"); string.push_str(&hash.algo.to_string()); @@ -276,12 +333,6 @@ pub fn node_to_hash(node: String) -> Result<Hash, HashNodeConversionError> { }) } -static CLIENT_INFO: Info = Info { - node: None, - features: vec![], - identities: vec![], -}; - #[cfg(test)] mod tests { use peanuts::{Writer, element::IntoElement}; @@ -390,9 +441,51 @@ mod tests { items: Vec::new(), }], }; - let caps = caps("https://macaw.chat".to_string(), info).unwrap(); + let test_caps = caps("https://macaw.chat".to_string(), info).unwrap(); + let stdout = tokio::io::stdout(); + let mut writer = Writer::new(stdout); + writer.write(&test_caps).await.unwrap(); + } + + #[tokio::test] + pub async fn test_gen_client_caps() { let stdout = tokio::io::stdout(); let mut writer = Writer::new(stdout); - writer.write(&caps).await; + // let info = info::Query { + // node: Some("https://bunny.garden/filamento".to_string()), + // features: vec![ + // Feature { + // var: "http://jabber.org/protocol/disco#items".to_string(), + // }, + // Feature { + // var: "http://jabber.org/protocol/disco#info".to_string(), + // }, + // Feature { + // var: "http://jabber.org/protocol/caps".to_string(), + // }, + // Feature { + // var: "http://jabber.org/protocol/nick".to_string(), + // }, + // Feature { + // var: "http://jabber.org/protocol/nick+notify".to_string(), + // }, + // ], + // identities: vec![Identity { + // category: "client".to_string(), + // name: Some("filamento 0.1.0".to_string()), + // r#type: "pc".to_string(), + // lang: None, + // }], + // extensions: vec![], + // }; + let info: info::Query = client_info().into(); + let client_caps = caps(CLIENT_URI.to_string(), info.clone()).unwrap(); + writer.write(&client_caps).await.unwrap(); + let node = caps_to_node(client_caps); + println!("client caps node: `{}`", node); + let client_caps_base64 = encode_info_base64(info); + println!("client caps: `{}`", client_caps_base64); + let client_caps = decode_info_base64(client_caps_base64).unwrap(); + println!("client caps: `{:?}`", client_caps); } } |