1use anyhow::{anyhow, Result};
2use serde::{Deserialize, Serialize};
3use sha2::{Digest, Sha256};
4use std::collections::HashMap;
5use std::sync::Arc;
6use parking_lot::RwLock;
7use uuid::Uuid;
8use chrono::{DateTime, Duration, Utc};
9
10#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
12#[serde(rename_all = "lowercase")]
13pub enum Role {
14 Admin,
15 Developer,
16 Viewer,
17}
18
19#[derive(Debug, Clone, Serialize, Deserialize)]
21pub struct User {
22 pub id: String,
23 pub username: String,
24 #[serde(skip_serializing)]
25 pub password_hash: String,
26 pub email: Option<String>,
27 pub role: Role,
28 pub created_at: DateTime<Utc>,
29 pub last_login: Option<DateTime<Utc>>,
30}
31
32impl User {
33 pub fn new(username: String, password: &str, role: Role) -> Self {
35 Self {
36 id: Uuid::new_v4().to_string(),
37 username,
38 password_hash: hash_password(password),
39 email: None,
40 role,
41 created_at: Utc::now(),
42 last_login: None,
43 }
44 }
45
46 pub fn verify_password(&self, password: &str) -> bool {
48 self.password_hash == hash_password(password)
49 }
50
51 pub fn has_permission(&self, required_role: &Role) -> bool {
53 match (&self.role, required_role) {
54 (Role::Admin, _) => true,
55 (Role::Developer, Role::Developer | Role::Viewer) => true,
56 (Role::Viewer, Role::Viewer) => true,
57 _ => false,
58 }
59 }
60}
61
62#[derive(Debug, Clone, Serialize, Deserialize)]
64pub struct Session {
65 pub token: String,
66 pub user_id: String,
67 pub username: String,
68 pub role: Role,
69 pub created_at: DateTime<Utc>,
70 pub expires_at: DateTime<Utc>,
71}
72
73impl Session {
74 pub fn new(user: &User, duration_hours: i64) -> Self {
76 let now = Utc::now();
77 Self {
78 token: Uuid::new_v4().to_string(),
79 user_id: user.id.clone(),
80 username: user.username.clone(),
81 role: user.role.clone(),
82 created_at: now,
83 expires_at: now + Duration::hours(duration_hours),
84 }
85 }
86
87 pub fn is_expired(&self) -> bool {
89 Utc::now() > self.expires_at
90 }
91}
92
93pub struct AuthManager {
95 users: Arc<RwLock<HashMap<String, User>>>,
96 sessions: Arc<RwLock<HashMap<String, Session>>>,
97}
98
99impl AuthManager {
100 pub fn new() -> Self {
102 let mut users = HashMap::new();
103
104 let admin = User::new("admin".to_string(), "admin123", Role::Admin);
106 users.insert(admin.username.clone(), admin);
107
108 Self {
109 users: Arc::new(RwLock::new(users)),
110 sessions: Arc::new(RwLock::new(HashMap::new())),
111 }
112 }
113
114 pub fn register(&self, username: String, password: &str, role: Role) -> Result<User> {
116 let mut users = self.users.write();
117
118 if users.contains_key(&username) {
119 return Err(anyhow!("Username already exists"));
120 }
121
122 let user = User::new(username.clone(), password, role);
123 users.insert(username, user.clone());
124
125 Ok(user)
126 }
127
128 pub fn login(&self, username: &str, password: &str) -> Result<Session> {
130 let mut users = self.users.write();
131
132 let user = users
133 .get_mut(username)
134 .ok_or_else(|| anyhow!("Invalid username or password"))?;
135
136 if !user.verify_password(password) {
137 return Err(anyhow!("Invalid username or password"));
138 }
139
140 user.last_login = Some(Utc::now());
142
143 let session = Session::new(user, 24);
145
146 let mut sessions = self.sessions.write();
147 sessions.insert(session.token.clone(), session.clone());
148
149 Ok(session)
150 }
151
152 pub fn validate_token(&self, token: &str) -> Result<Session> {
154 let mut sessions = self.sessions.write();
155
156 let session = sessions
157 .get(token)
158 .ok_or_else(|| anyhow!("Invalid or expired session"))?;
159
160 if session.is_expired() {
161 sessions.remove(token);
162 return Err(anyhow!("Session expired"));
163 }
164
165 Ok(session.clone())
166 }
167
168 pub fn logout(&self, token: &str) -> Result<()> {
170 let mut sessions = self.sessions.write();
171 sessions.remove(token);
172 Ok(())
173 }
174
175 pub fn get_user(&self, username: &str) -> Option<User> {
177 let users = self.users.read();
178 users.get(username).cloned()
179 }
180
181 pub fn list_users(&self) -> Vec<User> {
183 let users = self.users.read();
184 users.values().cloned().collect()
185 }
186
187 pub fn update_password(&self, username: &str, old_password: &str, new_password: &str) -> Result<()> {
189 let mut users = self.users.write();
190
191 let user = users
192 .get_mut(username)
193 .ok_or_else(|| anyhow!("User not found"))?;
194
195 if !user.verify_password(old_password) {
196 return Err(anyhow!("Invalid current password"));
197 }
198
199 user.password_hash = hash_password(new_password);
200 Ok(())
201 }
202
203 pub fn delete_user(&self, username: &str) -> Result<()> {
205 let mut users = self.users.write();
206 users.remove(username).ok_or_else(|| anyhow!("User not found"))?;
207 Ok(())
208 }
209
210 pub fn clean_expired_sessions(&self) {
212 let mut sessions = self.sessions.write();
213 sessions.retain(|_, session| !session.is_expired());
214 }
215}
216
217impl Default for AuthManager {
218 fn default() -> Self {
219 Self::new()
220 }
221}
222
223fn hash_password(password: &str) -> String {
225 let mut hasher = Sha256::new();
226 hasher.update(password.as_bytes());
227 format!("{:x}", hasher.finalize())
228}
229
230#[derive(Debug, Deserialize)]
232pub struct LoginRequest {
233 pub username: String,
234 pub password: String,
235}
236
237#[derive(Debug, Serialize)]
239pub struct LoginResponse {
240 pub token: String,
241 pub username: String,
242 pub role: Role,
243 pub expires_at: DateTime<Utc>,
244}
245
246#[derive(Debug, Deserialize)]
248pub struct CreateUserRequest {
249 pub username: String,
250 pub password: String,
251 pub role: Role,
252 pub email: Option<String>,
253}
254
255#[derive(Debug, Deserialize)]
257pub struct ChangePasswordRequest {
258 pub old_password: String,
259 pub new_password: String,
260}