Skip to content

Commit 2afb053

Browse files
committed
com.atproto.identity.resolveHandle
1 parent 1d646ef commit 2afb053

File tree

1 file changed

+97
-0
lines changed

1 file changed

+97
-0
lines changed

slingshot/src/server.rs

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,13 @@ fn bad_request_handler_resolve_mini(err: poem::Error) -> ResolveMiniIDResponse {
9191
}))
9292
}
9393

94+
fn bad_request_handler_resolve_handle(err: poem::Error) -> JustDidResponse {
95+
JustDidResponse::BadRequest(Json(XrpcErrorResponseObject {
96+
error: "InvalidRequest".to_string(),
97+
message: format!("Bad request, here's some info that maybe should not be exposed: {err}"),
98+
}))
99+
}
100+
94101
#[derive(Object)]
95102
#[oai(example = true)]
96103
struct FoundRecordResponseObject {
@@ -182,6 +189,34 @@ enum ResolveMiniIDResponse {
182189
BadRequest(XrpcError),
183190
}
184191

192+
#[derive(Object)]
193+
#[oai(example = true)]
194+
struct FoundDidResponseObject {
195+
/// the DID, bi-directionally verified if using Slingshot
196+
did: String,
197+
}
198+
impl Example for FoundDidResponseObject {
199+
fn example() -> Self {
200+
Self { did: example_did() }
201+
}
202+
}
203+
204+
#[derive(ApiResponse)]
205+
#[oai(bad_request_handler = "bad_request_handler_resolve_handle")]
206+
enum JustDidResponse {
207+
/// Resolution succeeded
208+
#[oai(status = 200)]
209+
Ok(Json<FoundDidResponseObject>),
210+
/// Bad request, failed to resolve, or failed to verify
211+
///
212+
/// `error` will be one of `InvalidRequest`, `HandleNotFound`.
213+
#[oai(status = 400)]
214+
BadRequest(XrpcError),
215+
/// Something went wrong trying to complete the request
216+
#[oai(status = 500)]
217+
ServerError(XrpcError),
218+
}
219+
185220
struct Xrpc {
186221
cache: HybridCache<String, CachedRecord>,
187222
identity: Identity,
@@ -314,6 +349,68 @@ impl Xrpc {
314349
.await
315350
}
316351

352+
/// com.atproto.identity.resolveHandle
353+
///
354+
/// Resolves an atproto [`handle`](https://atproto.com/guides/glossary#handle)
355+
/// (hostname) to a [`DID`](https://atproto.com/guides/glossary#did-decentralized-id).
356+
///
357+
/// Compatibility note: **Slingshot will _always_ bi-directionally verify
358+
/// against the DID document**, which is optional by the authoritative
359+
/// lexicon. You can trust the `DID` returned from this endpoint without
360+
/// further checks, but this may not hold if you switch from Slingshot to a
361+
/// different service offering this query.
362+
///
363+
/// See also the [canonical `com.atproto` XRPC documentation](https://docs.bsky.app/docs/api/com-atproto-identity-resolve-handle)
364+
/// that this endpoint aims to be compatible with.
365+
#[oai(
366+
path = "/com.atproto.identity.resolveHandle",
367+
method = "get",
368+
tag = "ApiTags::ComAtproto"
369+
)]
370+
async fn resolve_handle(
371+
&self,
372+
/// The handle to resolve.
373+
#[oai(example = "example_handle")]
374+
Query(handle): Query<String>,
375+
) -> JustDidResponse {
376+
let Ok(handle) = Handle::new(handle) else {
377+
return JustDidResponse::BadRequest(xrpc_error("InvalidRequest", "not a valid handle"));
378+
};
379+
380+
let Ok(alleged_did) = self.identity.handle_to_did(handle.clone()).await else {
381+
return JustDidResponse::ServerError(xrpc_error("Failed", "Could not resolve handle"));
382+
};
383+
384+
let Some(alleged_did) = alleged_did else {
385+
return JustDidResponse::BadRequest(xrpc_error(
386+
"HandleNotFound",
387+
"Could not resolve handle to a DID",
388+
));
389+
};
390+
391+
let Ok(partial_doc) = self.identity.did_to_partial_mini_doc(&alleged_did).await else {
392+
return JustDidResponse::ServerError(xrpc_error("Failed", "Could not fetch DID doc"));
393+
};
394+
395+
let Some(partial_doc) = partial_doc else {
396+
return JustDidResponse::BadRequest(xrpc_error(
397+
"HandleNotFound",
398+
"Resolved handle but could not find DID doc for the DID",
399+
));
400+
};
401+
402+
if partial_doc.unverified_handle != handle {
403+
return JustDidResponse::BadRequest(xrpc_error(
404+
"HandleNotFound",
405+
"Resolved handle failed bi-directional validation",
406+
));
407+
}
408+
409+
JustDidResponse::Ok(Json(FoundDidResponseObject {
410+
did: alleged_did.to_string(),
411+
}))
412+
}
413+
317414
/// com.bad-example.identity.resolveMiniDoc
318415
///
319416
/// Like [com.atproto.identity.resolveIdentity](https://docs.bsky.app/docs/api/com-atproto-identity-resolve-identity)

0 commit comments

Comments
 (0)