Constellation, Spacedust, Slingshot, UFOs: atproto crates and services for microcosm

working with bsky_appview...

Changed files
+25 -16
pocket
+5 -5
pocket/src/server.rs
···
tag = "ApiTags::Pocket"
)]
async fn app_bsky_get_prefs(&self, XrpcAuth(auth): XrpcAuth) -> GetBskyPrefsResponse {
-
let did = match self
+
let (did, aud) = match self
.verifier
.verify("app.bsky.actor.getPreferences", &auth.token)
.await
···
Ok(d) => d,
Err(e) => return GetBskyPrefsResponse::BadRequest(xrpc_error("boooo", e.to_string())),
};
-
log::info!("verified did: {did}");
+
log::info!("verified did: {did}/{aud}");
// TODO: fetch from storage
GetBskyPrefsResponse::Ok(Json(GetBskyPrefsResponseObject::example()))
}
···
XrpcAuth(auth): XrpcAuth,
Json(prefs): Json<Value>,
) -> PutBskyPrefsResponse {
-
let did = match self
+
let (did, aud) = match self
.verifier
.verify("app.bsky.actor.getPreferences", &auth.token)
.await
···
Ok(d) => d,
Err(e) => return PutBskyPrefsResponse::BadRequest(xrpc_error("boooo", e.to_string())),
};
-
log::info!("verified did: {did}");
+
log::info!("verified did: {did}/{aud}");
log::warn!("received prefs: {prefs:?}");
// TODO: put prefs into storage
PutBskyPrefsResponse::Ok(PlainText("hiiiiii".to_string()))
···
}
pub async fn serve(domain: &str) -> () {
-
let verifier = TokenVerifier::new(domain);
+
let verifier = TokenVerifier::default();
let api_service = OpenApiService::new(Xrpc { verifier }, "Pocket", env!("CARGO_PKG_VERSION"))
.server(domain)
.url_prefix("/xrpc")
+20 -11
pocket/src/token.rs
···
}
pub struct TokenVerifier {
-
domain: String,
client: reqwest::Client,
}
impl TokenVerifier {
-
pub fn new(domain: &str) -> Self {
+
pub fn new() -> Self {
let client = reqwest::Client::builder()
.user_agent(format!(
"microcosm pocket v{} (dev: @bad-example.com)",
···
.timeout(Duration::from_secs(12)) // slingshot timeout is 10s
.build()
.unwrap();
-
Self {
-
client,
-
domain: domain.to_string(),
-
}
+
Self { client }
}
-
pub async fn verify(&self, expected_lxm: &str, token: &str) -> Result<String, VerifyError> {
+
pub async fn verify(
+
&self,
+
expected_lxm: &str,
+
token: &str,
+
) -> Result<(String, String), VerifyError> {
let untrusted = UntrustedToken::new(token).unwrap();
// danger! unfortunately we need to decode the DID from the jwt body before we have a public key to verify the jwt with
···
let Some(aud) = claims.custom.get("aud") else {
return Err(VerifyError::VerificationFailed("missing aud"));
};
-
if *aud != format!("did:web:{}#bsky_appview", self.domain) {
-
return Err(VerifyError::VerificationFailed("wrong aud"));
-
}
+
let Some(aud) = aud.strip_prefix("did:web:") else {
+
return Err(VerifyError::VerificationFailed("expected a did:web aud"));
+
};
+
let Some((aud, _)) = aud.split_once("#") else {
+
return Err(VerifyError::VerificationFailed("aud missing #fragment"));
+
};
let Some(lxm) = claims.custom.get("lxm") else {
return Err(VerifyError::VerificationFailed("missing lxm"));
};
···
return Err(VerifyError::VerificationFailed("wrong lxm"));
}
-
Ok(did.to_string())
+
Ok((did.to_string(), aud.to_string()))
+
}
+
}
+
+
impl Default for TokenVerifier {
+
fn default() -> Self {
+
Self::new()
}
}