From d050866cceefb3fa3b63c7b6231009695c31804b Mon Sep 17 00:00:00 2001 From: nazeh Date: Sun, 28 Jul 2024 23:24:32 +0300 Subject: [PATCH] feat(pubky): auth working everywhere except nodejs --- Cargo.lock | 21 +++++- pubky-homeserver/Cargo.toml | 2 +- pubky-homeserver/src/routes.rs | 6 +- pubky-homeserver/src/routes/auth.rs | 29 ++++++-- pubky/pkg/test/auth.js | 40 ++++++----- pubky/src/error.rs | 6 +- pubky/src/native.rs | 61 ++++++++++++++--- pubky/src/native/pkarr.rs | 92 -------------------------- pubky/src/native/public.rs | 7 +- pubky/src/{native => shared}/auth.rs | 59 ++++++++++------- pubky/src/{shared.rs => shared/mod.rs} | 1 + pubky/src/shared/pkarr.rs | 70 +++++++++++++++++++- pubky/src/wasm.rs | 58 ++++++++++++++-- pubky/src/wasm/auth.rs | 68 ------------------- pubky/src/wasm/keys.rs | 2 +- pubky/src/wasm/pkarr.rs | 11 ++- pubky/src/wasm/session.rs | 6 ++ 17 files changed, 291 insertions(+), 248 deletions(-) delete mode 100644 pubky/src/native/pkarr.rs rename pubky/src/{native => shared}/auth.rs (63%) rename pubky/src/{shared.rs => shared/mod.rs} (51%) delete mode 100644 pubky/src/wasm/auth.rs create mode 100644 pubky/src/wasm/session.rs diff --git a/Cargo.lock b/Cargo.lock index ed8e5db..dbeea1b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -133,6 +133,7 @@ checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf" dependencies = [ "async-trait", "axum-core", + "axum-macros", "bytes", "futures-util", "http", @@ -205,6 +206,18 @@ dependencies = [ "tracing", ] +[[package]] +name = "axum-macros" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00c055ee2d014ae5981ce1016374e8213682aa14d9bf40e48ab48b5f3ef20eaa" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "backtrace" version = "0.3.73" @@ -348,7 +361,7 @@ version = "4.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d029b67f89d30bbb547c89fd5161293c0aec155fc691d7924b64550662db93e" dependencies = [ - "heck", + "heck 0.5.0", "proc-macro2", "quote", "syn", @@ -884,6 +897,12 @@ dependencies = [ "stable_deref_trait", ] +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + [[package]] name = "heck" version = "0.5.0" diff --git a/pubky-homeserver/Cargo.toml b/pubky-homeserver/Cargo.toml index 698a3e6..eaba493 100644 --- a/pubky-homeserver/Cargo.toml +++ b/pubky-homeserver/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" [dependencies] anyhow = "1.0.82" -axum = "0.7.5" +axum = { version = "0.7.5", features = ["macros"] } axum-extra = { version = "0.9.3", features = ["typed-header", "async-read-body"] } base32 = "0.5.1" bytes = "1.6.1" diff --git a/pubky-homeserver/src/routes.rs b/pubky-homeserver/src/routes.rs index 3f53d9b..0d3b7e3 100644 --- a/pubky-homeserver/src/routes.rs +++ b/pubky-homeserver/src/routes.rs @@ -41,10 +41,6 @@ pub fn create_app(state: AppState) -> Router { base(state.clone()) // TODO: Only enable this for test environments? .nest("/pkarr", pkarr_router(state)) - .layer( - CorsLayer::new() - .allow_methods([Method::GET, Method::PUT, Method::POST, Method::DELETE]) - .allow_origin(cors::Any), - ) + .layer(CorsLayer::very_permissive()) .layer(TraceLayer::new_for_http()) } diff --git a/pubky-homeserver/src/routes/auth.rs b/pubky-homeserver/src/routes/auth.rs index c38aa38..60761fb 100644 --- a/pubky-homeserver/src/routes/auth.rs +++ b/pubky-homeserver/src/routes/auth.rs @@ -1,6 +1,7 @@ use axum::{ + debug_handler, extract::{Request, State}, - http::{HeaderMap, StatusCode}, + http::{uri::Scheme, HeaderMap, StatusCode, Uri}, response::IntoResponse, Router, }; @@ -8,7 +9,7 @@ use axum_extra::{headers::UserAgent, TypedHeader}; use bytes::Bytes; use heed::BytesEncode; use postcard::to_allocvec; -use tower_cookies::{Cookie, Cookies}; +use tower_cookies::{cookie::SameSite, Cookie, Cookies}; use pubky_common::{ crypto::{random_bytes, random_hash}, @@ -26,16 +27,26 @@ use crate::{ server::AppState, }; +#[debug_handler] pub async fn signup( State(state): State, TypedHeader(user_agent): TypedHeader, cookies: Cookies, pubky: Pubky, + uri: Uri, body: Bytes, ) -> Result { // TODO: Verify invitation link. // TODO: add errors in case of already axisting user. - signin(State(state), TypedHeader(user_agent), cookies, pubky, body).await + signin( + State(state), + TypedHeader(user_agent), + cookies, + pubky, + uri, + body, + ) + .await } pub async fn session( @@ -57,6 +68,7 @@ pub async fn session( let session = session.to_owned(); rtxn.commit()?; + // TODO: add content-type return Ok(session); }; @@ -95,6 +107,7 @@ pub async fn signin( TypedHeader(user_agent): TypedHeader, cookies: Cookies, pubky: Pubky, + uri: Uri, body: Bytes, ) -> Result { let public_key = pubky.public_key(); @@ -135,7 +148,15 @@ pub async fn signin( sessions.put(&mut wtxn, &session_secret, &session.serialize())?; - cookies.add(Cookie::new(public_key.to_string(), session_secret)); + let mut cookie = Cookie::new(public_key.to_string(), session_secret); + cookie.set_path("/"); + if *uri.scheme().unwrap_or(&Scheme::HTTP) == Scheme::HTTPS { + cookie.set_secure(true); + cookie.set_same_site(SameSite::None); + } + cookie.set_http_only(true); + + cookies.add(cookie); wtxn.commit()?; diff --git a/pubky/pkg/test/auth.js b/pubky/pkg/test/auth.js index fd17015..a660d99 100644 --- a/pubky/pkg/test/auth.js +++ b/pubky/pkg/test/auth.js @@ -3,30 +3,28 @@ import test from 'tape' import { PubkyClient, Keypair, PublicKey } from '../index.js' test('seed auth', async (t) => { + const client = new PubkyClient() - let client = new PubkyClient(); + const keypair = Keypair.random() + const publicKey = keypair.public_key() - let keypair = Keypair.random(); + const homeserver = PublicKey.try_from('8pinxxgqs41n4aididenw5apqp1urfmzdztr8jt4abrkdn435ewo') + await client.signup(keypair, homeserver) - let homeserver = PublicKey.try_from("8pinxxgqs41n4aididenw5apqp1urfmzdztr8jt4abrkdn435ewo"); - await client.signup(keypair, homeserver); + const session = await client.session(publicKey) + t.ok(session) - t.ok(true); + { + await client.signout(publicKey) - // const session = await client.session() - // t.ok(session) - // - // { - // await client.logout(userId) - // - // const session = await client.session() - // t.absent(session?.users?.[userId]) - // } - // - // { - // await client.login(seed) - // - // const session = await client.session() - // t.ok(session?.users[userId]) - // } + const session = await client.session(publicKey) + t.notOk(session) + } + + { + await client.signin(keypair) + + const session = await client.session(publicKey) + t.ok(session) + } }) diff --git a/pubky/src/error.rs b/pubky/src/error.rs index e885f32..501168d 100644 --- a/pubky/src/error.rs +++ b/pubky/src/error.rs @@ -12,9 +12,6 @@ pub enum Error { #[error("Generic error: {0}")] Generic(String), - #[error("Not signed in")] - NotSignedIn, - // === Transparent === #[error(transparent)] Dns(#[from] SimpleDnsError), @@ -29,7 +26,6 @@ pub enum Error { Reqwest(#[from] reqwest::Error), #[error(transparent)] - #[cfg(not(target_arch = "wasm32"))] Session(#[from] pubky_common::session::Error), #[error("Could not resolve endpoint for {0}")] @@ -37,7 +33,7 @@ pub enum Error { } #[cfg(target_arch = "wasm32")] -use wasm_bindgen::{prelude::wasm_bindgen, JsValue}; +use wasm_bindgen::JsValue; #[cfg(target_arch = "wasm32")] impl From for JsValue { diff --git a/pubky/src/native.rs b/pubky/src/native.rs index 90a1930..fa2ae3f 100644 --- a/pubky/src/native.rs +++ b/pubky/src/native.rs @@ -1,22 +1,31 @@ -pub mod auth; -pub mod pkarr; pub mod public; use std::time::Duration; use ::pkarr::{ mainline::dht::{DhtSettings, Testnet}, - PkarrClient, PkarrClientAsync, Settings, + PkarrClient, PublicKey, Settings, SignedPacket, }; +use pkarr::Keypair; +use pubky_common::session::Session; +use reqwest::{Method, RequestBuilder}; +use url::Url; -use crate::PubkyClient; +use crate::{error::Result, PubkyClient}; static DEFAULT_USER_AGENT: &str = concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION"),); +impl Default for PubkyClient { + fn default() -> Self { + Self::new() + } +} + impl PubkyClient { pub fn new() -> Self { Self { http: reqwest::Client::builder() + .cookie_store(true) .user_agent(DEFAULT_USER_AGENT) .build() .unwrap(), @@ -25,7 +34,6 @@ impl PubkyClient { } } - #[cfg(not(target_arch = "wasm32"))] pub fn test(testnet: &Testnet) -> Self { Self { http: reqwest::Client::builder() @@ -45,10 +53,45 @@ impl PubkyClient { .as_async(), } } -} -impl Default for PubkyClient { - fn default() -> Self { - Self::new() + /// Signup to a homeserver and update Pkarr accordingly. + /// + /// The homeserver is a Pkarr domain name, where the TLD is a Pkarr public key + /// for example "pubky.o4dksfbqk85ogzdb5osziw6befigbuxmuxkuxq8434q89uj56uyy" + pub async fn signup(&self, keypair: &Keypair, homeserver: &PublicKey) -> Result<()> { + self.inner_signup(keypair, homeserver).await + } + + /// Check the current sesison for a given Pubky in its homeserver. + /// + /// Returns an [Error::NotSignedIn] if so, or [reqwest::Error] if + /// the response has any other `>=400` status code. + pub async fn session(&self, pubky: &PublicKey) -> Result> { + self.inner_session(pubky).await + } + + /// Signout from a homeserver. + pub async fn signout(&self, pubky: &PublicKey) -> Result<()> { + self.inner_signout(pubky).await + } + + /// Signin to a homeserver. + pub async fn signin(&self, keypair: &Keypair) -> Result<()> { + self.inner_signin(keypair).await + } + + pub(crate) async fn pkarr_resolve( + &self, + public_key: &PublicKey, + ) -> Result> { + Ok(self.pkarr.resolve(public_key).await?) + } + + pub(crate) async fn pkarr_publish(&self, signed_packet: &SignedPacket) -> Result<()> { + Ok(self.pkarr.publish(signed_packet).await?) + } + + pub(crate) fn request(&self, method: reqwest::Method, url: Url) -> RequestBuilder { + self.http.request(method, url) } } diff --git a/pubky/src/native/pkarr.rs b/pubky/src/native/pkarr.rs deleted file mode 100644 index 3f11711..0000000 --- a/pubky/src/native/pkarr.rs +++ /dev/null @@ -1,92 +0,0 @@ -use url::Url; - -use pkarr::{ - dns::{rdata::SVCB, Packet}, - Keypair, PublicKey, SignedPacket, -}; - -use crate::{ - error::{Error, Result}, - PubkyClient, -}; - -impl PubkyClient { - pub(crate) async fn pkarr_resolve( - &self, - public_key: &PublicKey, - ) -> Result> { - Ok(self.pkarr.resolve(public_key).await?) - } - - pub(crate) async fn pkarr_publish(&self, signed_packet: &SignedPacket) -> Result<()> { - Ok(self.pkarr.publish(signed_packet).await?) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - use pkarr::{ - dns::{rdata::SVCB, Packet}, - mainline::{dht::DhtSettings, Testnet}, - Keypair, PkarrClient, Settings, SignedPacket, - }; - use pubky_homeserver::Homeserver; - - #[tokio::test] - async fn resolve_homeserver() { - let testnet = Testnet::new(3); - let server = Homeserver::start_test(&testnet).await.unwrap(); - - // Publish an intermediate controller of the homeserver - let pkarr_client = PkarrClient::new(Settings { - dht: DhtSettings { - bootstrap: Some(testnet.bootstrap.clone()), - ..Default::default() - }, - ..Default::default() - }) - .unwrap() - .as_async(); - - let intermediate = Keypair::random(); - - let mut packet = Packet::new_reply(0); - - let server_tld = server.public_key().to_string(); - - let mut svcb = SVCB::new(0, server_tld.as_str().try_into().unwrap()); - - packet.answers.push(pkarr::dns::ResourceRecord::new( - "pubky".try_into().unwrap(), - pkarr::dns::CLASS::IN, - 60 * 60, - pkarr::dns::rdata::RData::SVCB(svcb), - )); - - let signed_packet = SignedPacket::from_packet(&intermediate, &packet).unwrap(); - - pkarr_client.publish(&signed_packet).await.unwrap(); - - { - let client = PubkyClient::test(&testnet); - - let pubky = Keypair::random(); - - client - .publish_pubky_homeserver(&pubky, &format!("pubky.{}", &intermediate.public_key())) - .await - .unwrap(); - - let (public_key, url) = client - .resolve_pubky_homeserver(&pubky.public_key()) - .await - .unwrap(); - - assert_eq!(public_key, server.public_key()); - assert_eq!(url.host_str(), Some("localhost")); - assert_eq!(url.port(), Some(server.port())); - } - } -} diff --git a/pubky/src/native/public.rs b/pubky/src/native/public.rs index ce2613e..9b2a271 100644 --- a/pubky/src/native/public.rs +++ b/pubky/src/native/public.rs @@ -50,12 +50,10 @@ fn normalize_path(path: &str) -> String { #[cfg(test)] mod tests { - use std::ops::Deref; use crate::*; use pkarr::{mainline::Testnet, Keypair}; - use pubky_common::session::Session; use pubky_homeserver::Homeserver; #[tokio::test] @@ -69,9 +67,10 @@ mod tests { client.signup(&keypair, &server.public_key()).await.unwrap(); - let response = client + client .put(&keypair.public_key(), "/pub/foo.txt", &[0, 1, 2, 3, 4]) - .await; + .await + .unwrap(); let response = client .get(&keypair.public_key(), "/pub/foo.txt") diff --git a/pubky/src/native/auth.rs b/pubky/src/shared/auth.rs similarity index 63% rename from pubky/src/native/auth.rs rename to pubky/src/shared/auth.rs index 23622ad..e78f84a 100644 --- a/pubky/src/native/auth.rs +++ b/pubky/src/shared/auth.rs @@ -1,4 +1,4 @@ -use reqwest::StatusCode; +use reqwest::{Method, StatusCode}; use pkarr::{Keypair, PublicKey}; use pubky_common::{auth::AuthnSignature, session::Session}; @@ -13,7 +13,11 @@ impl PubkyClient { /// /// The homeserver is a Pkarr domain name, where the TLD is a Pkarr public key /// for example "pubky.o4dksfbqk85ogzdb5osziw6befigbuxmuxkuxq8434q89uj56uyy" - pub async fn signup(&self, keypair: &Keypair, homeserver: &PublicKey) -> Result<()> { + pub(crate) async fn inner_signup( + &self, + keypair: &Keypair, + homeserver: &PublicKey, + ) -> Result<()> { let homeserver = homeserver.to_string(); let (audience, mut url) = self.resolve_endpoint(&homeserver).await?; @@ -24,7 +28,7 @@ impl PubkyClient { .as_bytes() .to_owned(); - self.http.put(url).body(body).send().await?; + self.request(Method::PUT, url).body(body).send().await?; self.publish_pubky_homeserver(keypair, &homeserver).await?; @@ -33,17 +37,17 @@ impl PubkyClient { /// Check the current sesison for a given Pubky in its homeserver. /// - /// Returns an [Error::NotSignedIn] if so, or [reqwest::Error] if - /// the response has any other `>=400` status code. - pub async fn session(&self, pubky: &PublicKey) -> Result { - let (homeserver, mut url) = self.resolve_pubky_homeserver(pubky).await?; + /// Returns None if not signed in, or [reqwest::Error] + /// if the response has any other `>=404` status code. + pub(crate) async fn inner_session(&self, pubky: &PublicKey) -> Result> { + let (_, mut url) = self.resolve_pubky_homeserver(pubky).await?; url.set_path(&format!("/{}/session", pubky)); - let res = self.http.get(url).send().await?; + let res = self.request(Method::GET, url).send().await?; if res.status() == StatusCode::NOT_FOUND { - return Err(Error::NotSignedIn); + return Ok(None); } if !res.status().is_success() { @@ -52,22 +56,22 @@ impl PubkyClient { let bytes = res.bytes().await?; - Ok(Session::deserialize(&bytes)?) + Ok(Some(Session::deserialize(&bytes)?)) } /// Signout from a homeserver. - pub async fn signout(&self, pubky: &PublicKey) -> Result<()> { - let (homeserver, mut url) = self.resolve_pubky_homeserver(pubky).await?; + pub async fn inner_signout(&self, pubky: &PublicKey) -> Result<()> { + let (_, mut url) = self.resolve_pubky_homeserver(pubky).await?; url.set_path(&format!("/{}/session", pubky)); - self.http.delete(url).send().await?; + self.request(Method::DELETE, url).send().await?; Ok(()) } /// Signin to a homeserver. - pub async fn signin(&self, keypair: &Keypair) -> Result<()> { + pub async fn inner_signin(&self, keypair: &Keypair) -> Result<()> { let pubky = keypair.public_key(); let (audience, mut url) = self.resolve_pubky_homeserver(&pubky).await?; @@ -78,7 +82,7 @@ impl PubkyClient { .as_bytes() .to_owned(); - self.http.post(url).body(body).send().await?; + self.request(Method::POST, url).body(body).send().await?; Ok(()) } @@ -86,11 +90,15 @@ impl PubkyClient { #[cfg(test)] mod tests { + + use std::time::Duration; + use crate::*; use pkarr::{mainline::Testnet, Keypair}; use pubky_common::session::Session; use pubky_homeserver::Homeserver; + use tokio::time::sleep; #[tokio::test] async fn basic_authn() { @@ -103,27 +111,30 @@ mod tests { client.signup(&keypair, &server.public_key()).await.unwrap(); - let session = client.session(&keypair.public_key()).await.unwrap(); + let session = client + .session(&keypair.public_key()) + .await + .unwrap() + .unwrap(); assert_eq!(session, Session { ..session.clone() }); client.signout(&keypair.public_key()).await.unwrap(); { - let session = client.session(&keypair.public_key()).await; + let session = client.session(&keypair.public_key()).await.unwrap(); - assert!(session.is_err()); - - match session { - Err(Error::NotSignedIn) => {} - _ => panic!("expected NotSignedInt error"), - } + assert!(session.is_none()); } client.signin(&keypair).await.unwrap(); { - let session = client.session(&keypair.public_key()).await.unwrap(); + let session = client + .session(&keypair.public_key()) + .await + .unwrap() + .unwrap(); assert_eq!(session, Session { ..session.clone() }); } diff --git a/pubky/src/shared.rs b/pubky/src/shared/mod.rs similarity index 51% rename from pubky/src/shared.rs rename to pubky/src/shared/mod.rs index ad39b70..c61bbfe 100644 --- a/pubky/src/shared.rs +++ b/pubky/src/shared/mod.rs @@ -1 +1,2 @@ +pub mod auth; pub mod pkarr; diff --git a/pubky/src/shared/pkarr.rs b/pubky/src/shared/pkarr.rs index d06b25c..879e901 100644 --- a/pubky/src/shared/pkarr.rs +++ b/pubky/src/shared/pkarr.rs @@ -77,7 +77,7 @@ impl PubkyClient { let response = self .pkarr_resolve(&public_key) .await - .map_err(|e| Error::ResolveEndpoint(original_target.into()))?; + .map_err(|_| Error::ResolveEndpoint(original_target.into()))?; let mut prior = None; @@ -132,3 +132,71 @@ impl PubkyClient { Err(Error::ResolveEndpoint(original_target.into())) } } + +#[cfg(test)] +mod tests { + use super::*; + + use pkarr::{ + dns::{rdata::SVCB, Packet}, + mainline::{dht::DhtSettings, Testnet}, + Keypair, PkarrClient, Settings, SignedPacket, + }; + use pubky_homeserver::Homeserver; + + #[tokio::test] + async fn resolve_homeserver() { + let testnet = Testnet::new(3); + let server = Homeserver::start_test(&testnet).await.unwrap(); + + // Publish an intermediate controller of the homeserver + let pkarr_client = PkarrClient::new(Settings { + dht: DhtSettings { + bootstrap: Some(testnet.bootstrap.clone()), + ..Default::default() + }, + ..Default::default() + }) + .unwrap() + .as_async(); + + let intermediate = Keypair::random(); + + let mut packet = Packet::new_reply(0); + + let server_tld = server.public_key().to_string(); + + let mut svcb = SVCB::new(0, server_tld.as_str().try_into().unwrap()); + + packet.answers.push(pkarr::dns::ResourceRecord::new( + "pubky".try_into().unwrap(), + pkarr::dns::CLASS::IN, + 60 * 60, + pkarr::dns::rdata::RData::SVCB(svcb), + )); + + let signed_packet = SignedPacket::from_packet(&intermediate, &packet).unwrap(); + + pkarr_client.publish(&signed_packet).await.unwrap(); + + { + let client = PubkyClient::test(&testnet); + + let pubky = Keypair::random(); + + client + .publish_pubky_homeserver(&pubky, &format!("pubky.{}", &intermediate.public_key())) + .await + .unwrap(); + + let (public_key, url) = client + .resolve_pubky_homeserver(&pubky.public_key()) + .await + .unwrap(); + + assert_eq!(public_key, server.public_key()); + assert_eq!(url.host_str(), Some("localhost")); + assert_eq!(url.port(), Some(server.port())); + } + } +} diff --git a/pubky/src/wasm.rs b/pubky/src/wasm.rs index 554a4e8..01fcf73 100644 --- a/pubky/src/wasm.rs +++ b/pubky/src/wasm.rs @@ -1,18 +1,66 @@ use wasm_bindgen::prelude::*; -pub mod auth; -pub mod keys; -pub mod pkarr; +use reqwest::{Method, RequestBuilder}; +use url::Url; use crate::PubkyClient; +mod keys; +mod pkarr; +mod session; + +use keys::{Keypair, PublicKey}; +use session::Session; + #[wasm_bindgen] impl PubkyClient { #[wasm_bindgen(constructor)] pub fn new() -> Self { Self { - http: reqwest::Client::new(), - // pkarr: pkarr::PkarrRelayClient::default(), + http: reqwest::Client::builder().build().unwrap(), } } + + /// Signup to a homeserver and update Pkarr accordingly. + /// + /// The homeserver is a Pkarr domain name, where the TLD is a Pkarr public key + /// for example "pubky.o4dksfbqk85ogzdb5osziw6befigbuxmuxkuxq8434q89uj56uyy" + #[wasm_bindgen] + pub async fn signup(&self, keypair: &Keypair, homeserver: &PublicKey) -> Result<(), JsValue> { + self.inner_signup(keypair.as_inner(), homeserver.as_inner()) + .await + .map_err(|e| e.into()) + } + + /// Check the current sesison for a given Pubky in its homeserver. + /// + /// Returns an [Error::NotSignedIn] if so, or [reqwest::Error] if + /// the response has any other `>=400` status code. + #[wasm_bindgen] + pub async fn session(&self, pubky: &PublicKey) -> Result, JsValue> { + self.inner_session(pubky.as_inner()) + .await + .map(|s| s.map(|s| Session(s).into())) + .map_err(|e| e.into()) + } + + /// Signout from a homeserver. + #[wasm_bindgen] + pub async fn signout(&self, pubky: &PublicKey) -> Result<(), JsValue> { + self.inner_signout(pubky.as_inner()) + .await + .map_err(|e| e.into()) + } + + /// Signin to a homeserver. + #[wasm_bindgen] + pub async fn signin(&self, keypair: &Keypair) -> Result<(), JsValue> { + self.inner_signin(keypair.as_inner()) + .await + .map_err(|e| e.into()) + } + + pub(crate) fn request(&self, method: Method, url: Url) -> reqwest::RequestBuilder { + self.http.request(method, url).fetch_credentials_include() + } } diff --git a/pubky/src/wasm/auth.rs b/pubky/src/wasm/auth.rs deleted file mode 100644 index f5d60c6..0000000 --- a/pubky/src/wasm/auth.rs +++ /dev/null @@ -1,68 +0,0 @@ -use wasm_bindgen::prelude::*; -use wasm_bindgen_futures::JsFuture; -use web_sys::RequestMode; - -use reqwest::StatusCode; - -use pkarr::PkarrRelayClient; - -use pubky_common::{auth::AuthnSignature, session::Session}; - -use crate::Error; - -use super::{ - keys::{Keypair, PublicKey}, - PubkyClient, -}; - -#[wasm_bindgen] -impl PubkyClient { - /// Signup to a homeserver and update Pkarr accordingly. - /// - /// The homeserver is a Pkarr domain name, where the TLD is a Pkarr public key - /// for example "pubky.o4dksfbqk85ogzdb5osziw6befigbuxmuxkuxq8434q89uj56uyy" - #[wasm_bindgen] - pub async fn signup(&self, keypair: &Keypair, homeserver: &PublicKey) -> Result<(), JsValue> { - let keypair = keypair.as_inner(); - let homeserver = homeserver.as_inner().to_string(); - - let (audience, mut url) = self.resolve_endpoint(&homeserver).await?; - - url.set_path(&format!("/{}", keypair.public_key())); - - let body = AuthnSignature::generate(keypair, &audience) - .as_bytes() - .to_owned(); - - self.http.put(url).body(body).send().await?; - - self.publish_pubky_homeserver(keypair, &homeserver).await?; - - Ok(()) - } - - /// Check the current sesison for a given Pubky in its homeserver. - /// - /// Returns an [Error::NotSignedIn] if so, or [reqwest::Error] if - /// the response has any other `>=400` status code. - #[wasm_bindgen] - pub async fn session(&self, pubky: &PublicKey) -> Result { - let (homeserver, mut url) = self.resolve_pubky_homeserver(pubky).await?; - - url.set_path(&format!("/{}/session", pubky)); - - let res = self.http.get(url).send().await?; - - if res.status() == StatusCode::NOT_FOUND { - return Err(Error::NotSignedIn); - } - - if !res.status().is_success() { - res.error_for_status_ref()?; - }; - - let bytes = res.bytes().await?; - - Ok(Session::deserialize(&bytes)?) - } -} diff --git a/pubky/src/wasm/keys.rs b/pubky/src/wasm/keys.rs index f54f7cb..cbd6ec7 100644 --- a/pubky/src/wasm/keys.rs +++ b/pubky/src/wasm/keys.rs @@ -9,7 +9,7 @@ pub struct Keypair(pkarr::Keypair); impl Keypair { #[wasm_bindgen] /// Generate a random [Keypair] - pub fn random(secret_key: js_sys::Uint8Array) -> Self { + pub fn random() -> Self { Self(pkarr::Keypair::random()) } diff --git a/pubky/src/wasm/pkarr.rs b/pubky/src/wasm/pkarr.rs index 91b85c2..8b43299 100644 --- a/pubky/src/wasm/pkarr.rs +++ b/pubky/src/wasm/pkarr.rs @@ -1,17 +1,14 @@ use reqwest::StatusCode; -use url::Url; -use wasm_bindgen::prelude::*; -pub use pkarr::{ - dns::{rdata::SVCB, Packet}, - Keypair, PublicKey, SignedPacket, -}; +pub use pkarr::{PublicKey, SignedPacket}; -use crate::error::{Error, Result}; +use crate::error::Result; use crate::PubkyClient; const TEST_RELAY: &str = "http://localhost:15411/pkarr"; +// TODO: Add an in memory cache of packets + impl PubkyClient { //TODO: Allow multiple relays in parallel //TODO: migrate to pkarr::PkarrRelayClient diff --git a/pubky/src/wasm/session.rs b/pubky/src/wasm/session.rs new file mode 100644 index 0000000..ec2e8ca --- /dev/null +++ b/pubky/src/wasm/session.rs @@ -0,0 +1,6 @@ +use pubky_common::session; + +use wasm_bindgen::prelude::*; + +#[wasm_bindgen] +pub struct Session(pub(crate) session::Session);