/* ** Copyright (C) 2021 KunoiSayami ** ** This file is part of cgit-simple-authentication and is released under ** the AGPL v3 License: https://www.gnu.org/licenses/agpl-3.0.txt ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU Affero General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU Affero General Public License for more details. ** ** You should have received a copy of the GNU Affero General Public License ** along with this program. If not, see . */ use sha2::Digest; use anyhow::Result; use url::form_urlencoded; use std::borrow::Cow; use std::path::Path; use std::fs::read_to_string; use std::convert::TryFrom; const DEFAULT_CONFIG_LOCATION: &str = "/etc/cgitrc"; const DEFAULT_COOKIE_TTL: usize = 1200; const DEFAULT_DATABASE_LOCATION: &str = "/etc/cgit/auth.db"; #[derive(Debug, Clone)] pub struct Config { pub cookie_ttl: usize, database: String, } impl Default for Config { fn default() -> Self { Self { cookie_ttl: DEFAULT_COOKIE_TTL, database: DEFAULT_DATABASE_LOCATION.to_string(), } } } impl Config { pub fn new() -> Self { Self::load_from_path(DEFAULT_CONFIG_LOCATION) } pub fn load_from_path>(path: P) -> Self { let file = read_to_string(path).unwrap_or_default(); let mut cookie_ttl: usize = DEFAULT_COOKIE_TTL; let mut database: &str = "/etc/cgit/auth.db"; for line in file.lines() { let line = line.trim(); if !line.contains('=') || !line.starts_with("cgit-simple-auth-") { continue } let (key, value) = if line.contains('#') { line.split_once('#').unwrap().0.split_once('=').unwrap() } else { line.split_once('=').unwrap() }; let key_name = key.split_once("auth-").unwrap().1; match key_name { "cookie-ttl" => cookie_ttl = usize::try_from(value).unwrap_or(DEFAULT_COOKIE_TTL), "database" => database = value, _ => {} } } Self { cookie_ttl, database: database.to_string() } } pub fn get_database_location(&self) -> &str { self.database.as_str() } } #[derive(Debug, Clone, Default)] pub struct FormData { user: String, password: String, hash: String, } impl FormData { pub fn new() -> Self { Self { ..Default::default()} } pub fn set_password(&mut self, password: String) { self.password = password; self.hash = Default::default(); } pub fn set_user(&mut self, user: String) { self.user = user } pub fn get_user(&self) -> &String { &self.user } pub fn get_password_sha256(&self) -> Result { let mut hasher = sha2::Sha256::new(); hasher.update(self.password.as_bytes()); Ok(format!("{:x}", hasher.finalize())) } #[allow(dead_code)] pub fn get_password_sha256_cache(&mut self) -> Result { if self.hash.len() == 0 { self.hash = self.get_password_sha256()?; } Ok(self.hash.clone()) } } impl From<&[u8]> for FormData { fn from(input: &[u8]) -> Self { let fields = form_urlencoded::parse(input); let mut data = Self::new(); for f in fields { match f.0 { Cow::Borrowed("username") => { data.set_user(f.1.to_string()); } Cow::Borrowed("password") => { data.set_password(f.1.to_string()); data.get_password_sha256_cache().unwrap(); } _ => {} } } data } } impl From<&String> for FormData { fn from(s: &String) -> Self { Self::from(s.as_bytes()) } } impl From for FormData { fn from(s: String) -> Self { Self::from(&s) } }