data_modelling_sdk/auth/
mod.rs

1//! Authentication types shared across all platforms
2//!
3//! These types are used by:
4//! - Web app (WASM) - via server functions
5//! - Desktop app - via local state and remote API client
6//! - API server - for session management
7
8use serde::{Deserialize, Serialize};
9
10/// Authentication mode
11///
12/// Determines how the application authenticates and where data is stored.
13///
14/// # Example
15///
16/// ```rust
17/// use data_modelling_sdk::auth::AuthMode;
18///
19/// // Web mode (GitHub SSO)
20/// let web_mode = AuthMode::Web;
21///
22/// // Online mode (remote API)
23/// let online_mode = AuthMode::Online {
24///     api_url: "https://api.example.com".to_string(),
25/// };
26///
27/// // Local mode (offline)
28/// let local_mode = AuthMode::Local;
29/// ```
30#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)]
31pub enum AuthMode {
32    /// Not yet selected (desktop/mobile only)
33    #[default]
34    None,
35    /// Web platform - GitHub SSO required
36    Web,
37    /// Local mode - works offline with local files
38    Local,
39    /// Online mode - connects to remote API server
40    Online { api_url: String },
41}
42
43/// GitHub email information
44#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
45pub struct GitHubEmail {
46    pub email: String,
47    pub verified: bool,
48    pub primary: bool,
49}
50
51/// Current authentication state
52///
53/// Tracks the current authentication status and available credentials.
54///
55/// # Example
56///
57/// ```rust
58/// use data_modelling_sdk::auth::{AuthState, AuthMode};
59///
60/// let state = AuthState {
61///     mode: AuthMode::Web,
62///     authenticated: true,
63///     email: Some("user@example.com".to_string()),
64///     available_emails: None,
65///     github_token: Some("token123".to_string()),
66///     api_url: None,
67///     auth_source: "web".to_string(),
68/// };
69/// ```
70#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
71pub struct AuthState {
72    /// Current authentication mode
73    pub mode: AuthMode,
74    /// Whether the user is currently authenticated
75    pub authenticated: bool,
76    /// Selected email address (if authenticated)
77    pub email: Option<String>,
78    /// Available GitHub emails (for selection during OAuth)
79    pub available_emails: Option<Vec<GitHubEmail>>,
80    /// GitHub OAuth token (if authenticated via GitHub)
81    pub github_token: Option<String>,
82    /// API URL (for online mode)
83    pub api_url: Option<String>,
84    /// Source of auth flow: "web", "desktop", or "mobile"
85    #[serde(default = "default_auth_source")]
86    pub auth_source: String,
87}
88
89fn default_auth_source() -> String {
90    "web".to_string()
91}
92
93impl Default for AuthState {
94    fn default() -> Self {
95        Self {
96            mode: AuthMode::None,
97            authenticated: false,
98            email: None,
99            available_emails: None,
100            github_token: None,
101            api_url: None,
102            auth_source: "web".to_string(),
103        }
104    }
105}
106
107/// OAuth initiation request
108#[derive(Debug, Clone, Serialize, Deserialize)]
109pub struct InitiateOAuthRequest {
110    pub redirect_uri: String,
111    pub source: String,
112}
113
114/// OAuth initiation response
115#[derive(Debug, Clone, Serialize, Deserialize)]
116pub struct InitiateOAuthResponse {
117    pub oauth_url: String,
118    pub state: String,
119}
120
121/// Email selection request
122#[derive(Debug, Clone, Serialize, Deserialize)]
123pub struct SelectEmailRequest {
124    pub email: String,
125}
126
127#[cfg(test)]
128mod tests {
129    use super::*;
130
131    #[test]
132    fn test_auth_mode_default() {
133        let mode = AuthMode::default();
134        assert_eq!(mode, AuthMode::None);
135    }
136
137    #[test]
138    fn test_auth_state_default() {
139        let state = AuthState::default();
140        assert!(!state.authenticated);
141        assert_eq!(state.mode, AuthMode::None);
142        assert_eq!(state.auth_source, "web");
143    }
144
145    #[test]
146    fn test_auth_state_serialization() {
147        let state = AuthState {
148            mode: AuthMode::Online {
149                api_url: "http://localhost:8080".to_string(),
150            },
151            authenticated: true,
152            email: Some("test@example.com".to_string()),
153            available_emails: Some(vec![GitHubEmail {
154                email: "test@example.com".to_string(),
155                verified: true,
156                primary: true,
157            }]),
158            github_token: None,
159            api_url: Some("http://localhost:8080".to_string()),
160            auth_source: "desktop".to_string(),
161        };
162
163        let json = serde_json::to_string(&state).unwrap();
164        let parsed: AuthState = serde_json::from_str(&json).unwrap();
165        assert_eq!(state, parsed);
166    }
167}