diff --git a/who-am-i/src/server.rs b/who-am-i/src/server.rs index aedbffa..64f682e 100644 --- a/who-am-i/src/server.rs +++ b/who-am-i/src/server.rs @@ -10,7 +10,7 @@ use axum::{ response::{IntoResponse, Json, Redirect, Response}, routing::{get, post}, }; -use axum_extra::extract::cookie::{Cookie, Key, SameSite, SignedCookieJar}; +use axum_extra::extract::cookie::{Cookie, Expiration, Key, SameSite, SignedCookieJar}; use axum_template::{RenderHtml, engine::Engine}; use handlebars::{Handlebars, handlebars_helper}; use jose_jwk::JwkSet; @@ -20,7 +20,7 @@ use serde::Deserialize; use serde_json::{Value, json}; use std::collections::HashSet; use std::sync::Arc; -use std::time::Duration; +use std::time::{Duration, SystemTime}; use tokio::net::TcpListener; use tokio_util::sync::CancellationToken; use url::Url; @@ -32,6 +32,7 @@ use crate::{ const FAVICON: &[u8] = include_bytes!("../static/favicon.ico"); const STYLE_CSS: &str = include_str!("../static/style.css"); +const HELLO_COOKIE_KEY: &str = "hello-who-am-i"; const DID_COOKIE_KEY: &str = "did"; const COOKIE_EXPIRATION: Duration = Duration::from_secs(30 * 86_400); @@ -113,6 +114,11 @@ pub async fn serve( .unwrap(); } +#[derive(Debug, Deserialize)] +struct HelloQuery { + auth_reload: Option, + auth_failed: Option, +} async fn hello( State(AppState { engine, @@ -121,8 +127,14 @@ async fn hello( oauth, .. }): State, + Query(params): Query, mut jar: SignedCookieJar, ) -> Response { + let is_auth_reload = params.auth_reload.is_some(); + let auth_failed = params.auth_failed.is_some(); + let no_cookie = jar.get(HELLO_COOKIE_KEY).is_none(); + jar = jar.add(hello_cookie()); + let info = if let Some(did) = jar.get(DID_COOKIE_KEY) { if let Ok(did) = Did::new(did.value_trimmed().to_string()) { // push cookie expiry @@ -138,13 +150,24 @@ async fn hello( json!({ "did": did, "fetch_key": fetch_key, + "is_auth_reload": is_auth_reload, + "auth_failed": auth_failed, + "no_cookie": no_cookie, }) } else { jar = jar.remove(DID_COOKIE_KEY); - json!({}) + json!({ + "is_auth_reload": is_auth_reload, + "auth_failed": auth_failed, + "no_cookie": no_cookie, + }) } } else { - json!({}) + json!({ + "is_auth_reload": is_auth_reload, + "auth_failed": auth_failed, + "no_cookie": no_cookie, + }) }; let frame_headers = [(CONTENT_SECURITY_POLICY, "frame-ancestors 'none'")]; (frame_headers, jar, RenderHtml("hello", engine, info)).into_response() @@ -162,12 +185,29 @@ async fn favicon() -> impl IntoResponse { ([(CONTENT_TYPE, "image/x-icon")], FAVICON) } +fn hello_cookie() -> Cookie<'static> { + Cookie::build((HELLO_COOKIE_KEY, "hiiii")) + .http_only(true) + .secure(true) + .same_site(SameSite::None) + .expires(Expiration::DateTime( + (SystemTime::now() + COOKIE_EXPIRATION).into(), + )) // wtf safari needs this to not be a session cookie?? + .max_age(COOKIE_EXPIRATION.try_into().unwrap()) + .path("/") + .into() +} + fn cookie(did: &Did) -> Cookie<'static> { Cookie::build((DID_COOKIE_KEY, did.to_string())) .http_only(true) .secure(true) .same_site(SameSite::None) + .expires(Expiration::DateTime( + (SystemTime::now() + COOKIE_EXPIRATION).into(), + )) // wtf safari needs this to not be a session cookie?? .max_age(COOKIE_EXPIRATION.try_into().unwrap()) + .path("/") .into() } diff --git a/who-am-i/static/style.css b/who-am-i/static/style.css index 89f0fa4..6d732dc 100644 --- a/who-am-i/static/style.css +++ b/who-am-i/static/style.css @@ -165,6 +165,13 @@ p.detail.no { color: #285; } +#need-storage { + font-size: 0.8rem; +} +.problem { + color: #a31; +} + #or { font-size: 0.8rem; text-align: center; @@ -182,3 +189,7 @@ input.handle { .hidden { display: none !important; } + +.hello-connect-plz { + margin: 1.667rem 0 0.667rem; +} diff --git a/who-am-i/templates/authorized.hbs b/who-am-i/templates/authorized.hbs index 7edacbc..9138f4c 100644 --- a/who-am-i/templates/authorized.hbs +++ b/who-am-i/templates/authorized.hbs @@ -1,6 +1,9 @@ + +great job! -

oh sick. hey {{ did }}. you can close this window now.

+

oauth success!

+

this window should automatically close itself (probably a bug if it hasn't)

diff --git a/who-am-i/templates/hello.hbs b/who-am-i/templates/hello.hbs index 5d62822..24cbad2 100644 --- a/who-am-i/templates/hello.hbs +++ b/who-am-i/templates/hello.hbs @@ -4,6 +4,7 @@

This is a little identity-verifying service for microcosm demos.

+

Only read access to your public data is required to connect: connecting does not grant any ability to modify your account or data.

{{#if did}} @@ -50,7 +51,8 @@ } catch (e) { err(e, 'failed to clear session, sorry'); } - window.location.reload(); + window.location.replace(location.pathname); + window.location.reload(); // backup, in case there is no query? }); })(); @@ -71,11 +73,50 @@ } {{else}} -

- No identity connected. -

+ +

Connect your handle

+ + {{#if is_auth_reload}} + {{#if no_cookie}} +

+ No identity connected. Your browser may be blocking access for connecting. +

+ {{else}} + {{#if auth_failed}} +

+ No identity connected. Connecting failed or was denied. +

+ {{else}} +

+ No identity connected. +

+ {{/if}} + {{/if}} + {{/if}} + +
+
+ + +
+
{{/if}} +
+ {{/inline}} {{#> base-full}}{{/base-full}} diff --git a/who-am-i/templates/prompt.hbs b/who-am-i/templates/prompt.hbs index 9e0278e..afdb713 100644 --- a/who-am-i/templates/prompt.hbs +++ b/who-am-i/templates/prompt.hbs @@ -27,6 +27,11 @@ + +