From 11279d97ac2f5945a282c6d2bbff6343e76875d5 Mon Sep 17 00:00:00 2001 From: phil Date: Wed, 3 Sep 2025 15:00:57 -0400 Subject: [PATCH] basic token verification works --- Cargo.lock | 276 +++++++++++++++++++++++++++++++++++++----- Cargo.toml | 1 + pocket/Cargo.toml | 19 +++ pocket/src/lib.rs | 5 + pocket/src/main.rs | 9 ++ pocket/src/server.rs | 208 +++++++++++++++++++++++++++++++ pocket/src/token.rs | 72 +++++++++++ quasar/src/storage.rs | 4 + 8 files changed, 561 insertions(+), 33 deletions(-) create mode 100644 pocket/Cargo.toml create mode 100644 pocket/src/lib.rs create mode 100644 pocket/src/main.rs create mode 100644 pocket/src/server.rs create mode 100644 pocket/src/token.rs diff --git a/Cargo.lock b/Cargo.lock index 7fc7650..eaf4675 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -192,7 +192,7 @@ dependencies = [ "nom", "num-traits", "rusticata-macros", - "thiserror 2.0.12", + "thiserror 2.0.16", "time", ] @@ -370,6 +370,19 @@ dependencies = [ "web-time", ] +[[package]] +name = "atrium-crypto" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73a3da430c71dd9006d61072c20771f264e5c498420a49c32305ceab8bd71955" +dependencies = [ + "ecdsa", + "k256", + "multibase", + "p256", + "thiserror 1.0.69", +] + [[package]] name = "atrium-identity" version = "0.1.5" @@ -628,7 +641,7 @@ dependencies = [ "axum", "handlebars", "serde", - "thiserror 2.0.12", + "thiserror 2.0.16", ] [[package]] @@ -773,6 +786,22 @@ dependencies = [ "syn 2.0.103", ] +[[package]] +name = "bitcoin-io" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b47c4ab7a93edb0c7198c5535ed9b52b63095f4e9b45279c6736cec4b856baf" + +[[package]] +name = "bitcoin_hashes" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb18c03d0db0247e147a21a6faafd5a7eb851c743db062de72018b6b7e8e4d16" +dependencies = [ + "bitcoin-io", + "hex-conservative", +] + [[package]] name = "bitflags" version = "2.9.0" @@ -906,6 +935,33 @@ dependencies = [ "windows-link", ] +[[package]] +name = "ciborium" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" + +[[package]] +name = "ciborium-ll" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" +dependencies = [ + "ciborium-io", + "half", +] + [[package]] name = "cid" version = "0.11.1" @@ -1171,6 +1227,12 @@ version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + [[package]] name = "crypto-bigint" version = "0.5.5" @@ -1514,7 +1576,7 @@ dependencies = [ "slog-bunyan", "slog-json", "slog-term", - "thiserror 2.0.12", + "thiserror 2.0.16", "tokio", "tokio-rustls 0.25.0", "toml", @@ -1683,6 +1745,18 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "fallible-iterator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" + +[[package]] +name = "fallible-streaming-iterator" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" + [[package]] name = "fastrand" version = "2.3.0" @@ -1814,7 +1888,7 @@ dependencies = [ "mixtrics", "pin-project", "serde", - "thiserror 2.0.12", + "thiserror 2.0.16", "tokio", "tracing", ] @@ -1834,7 +1908,7 @@ dependencies = [ "parking_lot", "pin-project", "serde", - "thiserror 2.0.12", + "thiserror 2.0.16", "tokio", "twox-hash", ] @@ -1867,7 +1941,7 @@ dependencies = [ "parking_lot", "pin-project", "serde", - "thiserror 2.0.12", + "thiserror 2.0.16", "tokio", "tracing", ] @@ -1899,7 +1973,7 @@ dependencies = [ "pin-project", "rand 0.9.1", "serde", - "thiserror 2.0.12", + "thiserror 2.0.16", "tokio", "tracing", "twox-hash", @@ -2120,6 +2194,16 @@ dependencies = [ "tracing", ] +[[package]] +name = "half" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9" +dependencies = [ + "cfg-if", + "crunchy", +] + [[package]] name = "handlebars" version = "6.3.2" @@ -2133,7 +2217,7 @@ dependencies = [ "pest_derive", "serde", "serde_json", - "thiserror 2.0.12", + "thiserror 2.0.16", "walkdir", ] @@ -2169,6 +2253,15 @@ dependencies = [ "foldhash", ] +[[package]] +name = "hashlink" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" +dependencies = [ + "hashbrown 0.15.2", +] + [[package]] name = "headers" version = "0.4.0" @@ -2222,6 +2315,15 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hex-conservative" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5313b072ce3c597065a808dbf612c4c8e8590bdbf8b579508bf7a762c5eae6cd" +dependencies = [ + "arrayvec", +] + [[package]] name = "hickory-proto" version = "0.25.2" @@ -2240,7 +2342,7 @@ dependencies = [ "once_cell", "rand 0.9.1", "ring", - "thiserror 2.0.12", + "thiserror 2.0.16", "tinyvec", "tokio", "tracing", @@ -2263,7 +2365,7 @@ dependencies = [ "rand 0.9.1", "resolv-conf", "smallvec", - "thiserror 2.0.12", + "thiserror 2.0.16", "tokio", "tracing", ] @@ -2757,7 +2859,7 @@ dependencies = [ "metrics", "serde", "serde_json", - "thiserror 2.0.12", + "thiserror 2.0.16", "tokio", "tokio-tungstenite 0.26.2", "url", @@ -2859,6 +2961,39 @@ dependencies = [ "simple_asn1", ] +[[package]] +name = "jwt-compact" +version = "0.9.0-beta.1" +source = "git+https://github.com/fatfingers23/jwt-compact.git#aed088b8ff5ad44ef2785c453f6a4b7916728b1c" +dependencies = [ + "anyhow", + "base64ct", + "chrono", + "ciborium", + "hmac", + "lazy_static", + "rand_core 0.6.4", + "secp256k1", + "serde", + "serde_json", + "sha2", + "smallvec", + "subtle", + "zeroize", +] + +[[package]] +name = "k256" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "sha2", +] + [[package]] name = "langtag" version = "0.3.4" @@ -2951,6 +3086,16 @@ dependencies = [ "zstd-sys", ] +[[package]] +name = "libsqlite3-sys" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "133c182a6a2c87864fe97778797e46c7e999672690dc9fa3ee8e241aa4a9c13f" +dependencies = [ + "pkg-config", + "vcpkg", +] + [[package]] name = "libz-sys" version = "1.1.22" @@ -2969,7 +3114,7 @@ dependencies = [ "anyhow", "fluent-uri", "nom", - "thiserror 2.0.12", + "thiserror 2.0.16", "tinyjson", ] @@ -3235,7 +3380,7 @@ dependencies = [ "metrics", "metrics-util 0.20.0", "quanta", - "thiserror 2.0.12", + "thiserror 2.0.16", "tokio", "tracing", ] @@ -3784,7 +3929,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1db05f56d34358a8b1066f67cbb203ee3e7ed2ba674a6263a1d5ec6db2204323" dependencies = [ "memchr", - "thiserror 2.0.12", + "thiserror 2.0.16", "ucd-trie", ] @@ -3880,6 +4025,25 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" +[[package]] +name = "pocket" +version = "0.1.0" +dependencies = [ + "atrium-crypto", + "clap", + "jwt-compact", + "log", + "poem", + "poem-openapi", + "reqwest", + "rusqlite", + "serde", + "serde_json", + "thiserror 2.0.16", + "tokio", + "tracing-subscriber", +] + [[package]] name = "poem" version = "3.1.12" @@ -3918,7 +4082,7 @@ dependencies = [ "smallvec", "sync_wrapper", "tempfile", - "thiserror 2.0.12", + "thiserror 2.0.16", "tokio", "tokio-rustls 0.26.2", "tokio-stream", @@ -3962,7 +4126,7 @@ dependencies = [ "serde_json", "serde_urlencoded", "serde_yaml", - "thiserror 2.0.12", + "thiserror 2.0.16", "tokio", ] @@ -3981,7 +4145,7 @@ dependencies = [ "quote", "regex", "syn 2.0.103", - "thiserror 2.0.12", + "thiserror 2.0.16", ] [[package]] @@ -4130,7 +4294,7 @@ dependencies = [ "rustc-hash 2.1.1", "rustls 0.23.31", "socket2 0.5.9", - "thiserror 2.0.12", + "thiserror 2.0.16", "tokio", "tracing", "web-time", @@ -4151,7 +4315,7 @@ dependencies = [ "rustls 0.23.31", "rustls-pki-types", "slab", - "thiserror 2.0.12", + "thiserror 2.0.16", "tinyvec", "tracing", "web-time", @@ -4504,6 +4668,20 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rusqlite" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "165ca6e57b20e1351573e3729b958bc62f0e48025386970b6e4d29e7a7e71f3f" +dependencies = [ + "bitflags", + "fallible-iterator", + "fallible-streaming-iterator", + "hashlink", + "libsqlite3-sys", + "smallvec", +] + [[package]] name = "rustc-demangle" version = "0.1.24" @@ -4732,6 +4910,26 @@ dependencies = [ "zeroize", ] +[[package]] +name = "secp256k1" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b50c5943d326858130af85e049f2661ba3c78b26589b8ab98e65e80ae44a1252" +dependencies = [ + "bitcoin_hashes", + "rand 0.8.5", + "secp256k1-sys", +] + +[[package]] +name = "secp256k1-sys" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4387882333d3aa8cb20530a17c69a3752e97837832f34f6dccc760e715001d9" +dependencies = [ + "cc", +] + [[package]] name = "security-framework" version = "2.11.1" @@ -4865,7 +5063,7 @@ dependencies = [ "percent-encoding", "ryu", "serde", - "thiserror 2.0.12", + "thiserror 2.0.16", ] [[package]] @@ -5008,7 +5206,7 @@ checksum = "297f631f50729c8c99b84667867963997ec0b50f32b2a7dbcab828ef0541e8bb" dependencies = [ "num-bigint", "num-traits", - "thiserror 2.0.12", + "thiserror 2.0.16", "time", ] @@ -5050,7 +5248,7 @@ dependencies = [ "rustls 0.23.31", "serde", "serde_json", - "thiserror 2.0.12", + "thiserror 2.0.16", "time", "tokio", "tokio-util", @@ -5161,7 +5359,7 @@ dependencies = [ "serde", "serde_json", "serde_qs", - "thiserror 2.0.12", + "thiserror 2.0.16", "tinyjson", "tokio", "tokio-tungstenite 0.27.0", @@ -5327,11 +5525,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.12" +version = "2.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0" dependencies = [ - "thiserror-impl 2.0.12", + "thiserror-impl 2.0.16", ] [[package]] @@ -5347,9 +5545,9 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "2.0.12" +version = "2.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960" dependencies = [ "proc-macro2", "quote", @@ -5742,7 +5940,7 @@ dependencies = [ "native-tls", "rand 0.9.1", "sha1", - "thiserror 2.0.12", + "thiserror 2.0.16", "url", "utf-8", ] @@ -5760,7 +5958,7 @@ dependencies = [ "log", "rand 0.9.1", "sha1", - "thiserror 2.0.12", + "thiserror 2.0.16", "utf-8", ] @@ -5813,7 +6011,7 @@ dependencies = [ "serde_qs", "sha2", "tempfile", - "thiserror 2.0.12", + "thiserror 2.0.16", "tikv-jemallocator", "tokio", "tokio-util", @@ -6147,7 +6345,7 @@ dependencies = [ "reqwest", "serde", "serde_json", - "thiserror 2.0.12", + "thiserror 2.0.16", "tokio", "tokio-util", "url", @@ -6540,7 +6738,7 @@ dependencies = [ "nom", "oid-registry", "rusticata-macros", - "thiserror 2.0.12", + "thiserror 2.0.16", "time", ] @@ -6651,6 +6849,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" dependencies = [ "serde", + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.103", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index e87ea96..25cbcc0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,4 +10,5 @@ members = [ "who-am-i", "slingshot", "quasar", + "pocket", ] diff --git a/pocket/Cargo.toml b/pocket/Cargo.toml new file mode 100644 index 0000000..3b785ff --- /dev/null +++ b/pocket/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "pocket" +version = "0.1.0" +edition = "2024" + +[dependencies] +atrium-crypto = "0.1.2" +clap = { version = "4.5.41", features = ["derive"] } +jwt-compact = { git = "https://github.com/fatfingers23/jwt-compact.git", features = ["es256k"] } +log = "0.4.27" +poem = { version = "3.1.12", features = ["acme", "static-files"] } +poem-openapi = { version = "5.1.16", features = ["scalar"] } +reqwest = { version = "0.12.22", features = ["json"] } +rusqlite = "0.37.0" +serde = { version = "1.0.219", features = ["derive"] } +serde_json = { version = "1.0.141" } +thiserror = "2.0.16" +tokio = { version = "1.47.0", features = ["full"] } +tracing-subscriber = { version = "0.3.19", features = ["env-filter"] } diff --git a/pocket/src/lib.rs b/pocket/src/lib.rs new file mode 100644 index 0000000..1a7a0be --- /dev/null +++ b/pocket/src/lib.rs @@ -0,0 +1,5 @@ +mod server; +mod token; + +pub use server::serve; +pub use token::verify; diff --git a/pocket/src/main.rs b/pocket/src/main.rs new file mode 100644 index 0000000..a68f1b8 --- /dev/null +++ b/pocket/src/main.rs @@ -0,0 +1,9 @@ +use pocket::serve; + +#[tokio::main] +async fn main() { + tracing_subscriber::fmt::init(); + println!("Hello, world!"); + serve("mac.cinnebar-tet.ts.net").await +} + diff --git a/pocket/src/server.rs b/pocket/src/server.rs new file mode 100644 index 0000000..940630d --- /dev/null +++ b/pocket/src/server.rs @@ -0,0 +1,208 @@ +use poem::{ + endpoint::make_sync, + Endpoint, + Route, + Server, + EndpointExt, + http::{Method, HeaderMap}, + middleware::{CatchPanic, Cors, Tracing}, + listener::TcpListener, +}; +use poem_openapi::{ + ContactObject, + ExternalDocumentObject, + OpenApi, + OpenApiService, + Tags, + Object, + ApiResponse, + types::Example, + auth::Bearer, + payload::Json, + SecurityScheme, +}; +use crate::verify; +use serde::Serialize; +use serde_json::{Value, json}; + + +#[derive(Debug, SecurityScheme)] +#[oai(ty = "bearer")] +struct BlahAuth(Bearer); + + +#[derive(Tags)] +enum ApiTags { + /// Bluesky-compatible APIs. + #[oai(rename = "app.bsky.* queries")] + AppBsky, +} + +#[derive(Object)] +#[oai(example = true)] +struct XrpcErrorResponseObject { + /// Should correspond an error `name` in the lexicon errors array + error: String, + /// Human-readable description and possibly additonal context + message: String, +} +impl Example for XrpcErrorResponseObject { + fn example() -> Self { + Self { + error: "PreferencesNotFound".to_string(), + message: "No preferences were found for this user".to_string(), + } + } +} +type XrpcError = Json; +fn xrpc_error(error: impl AsRef, message: impl AsRef) -> XrpcError { + Json(XrpcErrorResponseObject { + error: error.as_ref().to_string(), + message: message.as_ref().to_string(), + }) +} + +#[derive(Object)] +#[oai(example = true)] +struct GetBskyPrefsResponseObject { + /// at-uri for this record + preferences: Value, +} +impl Example for GetBskyPrefsResponseObject { + fn example() -> Self { + Self { + preferences: json!({ + "hello": "world", + }), + } + } +} + +#[derive(ApiResponse)] +enum GetBskyPrefsResponse { + /// Record found + #[oai(status = 200)] + Ok(Json), + /// Bad request or no preferences to return + #[oai(status = 400)] + BadRequest(XrpcError), + // /// Server errors + // #[oai(status = 500)] + // ServerError(XrpcError), +} + +struct Xrpc { + domain: String, +} + +#[OpenApi] +impl Xrpc { + /// app.bsky.actor.getPreferences + /// + /// get stored bluesky prefs + #[oai( + path = "/app.bsky.actor.getPreferences", + method = "get", + tag = "ApiTags::AppBsky" + )] + async fn app_bsky_get_prefs( + &self, + BlahAuth(auth): BlahAuth, + m: &HeaderMap, + ) -> GetBskyPrefsResponse { + log::warn!("hm: {m:?}"); + match verify( + &format!("did:web:{}#bsky_appview", self.domain), + "app.bsky.actor.getPreferences", + &auth.token, + ).await { + Ok(did) => log::info!("wooo! {did}"), + Err(err) => return GetBskyPrefsResponse::BadRequest(xrpc_error("booo", err)), + }; + log::warn!("got bearer: {:?}", auth.token); + GetBskyPrefsResponse::Ok(Json(GetBskyPrefsResponseObject::example())) + } + + /// app.bsky.actor.putPreferences + /// + /// store bluesky prefs + #[oai( + path = "/app.bsky.actor.putPreferences", + method = "post", + tag = "ApiTags::AppBsky" + )] + async fn app_bsky_put_prefs( + &self, + Json(prefs): Json, + ) -> () { + log::warn!("received prefs: {prefs:?}"); + () + } +} + +#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +struct AppViewService { + id: String, + r#type: String, + service_endpoint: String, +} +#[derive(Debug, Clone, Serialize)] +struct AppViewDoc { + id: String, + service: [AppViewService; 1], +} +/// Serve a did document for did:web for this to be an xrpc appview +fn get_did_doc(domain: &str) -> impl Endpoint + use<> { + let doc = poem::web::Json(AppViewDoc { + id: format!("did:web:{domain}"), + service: [AppViewService { + id: "#bsky_appview".to_string(), + r#type: "PocketBlueskyPreferences".to_string(), + service_endpoint: format!("https://{domain}"), + }], + }); + make_sync(move |_| doc.clone()) +} + +pub async fn serve( + domain: &str, +) -> () { + let api_service = OpenApiService::new( + Xrpc { domain: domain.to_string() }, + "Pocket", + env!("CARGO_PKG_VERSION"), + ) + .server(domain) + .url_prefix("/xrpc") + .contact( + ContactObject::new() + .name("@microcosm.blue") + .url("https://bsky.app/profile/microcosm.blue"), + ) + // .description(include_str!("../api-description.md")) + .external_document(ExternalDocumentObject::new( + "https://microcosm.blue/pocket", + )); + + let app = Route::new() + .at("/.well-known/did.json", get_did_doc(&domain)) + .nest("/xrpc/", api_service) + // .at("/", StaticFileEndpoint::new("./static/index.html")) + // .nest("/openapi", api_service.spec_endpoint()) + .with( + Cors::new() + .allow_method(Method::GET) + .allow_method(Method::POST) + ) + .with(CatchPanic::new()) + .with(Tracing); + + let listener = TcpListener::bind("127.0.0.1:3000"); + Server::new(listener) + .name("pocket") + .run(app) + .await + .unwrap(); + +} diff --git a/pocket/src/token.rs b/pocket/src/token.rs new file mode 100644 index 0000000..23e513f --- /dev/null +++ b/pocket/src/token.rs @@ -0,0 +1,72 @@ +use jwt_compact::{Claims, UntrustedToken}; +use atrium_crypto::did::parse_multikey; +use atrium_crypto::verify::Verifier; +use std::collections::HashMap; +use serde::Deserialize; + +#[derive(Debug, Deserialize)] +struct MiniDoc { + signing_key: String, +} + +pub async fn verify( + expected_aud: &str, + expected_lxm: &str, + token: &str, +) -> Result { + let untrusted = UntrustedToken::new(token).unwrap(); + + let claims: Claims> = untrusted.deserialize_claims_unchecked().unwrap(); + + let Some(did) = claims.custom.get("iss") else { + return Err("jwt must include the user's did in `iss`"); + }; + + if !did.starts_with("did:") { + return Err("iss should be a did"); + } + if did.contains("#") { + return Err("iss should be a user did without a service identifier"); + } + + println!("Claims: {claims:#?}"); + println!("did: {did:#?}"); + + let endpoint = "https://slingshot.microcosm.blue/xrpc/com.bad-example.identity.resolveMiniDoc"; + let doc: MiniDoc = reqwest::get(format!("{endpoint}?identifier={did}")) + .await + .unwrap() + .error_for_status() + .unwrap() + .json() + .await + .unwrap(); + + log::info!("got minidoc response: {doc:?}"); + + let (alg, public_key) = parse_multikey(&doc.signing_key).unwrap(); + log::info!("parsed key: {public_key:?}"); + + Verifier::default().verify( + alg, + &public_key, + &untrusted.signed_data, + untrusted.signature_bytes(), + ).unwrap(); + // if this passes, then our claims were trustworthy after all(??) + + let Some(aud) = claims.custom.get("aud") else { + return Err("missing aud"); + }; + if aud != expected_aud { + return Err("wrong aud"); + } + let Some(lxm) = claims.custom.get("lxm") else { + return Err("missing lxm"); + }; + if lxm != expected_lxm { + return Err("wrong lxm"); + } + + Ok(did.to_string()) +} diff --git a/quasar/src/storage.rs b/quasar/src/storage.rs index e69de29..4a26f98 100644 --- a/quasar/src/storage.rs +++ b/quasar/src/storage.rs @@ -0,0 +1,4 @@ + +trait Storage { + +} -- 2.51.2