aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKunoiSayami <[email protected]>2021-05-06 17:32:17 +0800
committerKunoiSayami <[email protected]>2021-05-06 17:32:17 +0800
commitc86aab7847dd62492318e4c0d0a733e5a86a305b (patch)
treebcd5a79163bc4ef092757b611611e32117b11bbe
parentcbc7b3810bfe8fa750e566e7db2166ef8b7fcad1 (diff)
feat: Add configure parser
-rw-r--r--Cargo.lock2
-rw-r--r--Cargo.toml2
-rw-r--r--src/datastructures.rs89
-rw-r--r--src/main.rs57
4 files changed, 105 insertions, 45 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 9534dd3..317aa01 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -338,7 +338,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cgit-simple-authentication"
-version = "0.0.1"
+version = "0.0.2"
dependencies = [
"anyhow",
"clap",
diff --git a/Cargo.toml b/Cargo.toml
index a887ec4..49a3118 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "cgit-simple-authentication"
-version = "0.0.1"
+version = "0.0.2"
authors = ["KunoiSayami <[email protected]>"]
edition = "2018"
diff --git a/src/datastructures.rs b/src/datastructures.rs
index 7ee01a9..d253fcb 100644
--- a/src/datastructures.rs
+++ b/src/datastructures.rs
@@ -18,18 +18,69 @@
** along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
-
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;
-#[derive(Debug, Clone, Default)]
+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 {}
+ Self::load_from_path(DEFAULT_CONFIG_LOCATION)
+ }
+
+ pub fn load_from_path<P: AsRef<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()
}
}
@@ -72,4 +123,36 @@ impl FormData {
}
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<String> for FormData {
+ fn from(s: String) -> Self {
+ Self::from(&s)
+ }
} \ No newline at end of file
diff --git a/src/main.rs b/src/main.rs
index 81f09e2..95476dc 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -78,7 +78,7 @@ async fn verify_login(cfg: &Config, data: &FormData) -> Result<bool> {
// Processing the `authenticate-basic` called by cgit.
fn cmd_authenticate_basic(
matches: &ArgMatches,
- cfg: Option<Config>,
+ cfg: Config,
) -> Result<()> {
unimplemented!()
}
@@ -86,7 +86,7 @@ fn cmd_authenticate_basic(
// Processing the `authenticate-cookie` called by cgit.
async fn cmd_authenticate_cookie(
matches: &ArgMatches<'_>,
- cfg: Option<Config>,
+ cfg: Config,
) -> Result<bool> {
let cookies = matches.value_of("http-cookie").unwrap_or("");
@@ -94,6 +94,7 @@ async fn cmd_authenticate_cookie(
return Ok(false)
}
+ // TODO: use async connection to redis
let mut conn = redis::Client::open("redis://127.0.0.1/")?;
for cookie in cookies.split(';').map(|x| x.trim()) {
@@ -110,11 +111,9 @@ async fn cmd_authenticate_cookie(
}
-async fn cmd_init(cfg: Option<Config>) -> Result<()> {
+async fn cmd_init(cfg: Config) -> Result<()> {
-
- // TODO: read database location from configure file
- let mut conn = sqlx::SqliteConnection::connect("sqlite::memory:").await?;
+ let mut conn = sqlx::SqliteConnection::connect(cfg.get_database_location()).await?;
let rows = sqlx::query(r#"SELECT name FROM sqlite_master WHERE type='table' AND name=?"#)
.bind("auth_meta")
@@ -133,41 +132,21 @@ async fn cmd_init(cfg: Option<Config>) -> Result<()> {
// Processing the `authenticate-post` called by cgit.
async fn cmd_authenticate_post(
matches: &ArgMatches<'_>,
- cfg: Option<Config>,
+ cfg: Config,
) -> Result<()> {
- // Load configurations.
- let cfg = cfg.unwrap_or_default();
// Read stdin from upstream.
let mut buffer = String::new();
stdin().read_to_string(&mut buffer)?;
- let mut data = datastructures::FormData::new();
+ let data = datastructures::FormData::from(buffer);
// Parsing user posted form.
- let fields = form_urlencoded::parse(buffer.as_bytes());
- 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())
- }
- _ => {}
- }
- }
// Authenticated via gogs.
if verify_login(&cfg, &data).await.is_ok() {
- //let hash = data.hash();
- //let cgitauth = format!("{}:{}", hash, data.nonce);
- //let cgitauth_b64 = base64::encode_block(cgitauth.as_bytes());
- //let path = Path::new(&cfg.cache_dir).join(&hash);
- //data.to_file(path, true);
let cookie = rand_str(COOKIE_LENGTH);
- //let redis = redis_async::client::connect(&SocketAddr::from_str("127.0.0.1:5432").unwrap()).await?;
- //redis.
+ // TODO: same here
let mut conn = redis::Client::open("redis://127.0.0.1/")?;
- conn.set_ex::<_, &str, i32>(format!("cgit_auth_{}", cookie), "1", 600)?;
+ conn.set_ex::<_, &str, i32>(format!("cgit_auth_{}", cookie), "1", cfg.cookie_ttl)?;
let is_secure = matches
.value_of("https")
@@ -185,9 +164,7 @@ async fn cmd_authenticate_post(
println!("Location: {}", location);
println!(
"Set-Cookie: cgit_auth={}; Domain={}; Max-Age={}; HttpOnly{}",
- // TODO: use cookie ttl instead
- //cookie, domain, cfg.cookie_ttl, cookie_suffix
- cookie, domain, 600, cookie_suffix
+ cookie, domain, cfg.cookie_ttl, cookie_suffix
);
} else {
println!("Status: 403 Forbidden");
@@ -201,7 +178,7 @@ async fn cmd_authenticate_post(
// Processing the `body` called by cgit.
-async fn cmd_body(matches: &ArgMatches<'_>, _cfg: Option<Config>) {
+async fn cmd_body(matches: &ArgMatches<'_>, _cfg: Config) {
let source = include_str!("authentication_page.html");
let handlebars = Handlebars::new();
let meta = Meta {
@@ -214,7 +191,7 @@ async fn cmd_body(matches: &ArgMatches<'_>, _cfg: Option<Config>) {
}
// Processing the `body` called by cron.
-fn cmd_expire(_matches: &ArgMatches, cfg: Option<Config>) {
+fn cmd_expire(_matches: &ArgMatches, cfg: Config) {
unimplemented!();
}
@@ -222,21 +199,21 @@ fn cmd_expire(_matches: &ArgMatches, cfg: Option<Config>) {
async fn async_main(arg_matches: ArgMatches<'_>, cfg: Config) -> Result<i32>{
match arg_matches.subcommand() {
("authenticate-cookie", Some(matches)) => {
- if cmd_authenticate_cookie(matches, Some(cfg)).await.is_ok() {
+ if cmd_authenticate_cookie(matches, cfg).await.is_ok() {
return Ok(1)
}
}
("authenticate-post", Some(matches)) => {
- cmd_authenticate_post(matches, Some(cfg)).await.unwrap();
+ cmd_authenticate_post(matches, cfg).await.unwrap();
}
("body", Some(matches)) => {
- cmd_body(matches, Some(cfg)).await;
+ cmd_body(matches, cfg).await;
}
("expire", Some(matches)) => {
- cmd_expire(matches, Some(cfg));
+ cmd_expire(matches, cfg);
}
("init", Some(matches)) => {
- cmd_init(Some(cfg)).await?;
+ cmd_init(cfg).await?;
}
_ => {}
}