this repo has no description
1use crate::api::ApiError;
2use crate::state::AppState;
3use axum::{
4 Json,
5 extract::State,
6 http::StatusCode,
7 response::{IntoResponse, Response},
8};
9use chrono::{Duration, Utc};
10use serde_json::json;
11use tracing::{error, info, warn};
12
13fn generate_plc_token() -> String {
14 crate::util::generate_token_code()
15}
16
17pub async fn request_plc_operation_signature(
18 State(state): State<AppState>,
19 headers: axum::http::HeaderMap,
20) -> Response {
21 let token = match crate::auth::extract_bearer_token_from_header(
22 headers.get("Authorization").and_then(|h| h.to_str().ok()),
23 ) {
24 Some(t) => t,
25 None => return ApiError::AuthenticationRequired.into_response(),
26 };
27 let auth_user =
28 match crate::auth::validate_bearer_token_allow_deactivated(&state.db, &token).await {
29 Ok(user) => user,
30 Err(e) => return ApiError::from(e).into_response(),
31 };
32 if let Err(e) = crate::auth::scope_check::check_identity_scope(
33 auth_user.is_oauth,
34 auth_user.scope.as_deref(),
35 crate::oauth::scopes::IdentityAttr::Wildcard,
36 ) {
37 return e;
38 }
39 let user = match sqlx::query!("SELECT id FROM users WHERE did = $1", auth_user.did)
40 .fetch_optional(&state.db)
41 .await
42 {
43 Ok(Some(row)) => row,
44 Ok(None) => return ApiError::AccountNotFound.into_response(),
45 Err(e) => {
46 error!("DB error: {:?}", e);
47 return ApiError::InternalError.into_response();
48 }
49 };
50 let _ = sqlx::query!(
51 "DELETE FROM plc_operation_tokens WHERE user_id = $1 OR expires_at < NOW()",
52 user.id
53 )
54 .execute(&state.db)
55 .await;
56 let plc_token = generate_plc_token();
57 let expires_at = Utc::now() + Duration::minutes(10);
58 if let Err(e) = sqlx::query!(
59 r#"
60 INSERT INTO plc_operation_tokens (user_id, token, expires_at)
61 VALUES ($1, $2, $3)
62 "#,
63 user.id,
64 plc_token,
65 expires_at
66 )
67 .execute(&state.db)
68 .await
69 {
70 error!("Failed to create PLC token: {:?}", e);
71 return (
72 StatusCode::INTERNAL_SERVER_ERROR,
73 Json(json!({"error": "InternalError"})),
74 )
75 .into_response();
76 }
77 let hostname = std::env::var("PDS_HOSTNAME").unwrap_or_else(|_| "localhost".to_string());
78 if let Err(e) =
79 crate::comms::enqueue_plc_operation(&state.db, user.id, &plc_token, &hostname).await
80 {
81 warn!("Failed to enqueue PLC operation notification: {:?}", e);
82 }
83 info!(
84 "PLC operation signature requested for user {}",
85 auth_user.did
86 );
87 (StatusCode::OK, Json(json!({}))).into_response()
88}