mirror of
https://tangled.org/tranquil.farm/tranquil-pds
synced 2026-09-11 04:36:05 +00:00
Age assurance override env var
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
use crate::auth::{extract_bearer_token_from_header, validate_bearer_token};
|
||||
use crate::state::AppState;
|
||||
use axum::{
|
||||
Json,
|
||||
body::Bytes,
|
||||
extract::{Path, RawQuery, State},
|
||||
http::{HeaderMap, Method, StatusCode},
|
||||
response::{IntoResponse, Response},
|
||||
};
|
||||
use serde_json::json;
|
||||
|
||||
pub async fn get_state(
|
||||
State(state): State<AppState>,
|
||||
headers: HeaderMap,
|
||||
RawQuery(query): RawQuery,
|
||||
) -> Response {
|
||||
if std::env::var("PDS_AGE_ASSURANCE_OVERRIDE").is_err() {
|
||||
return proxy_to_appview(state, headers, "app.bsky.ageassurance.getState", query).await;
|
||||
}
|
||||
|
||||
let created_at = get_account_created_at(&state, &headers).await;
|
||||
let now = chrono::Utc::now().to_rfc3339();
|
||||
|
||||
(
|
||||
StatusCode::OK,
|
||||
Json(json!({
|
||||
"state": {
|
||||
"status": "assured",
|
||||
"access": "full",
|
||||
"lastInitiatedAt": now
|
||||
},
|
||||
"metadata": {
|
||||
"accountCreatedAt": created_at
|
||||
}
|
||||
})),
|
||||
)
|
||||
.into_response()
|
||||
}
|
||||
|
||||
pub async fn get_age_assurance_state(
|
||||
State(state): State<AppState>,
|
||||
headers: HeaderMap,
|
||||
RawQuery(query): RawQuery,
|
||||
) -> Response {
|
||||
if std::env::var("PDS_AGE_ASSURANCE_OVERRIDE").is_err() {
|
||||
return proxy_to_appview(
|
||||
state,
|
||||
headers,
|
||||
"app.bsky.unspecced.getAgeAssuranceState",
|
||||
query,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
(StatusCode::OK, Json(json!({"status": "assured"}))).into_response()
|
||||
}
|
||||
|
||||
async fn get_account_created_at(state: &AppState, headers: &HeaderMap) -> Option<String> {
|
||||
let auth_header = headers.get("Authorization").and_then(|h| h.to_str().ok());
|
||||
tracing::debug!(?auth_header, "age assurance: extracting token");
|
||||
|
||||
let token = extract_bearer_token_from_header(auth_header)?;
|
||||
tracing::debug!("age assurance: got token, validating");
|
||||
|
||||
let auth_user = match validate_bearer_token(&state.db, &token).await {
|
||||
Ok(user) => {
|
||||
tracing::debug!(did = %user.did, "age assurance: validated user");
|
||||
user
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::warn!(?e, "age assurance: token validation failed");
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
let row = match sqlx::query!("SELECT created_at FROM users WHERE did = $1", auth_user.did)
|
||||
.fetch_optional(&state.db)
|
||||
.await
|
||||
{
|
||||
Ok(r) => {
|
||||
tracing::debug!(?r, "age assurance: query result");
|
||||
r
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::warn!(?e, "age assurance: query failed");
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
row.map(|r| r.created_at.to_rfc3339())
|
||||
}
|
||||
|
||||
async fn proxy_to_appview(
|
||||
state: AppState,
|
||||
headers: HeaderMap,
|
||||
method: &str,
|
||||
query: Option<String>,
|
||||
) -> Response {
|
||||
if headers.get("atproto-proxy").is_none() {
|
||||
return (
|
||||
StatusCode::BAD_REQUEST,
|
||||
Json(json!({
|
||||
"error": "InvalidRequest",
|
||||
"message": "Missing required atproto-proxy header"
|
||||
})),
|
||||
)
|
||||
.into_response();
|
||||
}
|
||||
|
||||
crate::api::proxy::proxy_handler(
|
||||
State(state),
|
||||
Path(method.to_string()),
|
||||
Method::GET,
|
||||
headers,
|
||||
RawQuery(query),
|
||||
Bytes::new(),
|
||||
)
|
||||
.await
|
||||
}
|
||||
@@ -986,6 +986,24 @@ pub async fn create_account(
|
||||
.into_response();
|
||||
}
|
||||
}
|
||||
if std::env::var("PDS_AGE_ASSURANCE_OVERRIDE").is_ok() {
|
||||
let birthdate_pref = json!({
|
||||
"$type": "app.bsky.actor.defs#personalDetailsPref",
|
||||
"birthDate": "1998-05-06T00:00:00.000Z"
|
||||
});
|
||||
if let Err(e) = sqlx::query!(
|
||||
"INSERT INTO account_preferences (user_id, name, value_json) VALUES ($1, $2, $3)
|
||||
ON CONFLICT (user_id, name) DO NOTHING",
|
||||
user_id,
|
||||
"app.bsky.actor.defs#personalDetailsPref",
|
||||
birthdate_pref
|
||||
)
|
||||
.execute(&mut *tx)
|
||||
.await
|
||||
{
|
||||
warn!("Failed to set default birthdate preference: {:?}", e);
|
||||
}
|
||||
}
|
||||
if let Err(e) = tx.commit().await {
|
||||
error!("Error committing transaction: {:?}", e);
|
||||
return (
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
pub mod actor;
|
||||
pub mod admin;
|
||||
pub mod age_assurance;
|
||||
pub mod delegation;
|
||||
pub mod error;
|
||||
pub mod identity;
|
||||
|
||||
@@ -478,6 +478,27 @@ pub async fn import_repo(
|
||||
{
|
||||
warn!("Failed to sequence import event: {:?}", e);
|
||||
}
|
||||
if std::env::var("PDS_AGE_ASSURANCE_OVERRIDE").is_ok() {
|
||||
let birthdate_pref = json!({
|
||||
"$type": "app.bsky.actor.defs#personalDetailsPref",
|
||||
"birthDate": "1998-05-06T00:00:00.000Z"
|
||||
});
|
||||
if let Err(e) = sqlx::query!(
|
||||
"INSERT INTO account_preferences (user_id, name, value_json) VALUES ($1, $2, $3)
|
||||
ON CONFLICT (user_id, name) DO NOTHING",
|
||||
user_id,
|
||||
"app.bsky.actor.defs#personalDetailsPref",
|
||||
birthdate_pref
|
||||
)
|
||||
.execute(&state.db)
|
||||
.await
|
||||
{
|
||||
warn!(
|
||||
"Failed to set default birthdate preference for migrated user: {:?}",
|
||||
e
|
||||
);
|
||||
}
|
||||
}
|
||||
(StatusCode::OK, Json(json!({}))).into_response()
|
||||
}
|
||||
Err(ImportError::SizeLimitExceeded) => (
|
||||
|
||||
@@ -706,6 +706,25 @@ pub async fn create_passkey_account(
|
||||
.await;
|
||||
}
|
||||
|
||||
if std::env::var("PDS_AGE_ASSURANCE_OVERRIDE").is_ok() {
|
||||
let birthdate_pref = json!({
|
||||
"$type": "app.bsky.actor.defs#personalDetailsPref",
|
||||
"birthDate": "1998-05-06T00:00:00.000Z"
|
||||
});
|
||||
if let Err(e) = sqlx::query!(
|
||||
"INSERT INTO account_preferences (user_id, name, value_json) VALUES ($1, $2, $3)
|
||||
ON CONFLICT (user_id, name) DO NOTHING",
|
||||
user_id,
|
||||
"app.bsky.actor.defs#personalDetailsPref",
|
||||
birthdate_pref
|
||||
)
|
||||
.execute(&mut *tx)
|
||||
.await
|
||||
{
|
||||
warn!("Failed to set default birthdate preference: {:?}", e);
|
||||
}
|
||||
}
|
||||
|
||||
if let Err(e) = tx.commit().await {
|
||||
error!("Error committing transaction: {:?}", e);
|
||||
return (
|
||||
|
||||
@@ -28,6 +28,7 @@ pub struct AuditLogEntry {
|
||||
pub created_at: DateTime<Utc>,
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub async fn log_delegation_action(
|
||||
pool: &PgPool,
|
||||
delegated_did: &str,
|
||||
|
||||
@@ -626,6 +626,14 @@ pub fn app(state: AppState) -> Router {
|
||||
"/xrpc/com.tranquil.delegation.createDelegatedAccount",
|
||||
post(api::delegation::create_delegated_account),
|
||||
)
|
||||
.route(
|
||||
"/xrpc/app.bsky.ageassurance.getState",
|
||||
get(api::age_assurance::get_state),
|
||||
)
|
||||
.route(
|
||||
"/xrpc/app.bsky.unspecced.getAgeAssuranceState",
|
||||
get(api::age_assurance::get_age_assurance_state),
|
||||
)
|
||||
.route("/xrpc/{*method}", any(api::proxy::proxy_handler))
|
||||
.layer(DefaultBodyLimit::max(util::get_max_blob_size()))
|
||||
.layer(middleware::from_fn(metrics::metrics_middleware))
|
||||
|
||||
Reference in New Issue
Block a user