diff options
| author | KunoiSayami <[email protected]> | 2021-05-15 02:38:31 +0800 |
|---|---|---|
| committer | KunoiSayami <[email protected]> | 2021-05-15 02:38:31 +0800 |
| commit | 8d68ac0b56fa6be0eb5215f346d513b9a2ef37b8 (patch) | |
| tree | fc0f0881a842759cc4fe8ac42abf3917bc85a72f /src/main.rs | |
| parent | 722d7da76380d8f3814f5f2a59e3ef14928b6203 (diff) | |
feat(core): Set protect policy default enabledv0.4.1
* fix(auth): Fix authenticate cookie failure in root page
Diffstat (limited to 'src/main.rs')
| -rw-r--r-- | src/main.rs | 148 |
1 files changed, 92 insertions, 56 deletions
diff --git a/src/main.rs b/src/main.rs index 7edd019..b422db1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -55,7 +55,6 @@ impl<R: BufRead, W: Write> IOModule<R, W> { //log::debug!("{}", buffer); let data = datastructures::FormData::from(buffer); - let ret = verify_login(&cfg, &data).await; if let Err(ref e) = ret { @@ -112,7 +111,7 @@ async fn cmd_authenticate_cookie(matches: &ArgMatches<'_>, cfg: Config) -> Resul bypass = true; } - if bypass || !cfg.check_repo_protect(repo){ + if bypass || (!repo.is_empty() && !cfg.check_repo_protect(repo)) { return Ok(true); } @@ -123,24 +122,23 @@ async fn cmd_authenticate_cookie(matches: &ArgMatches<'_>, cfg: Config) -> Resul let redis_conn = redis::Client::open("redis://127.0.0.1/")?; let mut conn = redis_conn.get_async_connection().await?; + let redis_key = format!("cgit_repo_{}", repo); if !repo.is_empty() { - let key = format!("cgit_repo_{}", repo); - if !conn.exists(&key).await? { + if !conn.exists(&redis_key).await? { let mut sql_conn = SqliteConnectOptions::from_str(cfg.get_database_location())? .read_only(true) .connect() .await?; - if let Some((users, )) = - sqlx::query_as::<_, (String, )>(r#"SELECT "users" FROM "repos" WHERE "repo" = ? "#) - .bind(repo) - .fetch_optional(&mut sql_conn) - .await? + if let Some((users,)) = + sqlx::query_as::<_, (String,)>(r#"SELECT "users" FROM "repos" WHERE "repo" = ? "#) + .bind(repo) + .fetch_optional(&mut sql_conn) + .await? { - let iter = users.split_whitespace().collect::<Vec<&str>>(); - conn.sadd(&key, iter).await?; + let users = users.split_whitespace().collect::<Vec<&str>>(); + conn.sadd(&redis_key, users).await?; } } - // TODO: redis repository ACL check should goes here } if let Ok(Some(cookie)) = Cookie::load_from_request(cookies) { @@ -149,7 +147,16 @@ async fn cmd_authenticate_cookie(matches: &ArgMatches<'_>, cfg: Config) -> Resul .await { if cookie.eq_body(r.as_str()) { - return Ok(true); + if repo.is_empty() { + return Ok(true); + } + if conn + .sismember::<_, _, i32>(&redis_key, cookie.get_user()) + .await? + == 1 + { + return Ok(true); + } } } log::debug!("{:?}", cookie); @@ -209,12 +216,11 @@ async fn verify_login(cfg: &Config, data: &FormData) -> Result<bool> { .connect() .await?; - let (passwd_hash,) = sqlx::query_as::<_, (String,)>( - r#"SELECT "password" FROM "accounts" WHERE "user" = ?"#, - ) - .bind(data.get_user()) - .fetch_one(&mut conn) - .await?; + let (passwd_hash,) = + sqlx::query_as::<_, (String,)>(r#"SELECT "password" FROM "accounts" WHERE "user" = ?"#) + .bind(data.get_user()) + .fetch_one(&mut conn) + .await?; let parsed_hash = PasswordHash::new(passwd_hash.as_str()).unwrap(); Ok(data.verify_password(&parsed_hash)) @@ -426,13 +432,20 @@ async fn cmd_upgrade_database(cfg: Config) -> Result<()> { Ok(()) } -async fn cmd_repo_user_control(matches: &ArgMatches<'_>, cfg: Config, is_delete: bool) -> Result<()> { +async fn cmd_repo_user_control( + matches: &ArgMatches<'_>, + cfg: Config, + is_delete: bool, +) -> Result<()> { let repo = matches.value_of("repo").unwrap_or(""); let user = matches.value_of("user").unwrap_or(""); let clear_all = matches.is_present("clear-all"); - if repo.is_empty() || (is_delete && !clear_all && user.is_empty()) || (!is_delete && user.is_empty()) { + if repo.is_empty() + || (is_delete && !clear_all && user.is_empty()) + || (!is_delete && user.is_empty()) + { return Err(anyhow::Error::msg("Invalid repository or username")); } @@ -445,10 +458,11 @@ async fn cmd_repo_user_control(matches: &ArgMatches<'_>, cfg: Config, is_delete: .bind(repo) .fetch_optional(&mut conn) .await? - .is_none() { + .is_none() + { if is_delete { println!("Row is empty."); - return Ok(()) + return Ok(()); } sqlx::query(r#"INSERT INTO "repos" VALUES (?, ?)"#) .bind(repo) @@ -488,7 +502,7 @@ async fn cmd_repo_user_control(matches: &ArgMatches<'_>, cfg: Config, is_delete: .await?; let redis_key = format!("cgit_repo_{}", repo); - if redis_conn.exists::<_, i32>(&redis_key).await? == 0{ + if redis_conn.exists::<_, i32>(&redis_key).await? == 0 { redis_conn.sadd::<_, _, i32>(&redis_key, users).await?; } else { if is_delete { @@ -503,11 +517,12 @@ async fn cmd_repo_user_control(matches: &ArgMatches<'_>, cfg: Config, is_delete: } if !clear_all { - println!("{} user {} {} repository {} ACL successful", - if is_delete { "Delete" } else { "Add" }, - user, - if is_delete { "from" } else { "to" }, - repo, + println!( + "{} user {} {} repository {} ACL successful", + if is_delete { "Delete" } else { "Add" }, + user, + if is_delete { "from" } else { "to" }, + repo, ); } else { println!("Clear all users from repository {} ACL", repo); @@ -562,9 +577,7 @@ async fn async_main(arg_matches: ArgMatches<'_>) -> Result<i32> { ("upgrade", Some(_matches)) => { cmd_upgrade_database(cfg).await?; } - ("repoadd", Some(matches)) => { - cmd_repo_user_control(matches, cfg, false).await? - } + ("repoadd", Some(matches)) => cmd_repo_user_control(matches, cfg, false).await?, ("repodel", Some(matches)) => { cmd_repo_user_control(matches, cfg, true).await?; } @@ -713,8 +726,8 @@ fn main() -> Result<()> { #[cfg(test)] mod test { - use crate::datastructures::{rand_str, Config, TestSuite, ProtectedRepo}; - use crate::{cmd_add_user, cmd_authenticate_cookie, cmd_init}; + use crate::datastructures::{rand_str, Config, TestSuite}; + use crate::{cmd_add_user, cmd_authenticate_cookie, cmd_init, cmd_repo_user_control}; use crate::{get_arg_matches, IOModule}; use argon2::{ password_hash::{PasswordHash, PasswordHasher, PasswordVerifier, SaltString}, @@ -870,12 +883,24 @@ mod test { #[test] fn test_03_insert_repo() { lock(&PathBuf::from("test/USER_WRITTEN"), 5); - let matches = crate::get_arg_matches(Some(vec!["a", "repoadd", "hunter2", "hunter2"])); + let matches = crate::get_arg_matches(Some(vec!["a", "repoadd", "test", "hunter2"])); + match matches.subcommand() { + ("repoadd", Some(matches)) => { + tokio::runtime::Builder::new_current_thread() + .enable_all() + .build() + .unwrap() + .block_on(cmd_repo_user_control(matches, Config::generate_test_config(), false)) + .unwrap(); + std::fs::File::create("test/REPO_USER_ADDED").unwrap(); + } + _ => unreachable!() + } } #[test] fn test_91_auth_pass() { - lock(&PathBuf::from("test/USER_WRITTEN"), 7); + lock(&PathBuf::from("test/REPO_USER_ADDED"), 7); let s = test_auth_post(); @@ -893,6 +918,16 @@ mod test { #[test] fn test_92_authenticate_cookie() { + test_authenticate_cookie("test"); + } + + #[test] + #[should_panic] + fn test_93_authenticate_cookie() { + test_authenticate_cookie("repo"); + } + + fn test_authenticate_cookie(repo: &str) { lock(&PathBuf::from("test/RESPONSE"), 15); let mut buffer = String::new(); @@ -923,7 +958,7 @@ mod test { "/", "git.example.com", "on", - "", + repo, "", "/", "/?p=login", @@ -958,31 +993,32 @@ mod test { fn test_02_protected_repo_parser() { let tmpdir = tempdir::TempDir::new("test").unwrap(); - let another_file_path = format!("include={}/REPO_SETTING # TEST", tmpdir.path().to_str().unwrap()); + let another_file_path = format!( + "include={}/REPO_SETTING # TEST\ncgit-simple-auth-protect=none", + tmpdir.path().to_str().unwrap() + ); write_to_specify_file(&tmpdir.path().join("CFG"), another_file_path.as_bytes()).unwrap(); + write_to_specify_file( + &tmpdir.path().join("REPO_SETTING"), + b"repo.url=test\nrepo.protect=true", + ) + .unwrap(); + let cfg = Config::load_from_path(tmpdir.path().join("CFG")); - write_to_specify_file(&tmpdir.path().join("REPO_SETTING"), b"repo.url=test\nrepo.protect=true").unwrap(); - - - let result = ProtectedRepo::load_from_file(tmpdir.path().join("CFG")); - - assert!(result.query_is_protected("test")); - assert!(!result.query_is_all_protected()); - - write_to_specify_file(&tmpdir.path().join("REPO_SETTING"), b"repo.protect=true\nrepo.url=test").unwrap(); - - let result = ProtectedRepo::load_from_file(tmpdir.path().join("CFG")); - - assert!(!result.query_is_protected("test")); - assert!(!result.query_is_all_protected()); + assert!(cfg.check_repo_protect("test")); + assert!(!cfg.query_is_all_protected()); - write_to_specify_file(&tmpdir.path().join("REPO_SETTING"), b"repo.protect=true\nrepo.url=test\n\ncgit-simple-auth-protect=full").unwrap(); + write_to_specify_file( + &tmpdir.path().join("REPO_SETTING"), + b"repo.protect=true\nrepo.url=test", + ) + .unwrap(); - let result = ProtectedRepo::load_from_file(tmpdir.path().join("CFG")); + let cfg = Config::load_from_path(tmpdir.path().join("CFG")); - assert!(result.query_is_all_protected()); - assert!(result.query_is_protected("test")); + assert!(!cfg.check_repo_protect("test")); + assert!(!cfg.query_is_all_protected()); tmpdir.close().unwrap(); } |
