Skip to main content

server_watchdog/infrastructure/config/
auth.rs

1use std::error::Error;
2use std::sync::Arc;
3use async_trait::async_trait;
4use crate::application::config::AuthUseCase;
5use crate::domain::chat::{Chat, ChatList, ChatMap};
6use crate::domain::config::Config;
7use crate::domain::file_accessor::FileAccessor;
8
9pub struct AuthAdapter {
10    password: Option<String>,
11    chat_map: Option<ChatMap>,
12    config_file_accessor: Arc<dyn FileAccessor<Config> + Send + Sync>,
13    chat_list_file_accessor: Arc<dyn FileAccessor<ChatList> + Send + Sync>
14}
15
16impl AuthAdapter {
17    pub fn new(
18        config_file_accessor: Arc<dyn FileAccessor<Config> + Send + Sync>,
19        chat_list_file_accessor: Arc<dyn FileAccessor<ChatList> + Send + Sync>
20    ) -> Self {
21        Self {
22            password: None,
23            chat_map: None,
24            config_file_accessor,
25            chat_list_file_accessor
26        }
27    }
28
29    pub async fn init(&mut self) {
30        let config = self.config_file_accessor.read().await
31            .unwrap();
32        self.password = config.password;
33    }
34
35    async fn get_chat_map(&mut self) -> Result<&ChatMap, Box<dyn Error + Send + Sync>> {
36        if self.chat_map.is_none() {
37            let list = self.chat_list_file_accessor.read().await?;
38            self.chat_map = Some(ChatMap::from(list));
39        }
40
41        Ok(self.chat_map.as_ref().unwrap())
42    }
43}
44
45#[async_trait]
46impl AuthUseCase for AuthAdapter {
47    async fn set_password(&self, password: Option<String>) -> Result<(), Box<dyn Error + Send + Sync>> {
48        let mut config = self.config_file_accessor.read().await?;
49        config.password = password;
50        self.config_file_accessor.write(&config).await?;
51        Ok(())
52    }
53
54    async fn validate_password(&mut self, password: String) -> bool {
55        let config_password = self.password.as_ref().expect("Password is not defined").as_str();
56        config_password.eq(password.as_str())
57    }
58
59    async fn register(&mut self, client_name: String, identity: String) -> Result<(), Box<dyn Error + Send + Sync>> {
60        let mut chat_list = self.chat_list_file_accessor.read()
61            .await?;
62        
63        // Check if the entry already exists to make registration idempotent
64        let already_exists = chat_list.chats.iter().any(|chat| {
65            chat.client_name == client_name && chat.identity == identity
66        });
67        
68        if !already_exists {
69            chat_list.chats.push(Chat::new(client_name, identity));
70            self.chat_list_file_accessor.write(&chat_list).await?;
71            self.chat_map = None;
72        }
73        
74        Ok(())
75    }
76
77    async fn authenticate(&mut self, client_name: String, identity: String) -> Option<String> {
78        let chat_map = match self.get_chat_map().await {
79            Ok(value) => value,
80            Err(_) => return None
81        };
82
83        let id = chat_map.get_id(client_name.as_str(), identity.as_str())?;
84        Some(String::from(id))
85    }
86
87    fn password_required(&self) -> bool {
88        self.password.is_some()
89    }
90}