diff --git a/rust/Cargo.toml b/rust/Cargo.toml index ca09fdd..1e1aa4c 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -8,6 +8,10 @@ edition = "2021" crate_type = ["cdylib", "staticlib"] name = "pubkymobile" +[[bin]] +name = "testing" +path = "testing/main.rs" + [net] git-fetch-with-cli = true diff --git a/rust/pubky/pubky-homeserver/src/config.toml b/rust/pubky/pubky-homeserver/src/config.toml index 2012efc..cb65622 100644 --- a/rust/pubky/pubky-homeserver/src/config.toml +++ b/rust/pubky/pubky-homeserver/src/config.toml @@ -1,5 +1,5 @@ # Use testnet network (local DHT) for testing. -testnet = false +testnet = true # Secret key (in hex) to generate the Homeserver's Keypair secret_key = "0000000000000000000000000000000000000000000000000000000000000000" # Domain to be published in Pkarr records for this server to be accessible by. diff --git a/rust/testing/main.rs b/rust/testing/main.rs new file mode 100644 index 0000000..0b8e1cf --- /dev/null +++ b/rust/testing/main.rs @@ -0,0 +1,184 @@ +use std::string::ToString; +use std::sync::Arc; +use once_cell::sync::Lazy; +use pkarr::{dns, Keypair, PublicKey, SignedPacket}; +use pkarr::dns::rdata::RData; +use pkarr::mainline::Testnet; +use pubky::PubkyClient; +use url::Url; + +static PUBKY_CLIENT: Lazy> = Lazy::new(|| { + // let custom_testnet = Testnet { + // bootstrap: vec!["http://localhost:6287".to_string()], + // nodes: vec![], + // }; + // + // let client = PubkyClient::builder() + // .testnet(&custom_testnet) + // .build(); + let client = PubkyClient::testnet(); + + Arc::new(client) +}); + +// static PUBKY_CLIENT: Lazy> = Lazy::new(|| { +// let custom_bootstrap = vec!["localhost:64630".to_string()]; +// +// let mut pkarr_settings = Settings::default(); +// pkarr_settings.dht.bootstrap = custom_bootstrap.clone().into(); +// pkarr_settings.resolvers = custom_bootstrap +// .iter() +// .flat_map(|resolver| resolver.to_socket_addrs()) +// .flatten() +// .collect::>() +// .into(); +// +// let client = PubkyClient::builder() +// .pkarr_settings(pkarr_settings) +// .build(); +// +// Arc::new(client) +// }); + +const HOMESERVER: &str = "pubky://8pinxxgqs41n4aididenw5apqp1urfmzdztr8jt4abrkdn435ewo"; +const SECRET_KEY: &str = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"; + +#[tokio::main] +async fn main() { + let sign_in_res = signin_or_signup(SECRET_KEY, HOMESERVER).await; + println!("{:?}", sign_in_res); + // let res = publish("recordname".to_string(), "recordcontent".to_string(), "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855".to_string()).await; + // println!("{:?}", res); + let url = "pubky://z4e8s17cou9qmuwen8p1556jzhf1wktmzo6ijsfnri9c4hnrdfty/pub/mydomain.com"; + let putRes = put(url.to_string(), "content".to_string()).await; + println!("{:?}", putRes); +} + +pub async fn signin_or_signup(secret_key: &str, homeserver: &str) -> Vec { + let sign_in_res = sign_in(secret_key).await; + if sign_in_res[0] == "success" { + return sign_in_res; + } + let sign_up_res = sign_up(secret_key, homeserver).await; + sign_up_res +} + +pub async fn sign_up(secret_key: &str, homeserver: &str) -> Vec { + let client = PUBKY_CLIENT.clone(); + let keypair = match get_keypair_from_secret_key(&secret_key) { + Ok(keypair) => keypair, + Err(error) => return create_response_vector(true, error), + }; + + let homeserver_public_key = match PublicKey::try_from(homeserver) { + Ok(key) => key, + Err(error) => return create_response_vector(true, format!("Invalid homeserver public key: {}", error)), + }; + + match client.signup(&keypair, &homeserver_public_key).await { + Ok(session) => create_response_vector(false, session.pubky().to_uri_string()), + Err(error) => create_response_vector(true, format!("signup failure: {}", error)), + } +} + +pub async fn sign_in(secret_key: &str) -> Vec { + let client = PUBKY_CLIENT.clone(); + let keypair = match get_keypair_from_secret_key(&secret_key) { + Ok(keypair) => keypair, + Err(error) => return create_response_vector(true, error), + }; + match client.signin(&keypair).await { + Ok(session) => { + create_response_vector(false, session.pubky().to_uri_string()) + }, + Err(error) => { + create_response_vector(true, format!("Failed to sign in: {}", error)) + } + } +} + +pub async fn publish(record_name: String, record_content: String, secret_key: String) -> Vec { + let client = PUBKY_CLIENT.clone(); + + let keypair = match get_keypair_from_secret_key(&secret_key) { + Ok(keypair) => keypair, + Err(error) => return create_response_vector(true, error), + }; + + let mut packet = dns::Packet::new_reply(0); + + let dns_name = match dns::Name::new(&record_name) { + Ok(name) => name, + Err(e) => return create_response_vector(true, format!("Failed to create DNS name: {}", e)), + }; + + let record_content_str: &str = record_content.as_str(); + + let txt_record = match record_content_str.try_into() { + Ok(value) => RData::TXT(value), + Err(e) => { + return create_response_vector(true, format!("Failed to convert string to TXT record: {}", e)) + } + }; + + packet.answers.push(dns::ResourceRecord::new( + dns_name, + dns::CLASS::IN, + 30, + txt_record, + )); + + match SignedPacket::from_packet(&keypair, &packet) { + Ok(signed_packet) => { + match client.pkarr().publish(&signed_packet).await { + Ok(()) => { + create_response_vector(false, keypair.public_key().to_string()) + } + Err(e) => { + create_response_vector(true, format!("Failed to publish: {}", e)) + } + } + } + Err(e) => { + create_response_vector(true, format!("Failed to create signed packet: {}", e)) + } + } +} + +pub fn get_keypair_from_secret_key(secret_key: &str) -> Result { + let bytes = match hex::decode(&secret_key) { + Ok(bytes) => bytes, + Err(_) => return Err("Failed to decode secret key".to_string()) + }; + + let secret_key_bytes: [u8; 32] = match bytes.try_into() { + Ok(secret_key) => secret_key, + Err(_) => { + return Err("Failed to convert secret key to 32-byte array".to_string()); + } + }; + + Ok(Keypair::from_secret_key(&secret_key_bytes)) +} + +pub fn create_response_vector(error: bool, data: String) -> Vec { + if error { + vec!["error".to_string(), data] + } else { + vec!["success".to_string(), data] + } +} + +pub async fn put(url: String, content: String) -> Vec { + let client = PUBKY_CLIENT.clone(); + let parsed_url = match Url::parse(&url) { + Ok(url) => url, + Err(_) => return create_response_vector(true, "Failed to parse URL".to_string()), + }; + match client.put(parsed_url, &content.as_bytes()).await { + Ok(_) => create_response_vector(false, "put success".to_string()), + Err(error) => { + create_response_vector(true, format!("Failed to put: {}", error)) + } + } +}