libspmg 0.2.1

Secure password manager library
Documentation



pub mod vault {
    pub mod lock;
    pub mod genpwd;
}

use vault::lock::Lock;

use std::path::PathBuf;

use std::sync::OnceLock;
use std::process;

use std::io::ErrorKind;
use std::sync::Arc;

use libeipc::EIPC_Server;

use base64::{encode, decode};

use std::sync::Mutex;

use crate::config::Config;

static LOCK: OnceLock<Mutex<Lock>> = OnceLock::new();

pub struct SPMGD {
    pub running: bool,
    store: std::collections::HashMap<String, String>,
}

impl SPMGD {
    pub fn new(config: Config) -> Self {
        let cfg_rc = Arc::new(config);

        std::fs::create_dir_all(&cfg_rc.spmg_path).unwrap();

        let spmg_path = PathBuf::from(cfg_rc.spmg_path.clone());
        if LOCK.set(Mutex::new(Lock::new(cfg_rc.clone(), spmg_path.join("pwds.lock")))).is_err() {
            eprintln!("LOCK is already initialized!");
        }

        let socket_path = format!("{}/socket", cfg_rc.spmg_path);
        let mut unix_socket_listener = EIPC_Server::new(&socket_path, cfg_rc.hkdf_salt.clone());

        unix_socket_listener.set_handler("init", Box::new(|args: &str, ppid: u32| -> String {
            println!("Creating a new lock!");
            if let Some(lock) = LOCK.get() {
                let mut lock = lock.lock().unwrap();
                lock.init(ppid, args);
            }
            String::from("OK")
        }));

        unix_socket_listener.set_handler("get-cached", Box::new(|args: &str, ppid: u32| -> String {
            if let Some(lock) = LOCK.get() {
                let mut lock = lock.lock().unwrap();
                if let Ok(key) = lock.get_cached_key(ppid) {
                    encode(key)
                } else {
                    String::from("NONE")
                }
            } else {
                String::from("NOLOCK")
            }
        }));

        unix_socket_listener.set_handler("clear-cache", Box::new(|args: &str, ppid: u32| -> String {
            if let Some(lock) = LOCK.get() {
                let mut lock = lock.lock().unwrap();
                match lock.clear_cache(ppid) {
                    Ok(result) => {
                        result
                    }
                    Err(err) => {
                        eprintln!("{}", err);
                        String::from("NOT-CACHED")
                    }
                }
            } else {
                String::from("NOLOCK")
            }
        }));

        unix_socket_listener.set_handler("cache-expiration", Box::new(|args: &str, ppid: u32| -> String {
            if let Some(lock) = LOCK.get() {
                let mut lock = lock.lock().unwrap();
                if let Ok(cache_expiration) = lock.get_cache_expiration(ppid) {
                    cache_expiration.to_string()
                } else {
                    String::from("NONE")
                }
            } else {
                String::from("NOLOCK")
            }
        }));

        unix_socket_listener.set_handler("add", Box::new(|arg_str: &str, ppid: u32| -> String {
            let args: Vec<&str> = arg_str.split_whitespace().collect();

            let mut pwd: Option<String> = None;
            if let Some(lock) = LOCK.get() {
                let mut lock = lock.lock().unwrap();
                let add_result = lock.add(ppid, args[0], args[1], args[2]);
                match add_result {
                    Ok(got_pwd) => {
                        String::from("OK")
                    },
                    Err(ref e) if e.kind() == ErrorKind::InvalidData => {
                        String::from("ERR UNAUTH")
                    },
                    Err(ref e) if e.kind() == ErrorKind::AlreadyExists => {
                        String::from("ERR EXISTS")
                    },
                    Err(ref e) if e.kind() == ErrorKind::NotConnected => {
                        String::from("ERR NOLOCK")
                    },
                    Err(e) => {
                        String::from("ERR OR")
                    }
                }
            } else {
                String::from("NOLOCK")
            }
        }));

        unix_socket_listener.set_handler("new", Box::new(|args: &str, ppid: u32| -> String {
            String::from("CREATED")
        }));

        unix_socket_listener.set_handler("get", Box::new(|arg_str: &str, ppid: u32| -> String {
            let args: Vec<&str> = arg_str.split_whitespace().collect();

            let mut pwd: Option<String> = None;
            if let Some(lock) = LOCK.get() {
                let mut lock = lock.lock().unwrap();
                let get_result = lock.get(ppid, args[0], args[1]);
                match get_result {
                    Ok(got_pwd) => {
                        got_pwd
                    },
                    Err(ref e) if e.kind() == ErrorKind::InvalidData => {
                        String::from("ERR UNAUTH")
                    },
                    Err(ref e) if e.kind() == ErrorKind::NotFound => {
                        String::from("ERR NOTFOUND")
                    },
                    Err(ref e) if e.kind() == ErrorKind::NotConnected => {
                        String::from("ERR NOLOCK")
                    },
                    Err(e) => {
                        String::from("ERR OR")
                    }
                }
            } else {
                String::from("NOLOCK")
            }
        }));


        unix_socket_listener.set_handler("kill", Box::new(|args: &str, ppid: u32| -> String {
            process::exit(0);
        }));

        unix_socket_listener.open();

        Self {
            running: false,
            store: std::collections::HashMap::new(),
        }
    }
}