alpha
Login
or
Join now
microcosm.blue
/
microcosm-rs
Star
0
Fork
3
Atom
Configure Feed
Issues
Pull Requests
Commits
Tags
Feed URL
Select the types of activity you want to include in your feed.
Constellation, Spacedust, Slingshot, UFOs: atproto crates and services for microcosm
Star
0
Fork
3
Atom
Configure Feed
Issues
Pull Requests
Commits
Tags
Feed URL
Select the types of activity you want to include in your feed.
Overview
Issues
Pulls
Pipelines
look up identity from did-cookie
author
phil
date
1 year ago
(Jun 26, 2025, 4:36 PM -0400)
commit
8ddb11f6
8ddb11f65adf582066463cabf2aefc5dc4c6cad6
parent
08b772bf
08b772bf9f70797faafd225bccac484018df1c0f
+468
-25
9 changed files
Expand all
Collapse all
Unified
Split
Cargo.lock
who-am-i
Cargo.toml
demo
index.html
src
expiring_task_map.rs
identity_resolver.rs
lib.rs
main.rs
server.rs
templates
prompt-known.hbs
+161
Cargo.lock
Reviewed
···
500
500
]
501
501
502
502
[[package]]
503
503
+
name = "axum-template"
504
504
+
version = "3.0.0"
505
505
+
source = "registry+https://github.com/rust-lang/crates.io-index"
506
506
+
checksum = "3df50f7d669bfc3a8c348f08f536fe37e7acfbeded3cfdffd2ad3d76725fc40c"
507
507
+
dependencies = [
508
508
+
"axum",
509
509
+
"handlebars",
510
510
+
"serde",
511
511
+
"thiserror 2.0.12",
512
512
+
]
513
513
+
514
514
+
[[package]]
503
515
name = "backtrace"
504
516
version = "0.3.74"
505
517
source = "registry+https://github.com/rust-lang/crates.io-index"
···
1164
1176
]
1165
1177
1166
1178
[[package]]
1179
1179
+
name = "derive_builder"
1180
1180
+
version = "0.20.2"
1181
1181
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1182
1182
+
checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947"
1183
1183
+
dependencies = [
1184
1184
+
"derive_builder_macro",
1185
1185
+
]
1186
1186
+
1187
1187
+
[[package]]
1188
1188
+
name = "derive_builder_core"
1189
1189
+
version = "0.20.2"
1190
1190
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1191
1191
+
checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8"
1192
1192
+
dependencies = [
1193
1193
+
"darling",
1194
1194
+
"proc-macro2",
1195
1195
+
"quote",
1196
1196
+
"syn",
1197
1197
+
]
1198
1198
+
1199
1199
+
[[package]]
1200
1200
+
name = "derive_builder_macro"
1201
1201
+
version = "0.20.2"
1202
1202
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1203
1203
+
checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c"
1204
1204
+
dependencies = [
1205
1205
+
"derive_builder_core",
1206
1206
+
"syn",
1207
1207
+
]
1208
1208
+
1209
1209
+
[[package]]
1167
1210
name = "digest"
1168
1211
version = "0.10.7"
1169
1212
source = "registry+https://github.com/rust-lang/crates.io-index"
···
1716
1759
"tokio",
1717
1760
"tokio-util",
1718
1761
"tracing",
1762
1762
+
]
1763
1763
+
1764
1764
+
[[package]]
1765
1765
+
name = "handlebars"
1766
1766
+
version = "6.3.2"
1767
1767
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1768
1768
+
checksum = "759e2d5aea3287cb1190c8ec394f42866cb5bf74fcbf213f354e3c856ea26098"
1769
1769
+
dependencies = [
1770
1770
+
"derive_builder",
1771
1771
+
"log",
1772
1772
+
"num-order",
1773
1773
+
"pest",
1774
1774
+
"pest_derive",
1775
1775
+
"serde",
1776
1776
+
"serde_json",
1777
1777
+
"thiserror 2.0.12",
1778
1778
+
"walkdir",
1719
1779
]
1720
1780
1721
1781
[[package]]
···
2879
2939
]
2880
2940
2881
2941
[[package]]
2942
2942
+
name = "num-modular"
2943
2943
+
version = "0.6.1"
2944
2944
+
source = "registry+https://github.com/rust-lang/crates.io-index"
2945
2945
+
checksum = "17bb261bf36fa7d83f4c294f834e91256769097b3cb505d44831e0a179ac647f"
2946
2946
+
2947
2947
+
[[package]]
2948
2948
+
name = "num-order"
2949
2949
+
version = "1.2.0"
2950
2950
+
source = "registry+https://github.com/rust-lang/crates.io-index"
2951
2951
+
checksum = "537b596b97c40fcf8056d153049eb22f481c17ebce72a513ec9286e4986d1bb6"
2952
2952
+
dependencies = [
2953
2953
+
"num-modular",
2954
2954
+
]
2955
2955
+
2956
2956
+
[[package]]
2882
2957
name = "num-traits"
2883
2958
version = "0.2.19"
2884
2959
source = "registry+https://github.com/rust-lang/crates.io-index"
···
3058
3133
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
3059
3134
3060
3135
[[package]]
3136
3136
+
name = "pest"
3137
3137
+
version = "2.8.1"
3138
3138
+
source = "registry+https://github.com/rust-lang/crates.io-index"
3139
3139
+
checksum = "1db05f56d34358a8b1066f67cbb203ee3e7ed2ba674a6263a1d5ec6db2204323"
3140
3140
+
dependencies = [
3141
3141
+
"memchr",
3142
3142
+
"thiserror 2.0.12",
3143
3143
+
"ucd-trie",
3144
3144
+
]
3145
3145
+
3146
3146
+
[[package]]
3147
3147
+
name = "pest_derive"
3148
3148
+
version = "2.8.1"
3149
3149
+
source = "registry+https://github.com/rust-lang/crates.io-index"
3150
3150
+
checksum = "bb056d9e8ea77922845ec74a1c4e8fb17e7c218cc4fc11a15c5d25e189aa40bc"
3151
3151
+
dependencies = [
3152
3152
+
"pest",
3153
3153
+
"pest_generator",
3154
3154
+
]
3155
3155
+
3156
3156
+
[[package]]
3157
3157
+
name = "pest_generator"
3158
3158
+
version = "2.8.1"
3159
3159
+
source = "registry+https://github.com/rust-lang/crates.io-index"
3160
3160
+
checksum = "87e404e638f781eb3202dc82db6760c8ae8a1eeef7fb3fa8264b2ef280504966"
3161
3161
+
dependencies = [
3162
3162
+
"pest",
3163
3163
+
"pest_meta",
3164
3164
+
"proc-macro2",
3165
3165
+
"quote",
3166
3166
+
"syn",
3167
3167
+
]
3168
3168
+
3169
3169
+
[[package]]
3170
3170
+
name = "pest_meta"
3171
3171
+
version = "2.8.1"
3172
3172
+
source = "registry+https://github.com/rust-lang/crates.io-index"
3173
3173
+
checksum = "edd1101f170f5903fde0914f899bb503d9ff5271d7ba76bbb70bea63690cc0d5"
3174
3174
+
dependencies = [
3175
3175
+
"pest",
3176
3176
+
"sha2",
3177
3177
+
]
3178
3178
+
3179
3179
+
[[package]]
3061
3180
name = "pin-project-lite"
3062
3181
version = "0.2.16"
3063
3182
source = "registry+https://github.com/rust-lang/crates.io-index"
···
3602
3721
checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
3603
3722
3604
3723
[[package]]
3724
3724
+
name = "same-file"
3725
3725
+
version = "1.0.6"
3726
3726
+
source = "registry+https://github.com/rust-lang/crates.io-index"
3727
3727
+
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
3728
3728
+
dependencies = [
3729
3729
+
"winapi-util",
3730
3730
+
]
3731
3731
+
3732
3732
+
[[package]]
3605
3733
name = "schannel"
3606
3734
version = "0.1.27"
3607
3735
source = "registry+https://github.com/rust-lang/crates.io-index"
···
4557
4685
checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f"
4558
4686
4559
4687
[[package]]
4688
4688
+
name = "ucd-trie"
4689
4689
+
version = "0.1.7"
4690
4690
+
source = "registry+https://github.com/rust-lang/crates.io-index"
4691
4691
+
checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971"
4692
4692
+
4693
4693
+
[[package]]
4560
4694
name = "ufos"
4561
4695
version = "0.1.0"
4562
4696
dependencies = [
···
4734
4868
]
4735
4869
4736
4870
[[package]]
4871
4871
+
name = "walkdir"
4872
4872
+
version = "2.5.0"
4873
4873
+
source = "registry+https://github.com/rust-lang/crates.io-index"
4874
4874
+
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
4875
4875
+
dependencies = [
4876
4876
+
"same-file",
4877
4877
+
"winapi-util",
4878
4878
+
]
4879
4879
+
4880
4880
+
[[package]]
4737
4881
name = "want"
4738
4882
version = "0.3.1"
4739
4883
source = "registry+https://github.com/rust-lang/crates.io-index"
···
4865
5009
version = "0.1.0"
4866
5010
dependencies = [
4867
5011
"atrium-api 0.25.4",
5012
5012
+
"atrium-common 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
4868
5013
"atrium-identity",
4869
5014
"atrium-oauth",
4870
5015
"axum",
4871
5016
"axum-extra",
5017
5017
+
"axum-template",
4872
5018
"clap",
5019
5019
+
"ctrlc",
5020
5020
+
"dashmap",
5021
5021
+
"handlebars",
4873
5022
"hickory-resolver",
4874
5023
"metrics",
5024
5024
+
"rand 0.9.1",
4875
5025
"serde",
5026
5026
+
"serde_json",
4876
5027
"tokio",
4877
5028
"tokio-util",
5029
5029
+
"url",
4878
5030
]
4879
5031
4880
5032
[[package]]
···
4898
5050
version = "0.4.0"
4899
5051
source = "registry+https://github.com/rust-lang/crates.io-index"
4900
5052
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
5053
5053
+
5054
5054
+
[[package]]
5055
5055
+
name = "winapi-util"
5056
5056
+
version = "0.1.9"
5057
5057
+
source = "registry+https://github.com/rust-lang/crates.io-index"
5058
5058
+
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
5059
5059
+
dependencies = [
5060
5060
+
"windows-sys 0.48.0",
5061
5061
+
]
4901
5062
4902
5063
[[package]]
4903
5064
name = "winapi-x86_64-pc-windows-gnu"
+8
who-am-i/Cargo.toml
Reviewed
···
5
5
6
6
[dependencies]
7
7
atrium-api = { version = "0.25.4", default-features = false }
8
8
+
atrium-common = "0.1.2"
8
9
atrium-identity = "0.1.5"
9
10
atrium-oauth = "0.1.3"
10
11
axum = "0.8.4"
11
12
axum-extra = { version = "0.10.1", features = ["cookie-signed", "typed-header"] }
13
13
+
axum-template = { version = "3.0.0", features = ["handlebars"] }
12
14
clap = { version = "4.5.40", features = ["derive"] }
15
15
+
ctrlc = "3.4.7"
16
16
+
dashmap = "6.1.0"
17
17
+
handlebars = { version = "6.3.2", features = ["dir_source"] }
13
18
hickory-resolver = "0.25.2"
14
19
metrics = "0.24.2"
20
20
+
rand = "0.9.1"
15
21
serde = { version = "1.0.219", features = ["derive"] }
22
22
+
serde_json = "1.0.140"
16
23
tokio = { version = "1.45.1", features = ["full", "macros"] }
17
24
tokio-util = "0.7.15"
25
25
+
url = "2.5.4"
+1
-3
who-am-i/demo/index.html
Reviewed
···
9
9
10
10
<h1>hey</h1>
11
11
12
12
-
<iframe src="http://127.0.0.1:9997/prompt" style="border: 2px solid #000; border-radius: 0.5em;" />
13
13
-
14
14
-
12
12
+
<iframe src="http://127.0.0.1:9997/prompt" style="border: none" height="140" width="280" />
+53
who-am-i/src/expiring_task_map.rs
Reviewed
···
1
1
+
use dashmap::DashMap;
2
2
+
use rand::{Rng, distr::Alphanumeric};
3
3
+
use std::sync::Arc;
4
4
+
use std::time::Duration;
5
5
+
use tokio::task::{JoinHandle, spawn};
6
6
+
use tokio::time::sleep; // 0.8
7
7
+
8
8
+
#[derive(Clone)]
9
9
+
pub struct ExpiringTaskMap<T>(Arc<TaskMap<T>>);
10
10
+
11
11
+
impl<T: Send + 'static> ExpiringTaskMap<T> {
12
12
+
pub fn new(expiration: Duration) -> Self {
13
13
+
let map = TaskMap {
14
14
+
map: DashMap::new(),
15
15
+
expiration,
16
16
+
};
17
17
+
Self(Arc::new(map))
18
18
+
}
19
19
+
20
20
+
pub fn dispatch(&self, task: impl Future<Output = T> + Send + 'static) -> String {
21
21
+
let task_key: String = rand::rng()
22
22
+
.sample_iter(&Alphanumeric)
23
23
+
.take(24)
24
24
+
.map(char::from)
25
25
+
.collect();
26
26
+
27
27
+
// spawn a tokio task and put the join handle in the map for later retrieval
28
28
+
self.0.map.insert(task_key.clone(), spawn(task));
29
29
+
30
30
+
// spawn a second task to clean up the map in case it doesn't get claimed
31
31
+
spawn({
32
32
+
let me = self.0.clone();
33
33
+
let key = task_key.clone();
34
34
+
async move {
35
35
+
sleep(me.expiration).await;
36
36
+
let _ = me.map.remove(&key);
37
37
+
// TODO: also use a cancellation token so taking and expiring can mutually cancel
38
38
+
}
39
39
+
});
40
40
+
41
41
+
task_key
42
42
+
}
43
43
+
44
44
+
pub fn take(&self, key: &str) -> Option<JoinHandle<T>> {
45
45
+
eprintln!("trying to take...");
46
46
+
self.0.map.remove(key).map(|(_, handle)| handle)
47
47
+
}
48
48
+
}
49
49
+
50
50
+
struct TaskMap<T> {
51
51
+
map: DashMap<String, JoinHandle<T>>,
52
52
+
expiration: Duration,
53
53
+
}
+20
who-am-i/src/identity_resolver.rs
Reviewed
···
1
1
+
use atrium_api::types::string::Did;
2
2
+
use atrium_common::resolver::Resolver;
3
3
+
use atrium_identity::did::{CommonDidResolver, CommonDidResolverConfig, DEFAULT_PLC_DIRECTORY_URL};
4
4
+
use atrium_oauth::DefaultHttpClient;
5
5
+
use std::sync::Arc;
6
6
+
7
7
+
pub async fn resolve_identity(did: String) -> String {
8
8
+
let http_client = Arc::new(DefaultHttpClient::default());
9
9
+
let resolver = CommonDidResolver::new(CommonDidResolverConfig {
10
10
+
plc_directory_url: DEFAULT_PLC_DIRECTORY_URL.to_string(),
11
11
+
http_client: Arc::clone(&http_client),
12
12
+
});
13
13
+
let doc = resolver.resolve(&Did::new(did).unwrap()).await.unwrap(); // TODO: this is only half the resolution? or is atrium checking dns?
14
14
+
if let Some(aka) = doc.also_known_as {
15
15
+
if let Some(f) = aka.first() {
16
16
+
return f.to_string();
17
17
+
}
18
18
+
}
19
19
+
"who knows".to_string()
20
20
+
}
+4
who-am-i/src/lib.rs
Reviewed
···
1
1
mod dns_resolver;
2
2
+
mod expiring_task_map;
3
3
+
mod identity_resolver;
2
4
mod oauth;
3
5
mod server;
4
6
5
7
pub use dns_resolver::HickoryDnsTxtResolver;
8
8
+
pub use expiring_task_map::ExpiringTaskMap;
9
9
+
pub use identity_resolver::resolve_identity;
6
10
pub use oauth::{Client, authorize, client};
7
11
pub use server::serve;
+27
-2
who-am-i/src/main.rs
Reviewed
···
1
1
+
use clap::Parser;
1
2
use tokio_util::sync::CancellationToken;
2
3
use who_am_i::serve;
3
4
5
5
+
/// Aggregate links in the at-mosphere
6
6
+
#[derive(Parser, Debug, Clone)]
7
7
+
#[command(version, about, long_about = None)]
8
8
+
struct Args {
9
9
+
/// secret key from which the cookie-signing key is derived
10
10
+
///
11
11
+
/// must have at least 512 bits (64 bytes) of randomness
12
12
+
///
13
13
+
/// eg: `cat /dev/urandom | head -c 64 | base64`
14
14
+
#[arg(long)]
15
15
+
app_secret: String,
16
16
+
/// Enable dev mode
17
17
+
///
18
18
+
/// enables automatic template reloading
19
19
+
#[arg(long, action)]
20
20
+
dev: bool,
21
21
+
}
22
22
+
4
23
#[tokio::main]
5
24
async fn main() {
6
6
-
let server_shutdown = CancellationToken::new();
7
7
-
serve(server_shutdown).await;
25
25
+
let shutdown = CancellationToken::new();
26
26
+
27
27
+
let ctrlc_shutdown = shutdown.clone();
28
28
+
ctrlc::set_handler(move || ctrlc_shutdown.cancel()).expect("failed to set ctrl-c handler");
29
29
+
30
30
+
let args = Args::parse();
31
31
+
32
32
+
serve(shutdown, args.app_secret, args.dev).await;
8
33
}
+98
-20
who-am-i/src/server.rs
Reviewed
···
3
3
use axum::{
4
4
Router,
5
5
extract::{FromRef, Query, State},
6
6
+
http::header::{HeaderMap, REFERER},
6
7
response::{Html, IntoResponse, Redirect},
7
8
routing::get,
8
9
};
9
10
use axum_extra::extract::cookie::{Cookie, Key, SameSite, SignedCookieJar};
11
11
+
use axum_template::{RenderHtml, engine::Engine};
12
12
+
use handlebars::{Handlebars, handlebars_helper};
10
13
11
11
-
use serde::Deserialize;
14
14
+
use serde::{Deserialize, Serialize};
15
15
+
use serde_json::Value;
12
16
use std::sync::Arc;
17
17
+
use std::time::Duration;
13
18
use tokio::net::TcpListener;
14
19
use tokio_util::sync::CancellationToken;
20
20
+
use url::Url;
15
21
16
16
-
use crate::{Client, authorize, client};
22
22
+
use crate::{Client, ExpiringTaskMap, authorize, client, resolve_identity};
17
23
18
24
const FAVICON: &[u8] = include_bytes!("../static/favicon.ico");
19
25
const INDEX_HTML: &str = include_str!("../static/index.html");
20
26
const LOGIN_HTML: &str = include_str!("../static/login.html");
21
27
22
22
-
pub async fn serve(shutdown: CancellationToken) {
28
28
+
const DID_COOKIE_KEY: &str = "did";
29
29
+
30
30
+
type AppEngine = Engine<Handlebars<'static>>;
31
31
+
32
32
+
#[derive(Clone)]
33
33
+
struct AppState {
34
34
+
pub key: Key,
35
35
+
pub engine: AppEngine,
36
36
+
pub client: Arc<Client>,
37
37
+
pub resolving: ExpiringTaskMap<String>,
38
38
+
}
39
39
+
40
40
+
impl FromRef<AppState> for Key {
41
41
+
fn from_ref(state: &AppState) -> Self {
42
42
+
state.key.clone()
43
43
+
}
44
44
+
}
45
45
+
46
46
+
pub async fn serve(shutdown: CancellationToken, app_secret: String, dev: bool) {
47
47
+
let mut hbs = Handlebars::new();
48
48
+
hbs.set_dev_mode(dev);
49
49
+
hbs.register_templates_directory("templates", Default::default())
50
50
+
.unwrap();
51
51
+
52
52
+
handlebars_helper!(json: |v: Value| serde_json::to_string(&v).unwrap());
53
53
+
hbs.register_helper("json", Box::new(json));
54
54
+
55
55
+
// clients have to pick up their identity-resolving tasks within this period
56
56
+
let task_pickup_expiration = Duration::from_secs(15);
57
57
+
23
58
let state = AppState {
24
24
-
key: Key::generate(), // TODO: via config
59
59
+
engine: Engine::new(hbs),
60
60
+
key: Key::from(app_secret.as_bytes()), // TODO: via config
25
61
client: Arc::new(client()),
62
62
+
resolving: ExpiringTaskMap::new(task_pickup_expiration),
26
63
};
27
64
28
65
let app = Router::new()
29
66
.route("/", get(|| async { Html(INDEX_HTML) }))
30
67
.route("/favicon.ico", get(|| async { FAVICON })) // todo MIME
31
68
.route("/prompt", get(prompt))
69
69
+
.route("/user-info", get(user_info))
32
70
.route("/auth", get(start_oauth))
33
71
.route("/authorized", get(complete_oauth))
34
72
.with_state(state);
···
43
81
.unwrap();
44
82
}
45
83
46
46
-
#[derive(Clone)]
47
47
-
struct AppState {
48
48
-
pub key: Key,
49
49
-
pub client: Arc<Client>,
84
84
+
#[derive(Debug, Serialize)]
85
85
+
struct Known {
86
86
+
did: Value,
87
87
+
fetch_key: Value,
88
88
+
parent_host: String,
50
89
}
90
90
+
async fn prompt(
91
91
+
State(AppState {
92
92
+
engine, resolving, ..
93
93
+
}): State<AppState>,
94
94
+
jar: SignedCookieJar,
95
95
+
headers: HeaderMap,
96
96
+
) -> impl IntoResponse {
97
97
+
let Some(referrer) = headers.get(REFERER) else {
98
98
+
return Html::<&'static str>("missing referrer, sorry").into_response();
99
99
+
};
100
100
+
let Ok(referrer) = referrer.to_str() else {
101
101
+
return "referer contained opaque bytes".into_response();
102
102
+
};
103
103
+
let Ok(url) = Url::parse(referrer) else {
104
104
+
return "referrer was not a url".into_response();
105
105
+
};
106
106
+
let Some(parent_host) = url.host_str() else {
107
107
+
return "could nto get host from url".into_response();
108
108
+
};
109
109
+
let m = if let Some(did) = jar.get(DID_COOKIE_KEY) {
110
110
+
let did = did.value_trimmed().to_string();
51
111
52
52
-
impl FromRef<AppState> for Key {
53
53
-
fn from_ref(state: &AppState) -> Self {
54
54
-
state.key.clone()
55
55
-
}
112
112
+
let fetch_key = resolving.dispatch(resolve_identity(did.clone()));
113
113
+
114
114
+
let json_did = Value::String(did);
115
115
+
let json_fetch_key = Value::String(fetch_key);
116
116
+
let known = Known {
117
117
+
did: json_did,
118
118
+
fetch_key: json_fetch_key,
119
119
+
parent_host: parent_host.to_string(),
120
120
+
};
121
121
+
return (jar, RenderHtml("prompt-known", engine, known)).into_response();
122
122
+
} else {
123
123
+
LOGIN_HTML.into_response()
124
124
+
};
125
125
+
(jar, Html(m)).into_response()
56
126
}
57
127
58
58
-
async fn prompt(jar: SignedCookieJar) -> impl IntoResponse {
59
59
-
let m = if let Some(did) = jar.get("did") {
60
60
-
format!("oh i know you: {did}")
61
61
-
} else {
62
62
-
LOGIN_HTML.into()
128
128
+
#[derive(Debug, Deserialize)]
129
129
+
#[serde(rename_all = "kebab-case")]
130
130
+
struct UserInfoParams {
131
131
+
fetch_key: String,
132
132
+
}
133
133
+
async fn user_info(
134
134
+
State(AppState { resolving, .. }): State<AppState>,
135
135
+
Query(params): Query<UserInfoParams>,
136
136
+
) -> impl IntoResponse {
137
137
+
// let fetch_key: [char; 16] = params.fetch_key.chars().collect::<Vec<_>>().try_into().unwrap();
138
138
+
let Some(handle) = resolving.take(¶ms.fetch_key) else {
139
139
+
return "oops, task does not exist or is gone".into_response();
63
140
};
64
64
-
(jar, Html(m))
141
141
+
let s = handle.await.unwrap();
142
142
+
format!("sup: {s}").into_response()
65
143
}
66
144
67
145
#[derive(Debug, Deserialize)]
···
74
152
jar: SignedCookieJar,
75
153
) -> (SignedCookieJar, Redirect) {
76
154
// if any existing session was active, clear it first
77
77
-
let jar = jar.remove("did");
155
155
+
let jar = jar.remove(DID_COOKIE_KEY);
78
156
79
157
let auth_url = authorize(&state.client, ¶ms.handle).await;
80
158
(jar, Redirect::to(&auth_url))
···
89
167
panic!("failed to do client callback");
90
168
};
91
169
let did = oauth_session.did().await.expect("a did to be present");
92
92
-
let cookie = Cookie::build(("did", did.to_string()))
170
170
+
let cookie = Cookie::build((DID_COOKIE_KEY, did.to_string()))
93
171
.http_only(true)
94
172
.secure(true)
95
173
.same_site(SameSite::None)
+96
who-am-i/templates/prompt-known.hbs
Reviewed
···
1
1
+
<!doctype html>
2
2
+
3
3
+
<style>
4
4
+
body {
5
5
+
color: #434;
6
6
+
font-family: 'Iowan Old Style', 'Palatino Linotype', 'URW Palladio L', P052, serif;
7
7
+
margin: 0;
8
8
+
min-height: 100vh;
9
9
+
padding: 0;
10
10
+
}
11
11
+
.wrap {
12
12
+
border: 2px solid #221828;
13
13
+
border-radius: 0.5rem;
14
14
+
box-sizing: border-box;
15
15
+
overflow: hidden;
16
16
+
display: flex;
17
17
+
flex-direction: column;
18
18
+
height: 100vh;
19
19
+
}
20
20
+
header {
21
21
+
background: #221828;
22
22
+
display: flex;
23
23
+
justify-content: space-between;
24
24
+
padding: 0 0.25rem;
25
25
+
color: #c9b;
26
26
+
display: flex;
27
27
+
gap: 0.5rem;
28
28
+
align-items: baseline;
29
29
+
}
30
30
+
header > * {
31
31
+
flex-basis: 33%;
32
32
+
}
33
33
+
header > .title {
34
34
+
text-align: center;
35
35
+
}
36
36
+
header > a.micro {
37
37
+
text-decoration: none;
38
38
+
font-size: 0.8rem;
39
39
+
text-align: right;
40
40
+
opacity: 0.5;
41
41
+
}
42
42
+
header > a.micro:hover {
43
43
+
opacity: 1;
44
44
+
}
45
45
+
main {
46
46
+
padding: 0.25rem 0.5rem;
47
47
+
background: #ccc;
48
48
+
flex-grow: 1;
49
49
+
}
50
50
+
p {
51
51
+
margin: 0.5rem 0;
52
52
+
}
53
53
+
</style>
54
54
+
55
55
+
<div class="wrap">
56
56
+
<header>
57
57
+
<div class="empty"></div>
58
58
+
<code class="title" style="font-family: monospace;"
59
59
+
>who-am-i</code>
60
60
+
<a href="https://microcosm.blue" target="_blank" class="micro"
61
61
+
><span style="color: #f396a9">m</span
62
62
+
><span style="color: #f49c5c">i</span
63
63
+
><span style="color: #c7b04c">c</span
64
64
+
><span style="color: #92be4c">r</span
65
65
+
><span style="color: #4ec688">o</span
66
66
+
><span style="color: #51c2b6">c</span
67
67
+
><span style="color: #54bed7">o</span
68
68
+
><span style="color: #8fb1f1">s</span
69
69
+
><span style="color: #ce9df1">m</span
70
70
+
></a>
71
71
+
</header>
72
72
+
73
73
+
<main>
74
74
+
<p>Share your identity with {{ parent_host }}?</p>
75
75
+
<div id="user-info">Loading…</div>
76
76
+
</main>
77
77
+
</div>
78
78
+
79
79
+
80
80
+
<script>
81
81
+
const infoEl = document.getElementById('user-info');
82
82
+
var DID = {{{json did}}};
83
83
+
let user_info = new URL('/user-info', window.location);
84
84
+
user_info.searchParams.set('fetch-key', {{{json fetch_key}}});
85
85
+
fetch(user_info).then(
86
86
+
info => {
87
87
+
infoEl.textContent = 'yay';
88
88
+
console.log(info);
89
89
+
},
90
90
+
err => {
91
91
+
infoEl.textContent = 'ohno';
92
92
+
console.error(err);
93
93
+
},
94
94
+
);
95
95
+
96
96
+
</script>