App password conf. vs ref

This commit is contained in:
lewis
2025-12-29 19:36:01 +02:00
parent 5aceed2ab3
commit 8cfc13fccc
9 changed files with 237 additions and 30 deletions
+27 -11
View File
@@ -232,7 +232,30 @@ pub async fn revoke_app_password(
if name.is_empty() {
return ApiError::InvalidRequest("name is required".into()).into_response();
}
match sqlx::query!(
let sessions_to_invalidate = sqlx::query_scalar!(
"SELECT access_jti FROM session_tokens WHERE did = $1 AND app_password_name = $2",
auth_user.did,
name
)
.fetch_all(&state.db)
.await
.unwrap_or_default();
if let Err(e) = sqlx::query!(
"DELETE FROM session_tokens WHERE did = $1 AND app_password_name = $2",
auth_user.did,
name
)
.execute(&state.db)
.await
{
error!("DB error revoking sessions for app password: {:?}", e);
return ApiError::InternalError.into_response();
}
for jti in &sessions_to_invalidate {
let cache_key = format!("auth:session:{}:{}", auth_user.did, jti);
let _ = state.cache.delete(&cache_key).await;
}
if let Err(e) = sqlx::query!(
"DELETE FROM app_passwords WHERE user_id = $1 AND name = $2",
user_id,
name
@@ -240,15 +263,8 @@ pub async fn revoke_app_password(
.execute(&state.db)
.await
{
Ok(r) => {
if r.rows_affected() == 0 {
return ApiError::AppPasswordNotFound.into_response();
}
Json(json!({})).into_response()
}
Err(e) => {
error!("DB error revoking app password: {:?}", e);
ApiError::InternalError.into_response()
}
error!("DB error revoking app password: {:?}", e);
return ApiError::InternalError.into_response();
}
Json(json!({})).into_response()
}
+13 -7
View File
@@ -35,17 +35,23 @@ pub async fn describe_server() -> impl IntoResponse {
let privacy_policy = std::env::var("PRIVACY_POLICY_URL").ok();
let terms_of_service = std::env::var("TERMS_OF_SERVICE_URL").ok();
let contact_email = std::env::var("CONTACT_EMAIL").ok();
let mut links = serde_json::Map::new();
if let Some(pp) = privacy_policy {
links.insert("privacyPolicy".to_string(), json!(pp));
}
if let Some(tos) = terms_of_service {
links.insert("termsOfService".to_string(), json!(tos));
}
let mut contact = serde_json::Map::new();
if let Some(email) = contact_email {
contact.insert("email".to_string(), json!(email));
}
Json(json!({
"availableUserDomains": domains,
"inviteCodeRequired": invite_code_required,
"did": format!("did:web:{}", pds_hostname),
"links": {
"privacyPolicy": privacy_policy,
"termsOfService": terms_of_service
},
"contact": {
"email": contact_email
},
"links": links,
"contact": contact,
"version": env!("CARGO_PKG_VERSION"),
"availableCommsChannels": get_available_comms_channels()
}))
+8 -6
View File
@@ -138,16 +138,16 @@ pub async fn create_session(
return ApiError::InternalError.into_response();
}
};
let (password_valid, app_password_scopes, app_password_controller) = if row
let (password_valid, app_password_name, app_password_scopes, app_password_controller) = if row
.password_hash
.as_ref()
.map(|h| verify(&input.password, h).unwrap_or(false))
.unwrap_or(false)
{
(true, None, None)
(true, None, None, None)
} else {
let app_passwords = sqlx::query!(
"SELECT password_hash, scopes, created_by_controller_did FROM app_passwords WHERE user_id = $1 ORDER BY created_at DESC LIMIT 20",
"SELECT name, password_hash, scopes, created_by_controller_did FROM app_passwords WHERE user_id = $1 ORDER BY created_at DESC LIMIT 20",
row.id
)
.fetch_all(&state.db)
@@ -159,10 +159,11 @@ pub async fn create_session(
match matched {
Some(app) => (
true,
Some(app.name.clone()),
app.scopes.clone(),
app.created_by_controller_did.clone(),
),
None => (false, None, None),
None => (false, None, None, None),
}
};
if !password_valid {
@@ -236,7 +237,7 @@ pub async fn create_session(
let did_resolver = state.did_resolver.clone();
let (insert_result, did_doc) = tokio::join!(
sqlx::query!(
"INSERT INTO session_tokens (did, access_jti, refresh_jti, access_expires_at, refresh_expires_at, legacy_login, mfa_verified, scope, controller_did) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)",
"INSERT INTO session_tokens (did, access_jti, refresh_jti, access_expires_at, refresh_expires_at, legacy_login, mfa_verified, scope, controller_did, app_password_name) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)",
row.did,
access_meta.jti,
refresh_meta.jti,
@@ -245,7 +246,8 @@ pub async fn create_session(
is_legacy_login,
false,
app_password_scopes,
app_password_controller
app_password_controller,
app_password_name
)
.execute(&state.db),
did_resolver.resolve_did_document(&did_for_doc)