rustical_frontend/nextcloud_login/
mod.rs

1use crate::unauthorized_handler;
2use axum::routing::{get, post};
3use axum::{Extension, Router, middleware};
4use chrono::{DateTime, Utc};
5use routes::{get_nextcloud_flow, post_nextcloud_flow, post_nextcloud_login, post_nextcloud_poll};
6use rustical_store::auth::AuthenticationProvider;
7use rustical_store::auth::middleware::AuthenticationLayer;
8use serde::{Deserialize, Serialize};
9use std::collections::HashMap;
10use std::sync::Arc;
11use tokio::sync::RwLock;
12mod routes;
13
14#[derive(Debug, Clone)]
15struct NextcloudFlow {
16    app_name: String,
17    created_at: DateTime<Utc>,
18    token: String,
19    response: Option<NextcloudSuccessResponse>,
20}
21
22#[derive(Debug, Clone, Deserialize, Serialize)]
23#[serde(rename_all = "camelCase")]
24struct NextcloudSuccessResponse {
25    server: String,
26    login_name: String,
27    app_password: String,
28}
29
30#[derive(Debug, Clone, Deserialize, Serialize)]
31#[serde(rename_all = "camelCase")]
32struct NextcloudLoginResponse {
33    poll: NextcloudLoginPoll,
34    login: String,
35}
36
37#[derive(Debug, Clone, Deserialize, Serialize)]
38#[serde(rename_all = "camelCase")]
39struct NextcloudLoginPoll {
40    token: String,
41    endpoint: String,
42}
43
44#[derive(Debug, Default)]
45pub struct NextcloudFlows {
46    flows: RwLock<HashMap<String, NextcloudFlow>>,
47}
48
49pub fn nextcloud_login_router<AP: AuthenticationProvider>(auth_provider: Arc<AP>) -> Router {
50    let nextcloud_flows = Arc::new(NextcloudFlows::default());
51
52    Router::new()
53        .route("/poll/{flow}", post(post_nextcloud_poll::<AP>))
54        .route(
55            "/flow/{flow}",
56            get(get_nextcloud_flow).post(post_nextcloud_flow),
57        )
58        .route("/", post(post_nextcloud_login))
59        .layer(Extension(nextcloud_flows))
60        .layer(Extension(auth_provider.clone()))
61        .layer(AuthenticationLayer::new(auth_provider))
62        .layer(middleware::from_fn(unauthorized_handler))
63}