/*
** 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 anyhow::Result;
use sha2::Digest;
use std::borrow::Cow;
use std::fs::read_to_string;
use std::path::Path;
use url::form_urlencoded;
const DEFAULT_CONFIG_LOCATION: &str = "/etc/cgitrc";
const DEFAULT_COOKIE_TTL: u64 = 1200;
const DEFAULT_DATABASE_LOCATION: &str = "/etc/cgit/auth.db";
pub const CACHE_DIR: &str = "/var/cache/cgit";
#[derive(Debug, Clone)]
pub struct Config {
pub cookie_ttl: u64,
database: String,
//access_node: hashmap,
pub bypass_root: bool,
}
impl Default for Config {
fn default() -> Self {
Self {
cookie_ttl: DEFAULT_COOKIE_TTL,
database: DEFAULT_DATABASE_LOCATION.to_string(),
bypass_root: false,
}
}
}
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: u64 = DEFAULT_COOKIE_TTL;
let mut database: &str = "/etc/cgit/auth.db";
let mut bypass_root: bool = false;
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.trim();
match key_name {
"cookie-ttl" => cookie_ttl = value.parse().unwrap_or(DEFAULT_COOKIE_TTL),
"database" => database = value,
"bypass-root" => bypass_root = value.to_lowercase().eq("true"),
_ => {}
}
}
Self {
cookie_ttl,
database: database.to_string(),
bypass_root,
}
}
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 get_string_sha256_value(s: &str) -> Result {
let mut hasher = sha2::Sha256::new();
hasher.update(s.as_bytes());
Ok(format!("{:x}", hasher.finalize()))
}
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 {
Self::get_string_sha256_value(&self.password)
}
#[allow(dead_code)]
pub fn get_password_sha256_cache(&mut self) -> Result {
if self.hash.is_empty() {
self.hash = self.get_password_sha256()?;
}
Ok(self.hash.clone())
}
#[allow(dead_code)]
pub fn get_sha256_without_calc(&self) -> &String {
&self.hash
}
}
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)
}
}