forked from rust-lang/crates.io
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
models: add initial user model bits for defining admins
Based on rust-lang#5376. Co-authored-by: Carol (Nichols || Goulding) <carol.nichols@gmail.com>
- Loading branch information
1 parent
3925cdd
commit 0a2cb03
Showing
6 changed files
with
136 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
pub mod admin; | ||
pub mod with_count; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
use std::collections::HashSet; | ||
|
||
use lazy_static::lazy_static; | ||
|
||
use crate::util::errors::{forbidden, AppResult}; | ||
|
||
lazy_static! { | ||
static ref AUTHORIZED_ADMIN_USERS: HashSet<String> = | ||
parse_authorized_admin_users(dotenv::var("GH_ADMIN_USERS")); | ||
} | ||
|
||
const DEFAULT_ADMIN_USERS: [&str; 3] = ["carols10cents", "jtgeibel", "Turbo87"]; | ||
|
||
fn parse_authorized_admin_users(maybe_users: dotenv::Result<String>) -> HashSet<String> { | ||
match maybe_users { | ||
Ok(users) => users | ||
.split(|c: char| !(c.is_ascii_alphanumeric() || c == '-')) | ||
.filter(|user| !user.is_empty()) | ||
.map(String::from) | ||
.collect(), | ||
Err(_err) => DEFAULT_ADMIN_USERS.into_iter().map(String::from).collect(), | ||
} | ||
} | ||
|
||
/// Return `Ok(())` if the given GitHub user name matches a known admin (set | ||
/// either via the `$GH_ADMIN_USERS` environment variable, or the builtin | ||
/// fallback list if that variable is unset), or a forbidden error otherwise. | ||
pub fn is_authorized_admin(username: &str) -> AppResult<()> { | ||
// This hack is here to allow tests to have a consistent set of admin users | ||
// (in this case, just the contents of the `DEFAULT_ADMIN_USERS` constant | ||
// above). | ||
|
||
#[cfg(not(test))] | ||
fn check_username(username: &str) -> bool { | ||
AUTHORIZED_ADMIN_USERS.contains(username) | ||
} | ||
|
||
#[cfg(test)] | ||
fn check_username(username: &str) -> bool { | ||
DEFAULT_ADMIN_USERS.contains(&username) | ||
} | ||
|
||
if check_username(username) { | ||
Ok(()) | ||
} else { | ||
Err(forbidden()) | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use std::io::{self, ErrorKind}; | ||
|
||
use super::{is_authorized_admin, parse_authorized_admin_users, DEFAULT_ADMIN_USERS}; | ||
|
||
#[test] | ||
fn test_is_authorized_admin() { | ||
assert_ok!(is_authorized_admin("Turbo87")); | ||
assert_err!(is_authorized_admin("")); | ||
assert_err!(is_authorized_admin("foo")); | ||
} | ||
|
||
#[test] | ||
fn test_parse_authorized_admin_users() { | ||
fn assert_authorized(input: dotenv::Result<&str>, expected: &[&str]) { | ||
assert_eq!( | ||
parse_authorized_admin_users(input.map(String::from)), | ||
expected.iter().map(|s| String::from(*s)).collect() | ||
); | ||
} | ||
|
||
assert_authorized(Ok(""), &[]); | ||
assert_authorized(Ok("foo"), &["foo"]); | ||
assert_authorized(Ok("foo, bar"), &["foo", "bar"]); | ||
assert_authorized(Ok(" foo bar "), &["foo", "bar"]); | ||
assert_authorized(Ok("foo;bar"), &["foo", "bar"]); | ||
|
||
let not_found_error = dotenv::Error::Io(io::Error::new(ErrorKind::NotFound, "not found")); | ||
assert_authorized(Err(not_found_error), DEFAULT_ADMIN_USERS.as_slice()); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters