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

wip: handle resolution failures + missed files

+1 -1
who-am-i/src/oauth.rs
···
};
if bare_handle.is_empty() {
return Err(ResolveHandleError::InvalidHandle(
-
bare_handle.to_string(),
+
at_uri_handle.to_string(),
"empty handle",
));
}
+31 -10
who-am-i/src/server.rs
···
headers: HeaderMap,
) -> impl IntoResponse {
let err = |reason, check_frame| {
-
let info = json!({
-
"reason": reason,
-
"check_frame": check_frame,
-
});
-
RenderHtml("prompt-error", engine.clone(), info).into_response()
+
let info = json!({ "reason": reason, "check_frame": check_frame });
+
let html = RenderHtml("prompt-error", engine.clone(), info);
+
(StatusCode::BAD_REQUEST, html).into_response()
};
let Some(referrer) = headers.get(REFERER) else {
···
}): State<AppState>,
Query(params): Query<UserInfoParams>,
) -> impl IntoResponse {
+
let err = |status, reason| (status, Json(json!({ "reason": reason }))).into_response();
+
let Some(task_handle) = resolve_handles.take(&params.fetch_key) else {
-
return "oops, task does not exist or is gone".into_response();
+
return err(StatusCode::NOT_FOUND, "fetch key does not exist or expired");
};
-
if let Ok(handle) = task_handle.await.unwrap() {
-
Json(json!({ "handle": handle })).into_response()
-
} else {
-
"no handle?".into_response()
+
+
match task_handle.await {
+
Err(task_err) => {
+
eprintln!("task join error? {task_err:?}");
+
err(StatusCode::INTERNAL_SERVER_ERROR, "server errored")
+
}
+
Ok(Err(ResolveHandleError::ResolutionFailed(atrium_identity::Error::NotFound))) => {
+
err(StatusCode::NOT_FOUND, "handle not found")
+
}
+
Ok(Err(ResolveHandleError::ResolutionFailed(e))) => {
+
eprintln!("handle resolution failed: {e:?}");
+
err(
+
StatusCode::INTERNAL_SERVER_ERROR,
+
"handle resolution failed",
+
)
+
}
+
Ok(Err(ResolveHandleError::NoHandle)) => err(
+
StatusCode::INTERNAL_SERVER_ERROR,
+
"resolved identity but did not find a handle",
+
),
+
Ok(Err(ResolveHandleError::InvalidHandle(_h, reason))) => err(
+
StatusCode::INTERNAL_SERVER_ERROR,
+
&format!("handle appears invalid: {reason}"),
+
),
+
Ok(Ok(handle)) => Json(json!({ "handle": handle })).into_response(),
}
}
who-am-i/static/favicon.ico

This is a binary file and will not be displayed.

+146
who-am-i/static/style.css
···
+
body {
+
color: #434;
+
font-family: 'Iowan Old Style', 'Palatino Linotype', 'URW Palladio L', P052, serif;
+
margin: 0;
+
min-height: 100vh;
+
padding: 0;
+
}
+
.wrap {
+
border: 2px solid #221828;
+
border-radius: 0.5rem;
+
box-sizing: border-box;
+
overflow: hidden;
+
display: flex;
+
flex-direction: column;
+
height: 100vh;
+
}
+
.wrap.unframed {
+
border-radius: 0;
+
border-width: 0.4rem;
+
}
+
header {
+
background: #221828;
+
display: flex;
+
justify-content: space-between;
+
padding: 0 0.25rem;
+
color: #c9b;
+
display: flex;
+
gap: 0.5rem;
+
align-items: baseline;
+
}
+
header > * {
+
flex-basis: 33%;
+
}
+
header > .empty {
+
font-size: 0.8rem;
+
opacity: 0.5;
+
}
+
header > .title {
+
text-align: center;
+
}
+
header > a.micro {
+
text-decoration: none;
+
font-size: 0.8rem;
+
text-align: right;
+
opacity: 0.5;
+
}
+
header > a.micro:hover {
+
opacity: 1;
+
}
+
main {
+
background: #ccc;
+
display: flex;
+
flex-direction: column;
+
flex-grow: 1;
+
padding: 0.25rem 0.5rem;
+
}
+
.mini-content {
+
margin: 1rem auto 0;
+
padding: 1rem 0.5rem;
+
max-width: 21rem;
+
}
+
+
p {
+
margin: 1rem 0 0;
+
text-align: center;
+
}
+
.parent-host {
+
font-weight: bold;
+
color: #48c;
+
display: inline-block;
+
padding: 0 0.125rem;
+
border-radius: 0.25rem;
+
border: 1px solid #aaa;
+
font-size: 0.8rem;
+
}
+
+
#loader {
+
display: flex;
+
flex-grow: 1;
+
justify-content: center;
+
align-items: center;
+
}
+
.spinner {
+
animation: rotation 1.618s ease-in-out infinite;
+
border-radius: 50%;
+
border: 3px dashed #434;
+
box-sizing: border-box;
+
display: inline-block;
+
height: 1.5em;
+
width: 1.5em;
+
}
+
@keyframes rotation {
+
0% { transform: rotate(0deg) }
+
100% { transform: rotate(360deg) }
+
}
+
+
#user-info {
+
flex-grow: 1;
+
display: flex;
+
flex-direction: column;
+
justify-content: center;
+
}
+
#action {
+
background: #eee;
+
display: flex;
+
justify-content: space-between;
+
padding: 0.5rem 0.25rem 0.5rem 0.5rem;
+
font-size: 0.8rem;
+
align-items: baseline;
+
border-radius: 0.5rem;
+
border: 1px solid #bbb;
+
cursor: pointer;
+
}
+
#action:hover {
+
background: #fff;
+
}
+
#allow {
+
background: transparent;
+
border: none;
+
border-left: 1px solid #bbb;
+
padding: 0 0.5rem;
+
color: #375;
+
font: inherit;
+
cursor: pointer;
+
}
+
#action:hover #allow {
+
color: #285;
+
}
+
+
#or {
+
font-size: 0.8rem;
+
text-align: center;
+
}
+
#or p {
+
margin: 0 0 1rem;
+
}
+
+
input#handle {
+
border: none;
+
border-bottom: 1px dashed #aaa;
+
background: transparent;
+
}
+
+
.hidden {
+
display: none !important;
+
}
+17
who-am-i/templates/base-base.hbs
···
+
<!doctype html>
+
<html lang="en">
+
<head>
+
<meta charset="utf-8" />
+
<title>who-am-i</title>
+
<meta name="description" content="{{> description }}">
+
<meta property="og:type" content="website">
+
<meta property="og:description" content="{{> description}}">
+
<!-- <meta property="og:image" content=""> -->
+
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
+
<link href="/style.css" rel="stylesheet" type="text/css" />
+
</head>
+
<body>
+
{{> body}}
+
</body>
+
</html>
+28
who-am-i/templates/base-framed.hbs
···
+
{{#*inline "description"}}{{/inline}}
+
+
{{#*inline "body"}}
+
<div class="wrap">
+
<header>
+
<div class="empty">🔒</div>
+
<code class="title" style="font-family: monospace;"
+
>who-am-i</code>
+
<a href="https://microcosm.blue" target="_blank" class="micro"
+
><span style="color: #f396a9">m</span
+
><span style="color: #f49c5c">i</span
+
><span style="color: #c7b04c">c</span
+
><span style="color: #92be4c">r</span
+
><span style="color: #4ec688">o</span
+
><span style="color: #51c2b6">c</span
+
><span style="color: #54bed7">o</span
+
><span style="color: #8fb1f1">s</span
+
><span style="color: #ce9df1">m</span
+
></a>
+
</header>
+
+
<main>
+
{{> main}}
+
</main>
+
</div>
+
{{/inline}}
+
+
{{#> base-base}}{{/base-base}}
+26
who-am-i/templates/base-full.hbs
···
+
{{#*inline "body"}}
+
<div class="wrap unframed">
+
<header>
+
<div class="empty">🔒</div>
+
<code class="title" style="font-family: monospace;"
+
>who-am-i</code>
+
<a href="https://microcosm.blue" target="_blank" class="micro"
+
><span style="color: #f396a9">m</span
+
><span style="color: #f49c5c">i</span
+
><span style="color: #c7b04c">c</span
+
><span style="color: #92be4c">r</span
+
><span style="color: #4ec688">o</span
+
><span style="color: #51c2b6">c</span
+
><span style="color: #54bed7">o</span
+
><span style="color: #8fb1f1">s</span
+
><span style="color: #ce9df1">m</span
+
></a>
+
</header>
+
+
<main>
+
{{> main}}
+
</main>
+
</div>
+
{{/inline}}
+
+
{{#> base-base}}{{/base-base}}
+9
who-am-i/templates/hello.hbs
···
+
{{#*inline "description"}}A little identity-verifying auth service for microcosm demos{{/inline}}
+
+
{{#*inline "main"}}
+
<div class="mini-content">
+
This is a little identity-verifying service for microcosm demos.
+
</div>
+
{{/inline}}
+
+
{{#> base-full}}{{/base-full}}
+17
who-am-i/templates/prompt-error.hbs
···
+
{{#*inline "main"}}
+
<div class="prompt-error">
+
<p class="went-wrong">Something went wrong :(</p>
+
<p class="reason">{{ reason }}</p>
+
<p id="maybe-not-in-iframe" class="hidden">
+
Possibly related: this prompt is meant to be shown in an iframe, but it seems like it's not.
+
</p>
+
</div>
+
+
<script>
+
if ({{{json check_frame}}} && window.self === window.top) {
+
document.getElementById('maybe-not-in-iframe').classList.remove('hidden');
+
}
+
</script>
+
{{/inline}}
+
+
{{#> base-framed}}{{/base-framed}}