aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKunoiSayami <[email protected]>2021-05-10 19:23:14 +0800
committerKunoiSayami <[email protected]>2021-05-10 19:23:14 +0800
commit096186b2ca129d83b1041a2a9226d5a7fba0226b (patch)
treeee9739a4c324626b8130b7a003cd0860947f160f
parentbaeb888db8a12181f38499560b30c0a84ec9982e (diff)
style(core): Address cargo fmt
-rw-r--r--Cargo.lock2
-rw-r--r--Cargo.toml2
-rw-r--r--src/database.rs2
-rw-r--r--src/datastructures.rs41
-rw-r--r--src/main.rs120
5 files changed, 99 insertions, 68 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 86bfaea..b9da333 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -377,7 +377,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cgit-simple-authentication"
-version = "0.3.0"
+version = "0.3.1"
dependencies = [
"anyhow",
"argon2",
diff --git a/Cargo.toml b/Cargo.toml
index b818819..633ecf1 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "cgit-simple-authentication"
-version = "0.3.0"
+version = "0.3.1"
authors = ["KunoiSayami <[email protected]>"]
edition = "2018"
diff --git a/src/database.rs b/src/database.rs
index eceec98..e620241 100644
--- a/src/database.rs
+++ b/src/database.rs
@@ -17,7 +17,7 @@
** You should have received a copy of the GNU Affero General Public License
** along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
-#[deprecated(since = "0.3.0", note = "Please use v2 instead")]
+#[deprecated(since = "0.3.0", note = "Please use v2 instead")]
#[allow(dead_code)]
pub mod v1 {
pub const CREATE_TABLES: &str = r#"
diff --git a/src/datastructures.rs b/src/datastructures.rs
index 0498f8f..7bdbab5 100644
--- a/src/datastructures.rs
+++ b/src/datastructures.rs
@@ -19,18 +19,18 @@
*/
use anyhow::Result;
-use std::borrow::Cow;
-use std::fs::read_to_string;
-use std::path::{Path, PathBuf};
-use url::form_urlencoded;
-use std::fmt::Formatter;
-use rand::Rng;
-use serde::{Serialize, Deserialize};
use argon2::{
password_hash::{PasswordHash, PasswordHasher, PasswordVerifier, SaltString},
- Argon2
+ Argon2,
};
+use rand::Rng;
use rand_core::OsRng;
+use serde::{Deserialize, Serialize};
+use std::borrow::Cow;
+use std::fmt::Formatter;
+use std::fs::read_to_string;
+use std::path::{Path, PathBuf};
+use url::form_urlencoded;
const DEFAULT_CONFIG_LOCATION: &str = "/etc/cgitrc";
const DEFAULT_COOKIE_TTL: u64 = 1200;
@@ -69,8 +69,6 @@ pub fn rand_str(len: usize) -> String {
password
}
-
-
#[derive(Debug, Clone)]
pub struct Config {
pub cookie_ttl: u64,
@@ -134,7 +132,7 @@ impl Config {
self.database.as_str()
}
-/* pub fn get_secret_warning(&self) -> &str {
+ /* pub fn get_secret_warning(&self) -> &str {
if self.secret.is_empty() {
r#"<span color="red">Warning: You should specify secret in your cgitrc file.</span>"#
} else if self.secret.len() < MINIMUM_SECRET_LENGTH {
@@ -173,7 +171,10 @@ impl FormData {
let argon2_alg = Argon2::default();
- Ok(argon2_alg.hash_password_simple(passwd, salt.as_ref()).unwrap().to_string())
+ Ok(argon2_alg
+ .hash_password_simple(passwd, salt.as_ref())
+ .unwrap()
+ .to_string())
}
pub fn set_password(&mut self, password: String) {
@@ -183,7 +184,9 @@ impl FormData {
pub fn verify_password(&self, password_hash: &PasswordHash) -> bool {
let argon2_alg = Argon2::default();
- argon2_alg.verify_password(self.password.as_bytes(), password_hash).is_ok()
+ argon2_alg
+ .verify_password(self.password.as_bytes(), password_hash)
+ .is_ok()
}
pub fn set_user(&mut self, user: String) {
@@ -285,13 +288,13 @@ impl Cookie {
let (timestamp, randint) = key.split_once("_").unwrap_or(("0", ""));
- cookie_self = Some(Self{
+ cookie_self = Some(Self {
timestamp: timestamp.parse()?,
randint: randint.parse()?,
user: user.trim().to_string(),
reversed: reversed.trim().to_string(),
});
- break
+ break;
}
}
Ok(cookie_self)
@@ -318,10 +321,12 @@ impl Cookie {
}
}
-
impl std::fmt::Display for Cookie {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
- let s = format!("{}_{}; {}; {}", self.timestamp, self.randint, self.user, self.reversed);
+ let s = format!(
+ "{}_{}; {}; {}",
+ self.timestamp, self.randint, self.user, self.reversed
+ );
write!(f, "{}", base64::encode(s))
}
}
@@ -370,4 +375,4 @@ impl CookieOrigin {
Ok(())
}
}
-*/ \ No newline at end of file
+*/
diff --git a/src/main.rs b/src/main.rs
index 6cd95ec..27594a5 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -21,8 +21,9 @@
mod database;
mod datastructures;
-use crate::datastructures::{Config, FormData, Cookie};
+use crate::datastructures::{Config, Cookie, FormData};
use anyhow::Result;
+use argon2::password_hash::PasswordHash;
use clap::{App, Arg, ArgMatches, SubCommand};
use handlebars::Handlebars;
use log4rs::append::file::FileAppender;
@@ -30,19 +31,14 @@ use log4rs::config::{Appender, Root};
use log4rs::encode::pattern::PatternEncoder;
use redis::AsyncCommands;
use serde::Serialize;
-use sqlx::{Connection, ConnectOptions, SqliteConnection};
+use sqlx::sqlite::SqliteConnectOptions;
+use sqlx::{ConnectOptions, Connection, SqliteConnection};
use std::env;
use std::io::{stdin, Read};
use std::result::Result::Ok;
-use tokio_stream::StreamExt as _;
-use argon2::{
- password_hash::{PasswordHash},
-};
use std::str::FromStr;
use tempdir::TempDir;
-use sqlx::sqlite::SqliteConnectOptions;
-
-
+use tokio_stream::StreamExt as _;
// Processing the `authenticate-cookie` called by cgit.
async fn cmd_authenticate_cookie(matches: &ArgMatches<'_>, cfg: Config) -> Result<bool> {
@@ -66,7 +62,10 @@ async fn cmd_authenticate_cookie(matches: &ArgMatches<'_>, cfg: Config) -> Resul
let mut conn = redis_conn.get_async_connection().await?;
if let Ok(Some(cookie)) = Cookie::load_from_request(cookies) {
- if let Ok(r) = conn.get::<_, String>(format!("cgit_auth_{}", cookie.get_key())).await{
+ if let Ok(r) = conn
+ .get::<_, String>(format!("cgit_auth_{}", cookie.get_key()))
+ .await
+ {
if cookie.eq_body(r.as_str()) {
return Ok(true);
}
@@ -104,26 +103,36 @@ async fn cmd_init(cfg: Config) -> Result<()> {
async fn verify_login(cfg: &Config, data: &FormData, redis_conn: redis::Client) -> Result<bool> {
// TODO: use timestamp to mark file diff
// or copy in init process
- std::fs::copy(cfg.get_database_location(), cfg.get_copied_database_location())?;
+ std::fs::copy(
+ cfg.get_database_location(),
+ cfg.get_copied_database_location(),
+ )?;
let mut rd = redis_conn.get_async_connection().await?;
- let mut conn = sqlx::sqlite::SqliteConnectOptions::from_str(cfg.get_copied_database_location().to_str().unwrap())?
- .journal_mode(sqlx::sqlite::SqliteJournalMode::Off)
- .log_statements(log::LevelFilter::Trace)
- .connect().await?;
+ let mut conn = sqlx::sqlite::SqliteConnectOptions::from_str(
+ cfg.get_copied_database_location().to_str().unwrap(),
+ )?
+ .journal_mode(sqlx::sqlite::SqliteJournalMode::Off)
+ .log_statements(log::LevelFilter::Trace)
+ .connect()
+ .await?;
- let (passwd_hash, uid) = sqlx::query_as::<_, (String, String)>(r#"SELECT "password", "uid" FROM "accounts" WHERE "user" = ?"#)
- .bind(data.get_user())
- .fetch_one(&mut conn)
- .await?;
+ let (passwd_hash, uid) = sqlx::query_as::<_, (String, String)>(
+ r#"SELECT "password", "uid" FROM "accounts" WHERE "user" = ?"#,
+ )
+ .bind(data.get_user())
+ .fetch_one(&mut conn)
+ .await?;
let key = format!("cgit_repo_{}", data.get_user());
if !rd.exists(&key).await? {
- if let Some((repos, )) = sqlx::query_as::<_, (String, )>(r#"SELECT "repos" FROM "repo" WHERE "uid" = ? "#)
- .bind(uid)
- .fetch_optional(&mut conn)
- .await? {
+ if let Some((repos,)) =
+ sqlx::query_as::<_, (String,)>(r#"SELECT "repos" FROM "repo" WHERE "uid" = ? "#)
+ .bind(uid)
+ .fetch_optional(&mut conn)
+ .await?
+ {
let iter = repos.split_whitespace().collect::<Vec<&str>>();
rd.sadd(&key, iter).await?;
}
@@ -141,7 +150,6 @@ async fn cmd_authenticate_post(matches: &ArgMatches<'_>, cfg: Config) -> Result<
stdin().read_to_string(&mut buffer)?;
//log::debug!("{}", buffer);
let data = datastructures::FormData::from(buffer);
- // Parsing user posted form.
let redis_conn = redis::Client::open("redis://127.0.0.1/")?;
@@ -192,7 +200,6 @@ pub struct Meta<'a> {
//custom_warning: &'a str,
}
-
// Processing the `body` called by cgit.
async fn cmd_body(matches: &ArgMatches<'_>, _cfg: Config) {
let source = include_str!("authentication_page.html");
@@ -216,11 +223,13 @@ async fn cmd_add_user(matches: &ArgMatches<'_>, cfg: Config) -> Result<()> {
}
if user.len() >= 20 {
- return Err(anyhow::Error::msg("Username length should less than 21"))
+ return Err(anyhow::Error::msg("Username length should less than 21"));
}
if !re.is_match(user) {
- return Err(anyhow::Error::msg("Username must pass regex check\"^\\w+$\""))
+ return Err(anyhow::Error::msg(
+ "Username must pass regex check\"^\\w+$\"",
+ ));
}
let mut conn = sqlx::SqliteConnection::connect(cfg.get_database_location()).await?;
@@ -275,7 +284,7 @@ async fn cmd_list_user(cfg: Config) -> Result<()> {
async fn cmd_delete_user(matches: &ArgMatches<'_>, cfg: Config) -> Result<()> {
let user = matches.value_of("user").unwrap_or("");
if user.is_empty() {
- return Err(anyhow::Error::msg("Please input a valid username"))
+ return Err(anyhow::Error::msg("Please input a valid username"));
}
let mut conn = sqlx::SqliteConnection::connect(cfg.get_database_location()).await?;
@@ -286,7 +295,7 @@ async fn cmd_delete_user(matches: &ArgMatches<'_>, cfg: Config) -> Result<()> {
.await?;
if items.is_empty() {
- return Err(anyhow::Error::msg(format!("User {} not found", user)))
+ return Err(anyhow::Error::msg(format!("User {} not found", user)));
}
sqlx::query(r#"DELETE FROM "accounts" WHERE "user" = ?"#)
@@ -301,7 +310,9 @@ async fn cmd_delete_user(matches: &ArgMatches<'_>, cfg: Config) -> Result<()> {
async fn cmd_reset_database(matches: &ArgMatches<'_>, cfg: Config) -> Result<()> {
if !matches.is_present("confirm") {
- return Err(anyhow::Error::msg("Please add --confirm argument to process reset"))
+ return Err(anyhow::Error::msg(
+ "Please add --confirm argument to process reset",
+ ));
}
let mut conn = SqliteConnection::connect(cfg.get_database_location()).await?;
@@ -320,7 +331,6 @@ async fn cmd_reset_database(matches: &ArgMatches<'_>, cfg: Config) -> Result<()>
}
async fn cmd_upgrade_database(cfg: Config) -> Result<()> {
-
let tmp_dir = TempDir::new("rolling")?;
let v1_path = tmp_dir.path().join("v1.db");
@@ -336,14 +346,15 @@ async fn cmd_upgrade_database(cfg: Config) -> Result<()> {
.connect()
.await?;
- let (v,) = sqlx::query_as::<_, (String,)>(r#"SELECT "value" FROM "auth_meta" WHERE "key" = 'version' "#)
- .fetch_optional(&mut origin_conn)
- .await?
- .unwrap();
+ let (v,) = sqlx::query_as::<_, (String,)>(
+ r#"SELECT "value" FROM "auth_meta" WHERE "key" = 'version' "#,
+ )
+ .fetch_optional(&mut origin_conn)
+ .await?
+ .unwrap();
#[allow(deprecated)]
if v.eq(database::previous::VERSION) {
-
let mut conn = SqliteConnection::connect(v2_path.as_path().to_str().unwrap()).await?;
sqlx::query(database::current::CREATE_TABLES)
@@ -369,7 +380,11 @@ async fn cmd_upgrade_database(cfg: Config) -> Result<()> {
.expect("Copy back to database location failure");
println!("Upgrade database successful");
} else {
- eprintln!("Got database version {} but {} required", v, database::previous::VERSION)
+ eprintln!(
+ "Got database version {} but {} required",
+ v,
+ database::previous::VERSION
+ )
}
drop(origin_conn);
tmp_dir.close()?;
@@ -417,7 +432,6 @@ async fn async_main(arg_matches: ArgMatches<'_>, cfg: Config) -> Result<i32> {
}
fn process_arguments(arguments: Option<Vec<&str>>) -> Result<()> {
-
// Sub-arguments for each command, see cgi defines.
let sub_args = &[
Arg::with_name("http-cookie").required(true), // 2
@@ -461,16 +475,16 @@ fn process_arguments(arguments: Option<Vec<&str>>) -> Result<()> {
.subcommand(
SubCommand::with_name("deluser")
.about("Delete user from database")
- .arg(Arg::with_name("user").required(true))
+ .arg(Arg::with_name("user").required(true)),
)
.subcommand(
SubCommand::with_name("reset")
.about("Reset database")
- .arg(Arg::with_name("confirm").long("confirm"))
+ .arg(Arg::with_name("confirm").long("confirm")),
)
.subcommand(
SubCommand::with_name("upgrade")
- .about("Upgrade database from v1(v0.1.x - v0.2.x) to v2(^v0.3.x)")
+ .about("Upgrade database from v1(v0.1.x - v0.2.x) to v2(^v0.3.x)"),
);
let matches = if let Some(args) = arguments {
@@ -479,7 +493,6 @@ fn process_arguments(arguments: Option<Vec<&str>>) -> Result<()> {
app.get_matches()
};
-
// Load filter configurations
let cfg = Config::new();
@@ -538,7 +551,7 @@ mod test {
fn test_argon2() {
use argon2::{
password_hash::{PasswordHasher, SaltString},
- Argon2
+ Argon2,
};
use rand_core::OsRng;
let passwd = b"hunter2";
@@ -547,14 +560,13 @@ mod test {
let argon2 = Argon2::default();
argon2.hash_password_simple(passwd, salt.as_ref()).unwrap();
-
}
#[test]
fn test_argon2_verify() {
use argon2::{
password_hash::{PasswordHash, PasswordVerifier},
- Argon2
+ Argon2,
};
let passwd = b"hunter2";
let parsed_hash = PasswordHash::new("$argon2id$v=19$m=4096,t=3,p=1$szYDnoQSVPmXq+RD2LneBw$fRETH//iCQuIX+SgjYPdZ9iIbM8gEy9fBjTJ/KFFJNM").unwrap();
@@ -566,7 +578,21 @@ mod test {
#[allow(dead_code)]
fn test_auth_post() {
use crate::process_arguments;
- process_arguments(Some(vec!["cgit-simple-authentication", "authenticate-post", "", "POST", "p=login", "https://git.example.com/?p=login", "/", "git.example.com", "", "", "login", "/?p=login", "/?p=login"])).unwrap();
+ process_arguments(Some(vec![
+ "cgit-simple-authentication",
+ "authenticate-post",
+ "",
+ "POST",
+ "p=login",
+ "https://git.example.com/?p=login",
+ "/",
+ "git.example.com",
+ "",
+ "",
+ "login",
+ "/?p=login",
+ "/?p=login",
+ ]))
+ .unwrap();
}
}
-