+5
-5
pocket/src/server.rs
+5
-5
pocket/src/server.rs
···
108
108
tag = "ApiTags::Pocket"
109
109
)]
110
110
async fn app_bsky_get_prefs(&self, XrpcAuth(auth): XrpcAuth) -> GetBskyPrefsResponse {
111
-
let did = match self
111
+
let (did, aud) = match self
112
112
.verifier
113
113
.verify("app.bsky.actor.getPreferences", &auth.token)
114
114
.await
···
116
116
Ok(d) => d,
117
117
Err(e) => return GetBskyPrefsResponse::BadRequest(xrpc_error("boooo", e.to_string())),
118
118
};
119
-
log::info!("verified did: {did}");
119
+
log::info!("verified did: {did}/{aud}");
120
120
// TODO: fetch from storage
121
121
GetBskyPrefsResponse::Ok(Json(GetBskyPrefsResponseObject::example()))
122
122
}
···
134
134
XrpcAuth(auth): XrpcAuth,
135
135
Json(prefs): Json<Value>,
136
136
) -> PutBskyPrefsResponse {
137
-
let did = match self
137
+
let (did, aud) = match self
138
138
.verifier
139
139
.verify("app.bsky.actor.getPreferences", &auth.token)
140
140
.await
···
142
142
Ok(d) => d,
143
143
Err(e) => return PutBskyPrefsResponse::BadRequest(xrpc_error("boooo", e.to_string())),
144
144
};
145
-
log::info!("verified did: {did}");
145
+
log::info!("verified did: {did}/{aud}");
146
146
log::warn!("received prefs: {prefs:?}");
147
147
// TODO: put prefs into storage
148
148
PutBskyPrefsResponse::Ok(PlainText("hiiiiii".to_string()))
···
184
184
}
185
185
186
186
pub async fn serve(domain: &str) -> () {
187
-
let verifier = TokenVerifier::new(domain);
187
+
let verifier = TokenVerifier::default();
188
188
let api_service = OpenApiService::new(Xrpc { verifier }, "Pocket", env!("CARGO_PKG_VERSION"))
189
189
.server(domain)
190
190
.url_prefix("/xrpc")
+20
-11
pocket/src/token.rs
+20
-11
pocket/src/token.rs
···
21
21
}
22
22
23
23
pub struct TokenVerifier {
24
-
domain: String,
25
24
client: reqwest::Client,
26
25
}
27
26
28
27
impl TokenVerifier {
29
-
pub fn new(domain: &str) -> Self {
28
+
pub fn new() -> Self {
30
29
let client = reqwest::Client::builder()
31
30
.user_agent(format!(
32
31
"microcosm pocket v{} (dev: @bad-example.com)",
···
36
35
.timeout(Duration::from_secs(12)) // slingshot timeout is 10s
37
36
.build()
38
37
.unwrap();
39
-
Self {
40
-
client,
41
-
domain: domain.to_string(),
42
-
}
38
+
Self { client }
43
39
}
44
40
45
-
pub async fn verify(&self, expected_lxm: &str, token: &str) -> Result<String, VerifyError> {
41
+
pub async fn verify(
42
+
&self,
43
+
expected_lxm: &str,
44
+
token: &str,
45
+
) -> Result<(String, String), VerifyError> {
46
46
let untrusted = UntrustedToken::new(token).unwrap();
47
47
48
48
// danger! unfortunately we need to decode the DID from the jwt body before we have a public key to verify the jwt with
···
118
118
let Some(aud) = claims.custom.get("aud") else {
119
119
return Err(VerifyError::VerificationFailed("missing aud"));
120
120
};
121
-
if *aud != format!("did:web:{}#bsky_appview", self.domain) {
122
-
return Err(VerifyError::VerificationFailed("wrong aud"));
123
-
}
121
+
let Some(aud) = aud.strip_prefix("did:web:") else {
122
+
return Err(VerifyError::VerificationFailed("expected a did:web aud"));
123
+
};
124
+
let Some((aud, _)) = aud.split_once("#") else {
125
+
return Err(VerifyError::VerificationFailed("aud missing #fragment"));
126
+
};
124
127
let Some(lxm) = claims.custom.get("lxm") else {
125
128
return Err(VerifyError::VerificationFailed("missing lxm"));
126
129
};
···
128
131
return Err(VerifyError::VerificationFailed("wrong lxm"));
129
132
}
130
133
131
-
Ok(did.to_string())
134
+
Ok((did.to_string(), aud.to_string()))
135
+
}
136
+
}
137
+
138
+
impl Default for TokenVerifier {
139
+
fn default() -> Self {
140
+
Self::new()
132
141
}
133
142
}