rustical_frontend/nextcloud_login/
mod.rs1use 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}