Test user authentication
This commit is contained in:
parent
a33b94e5b3
commit
a0f1a0b81c
@ -35,3 +35,4 @@ CREATE TABLE roles(
|
||||
FOREIGN KEY(game_id) REFERENCES games(uuid)
|
||||
);
|
||||
|
||||
INSERT INTO users VALUES ('admin', 'admin', '', true, true);
|
||||
|
@ -11,7 +11,7 @@ use uuid::Uuid;
|
||||
use crate::{
|
||||
asset_db::{self, AssetId, Assets},
|
||||
database::{CharacterId, Database, SessionId, UserId},
|
||||
types::{AppError, FatalError, Game, Message, Tabletop, User, Rgb},
|
||||
types::{AppError, FatalError, Game, Message, Rgb, Tabletop, User},
|
||||
};
|
||||
|
||||
const DEFAULT_BACKGROUND_COLOR: Rgb = Rgb {
|
||||
@ -154,9 +154,7 @@ impl Core {
|
||||
asset_db::Error::Inaccessible => {
|
||||
AppError::Inaccessible(format!("{}", asset_id))
|
||||
}
|
||||
asset_db::Error::Unexpected(err) => {
|
||||
AppError::Inaccessible(format!("{}", err))
|
||||
}
|
||||
asset_db::Error::Unexpected(err) => AppError::Inaccessible(format!("{}", err)),
|
||||
}),
|
||||
)
|
||||
}
|
||||
@ -212,6 +210,25 @@ impl Core {
|
||||
});
|
||||
}
|
||||
|
||||
pub async fn save_user(
|
||||
&self,
|
||||
uuid: Option<UserId>,
|
||||
username: &str,
|
||||
password: &str,
|
||||
admin: bool,
|
||||
enabled: bool,
|
||||
) -> ResultExt<UserId, AppError, FatalError> {
|
||||
let state = self.0.read().await;
|
||||
match state
|
||||
.db
|
||||
.save_user(uuid, username, password, admin, enabled)
|
||||
.await
|
||||
{
|
||||
Ok(uuid) => ok(uuid),
|
||||
Err(err) => fatal(err),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn set_password(
|
||||
&self,
|
||||
uuid: UserId,
|
||||
@ -290,7 +307,7 @@ mod test {
|
||||
]);
|
||||
let memory_db: Option<PathBuf> = None;
|
||||
let conn = DbConn::new(memory_db);
|
||||
conn.save_user(None, "admin", "aoeu", true, true)
|
||||
conn.save_user(Some(UserId::from("admin")), "admin", "aoeu", true, true)
|
||||
.await
|
||||
.unwrap();
|
||||
conn.save_user(None, "gm_1", "aoeu", false, true)
|
||||
|
@ -100,7 +100,7 @@ impl DiskDb {
|
||||
) -> Result<UserId, FatalError> {
|
||||
match user_id {
|
||||
None => {
|
||||
let user_id = UserId::new();
|
||||
let user_id = UserId::default();
|
||||
let mut stmt = self
|
||||
.conn
|
||||
.prepare("INSERT INTO users VALUES (?, ?, ?, ?, ?)")
|
||||
|
@ -173,7 +173,7 @@ mod test {
|
||||
let no_path: Option<PathBuf> = None;
|
||||
let db = DiskDb::new(no_path).unwrap();
|
||||
|
||||
db.save_user(None, "admin", "abcdefg", true, true).unwrap();
|
||||
db.save_user(Some(UserId::from("admin")), "admin", "abcdefg", true, true).unwrap();
|
||||
let game_id = db.save_game(None, "Candela").unwrap();
|
||||
(db, game_id)
|
||||
}
|
||||
|
@ -6,15 +6,17 @@ use uuid::Uuid;
|
||||
pub struct UserId(String);
|
||||
|
||||
impl UserId {
|
||||
pub fn new() -> Self {
|
||||
Self(format!("{}", Uuid::new_v4().hyphenated()))
|
||||
}
|
||||
|
||||
pub fn as_str(&self) -> &str {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for UserId {
|
||||
fn default() -> Self {
|
||||
Self(format!("{}", Uuid::new_v4().hyphenated()))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for UserId {
|
||||
fn from(s: &str) -> Self {
|
||||
Self(s.to_owned())
|
||||
|
@ -32,8 +32,8 @@ pub async fn healthcheck(core: Core) -> Vec<u8> {
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
#[typeshare]
|
||||
pub struct AuthRequest {
|
||||
username: String,
|
||||
password: String,
|
||||
pub username: String,
|
||||
pub password: String,
|
||||
}
|
||||
|
||||
pub async fn check_password(core: Core, req: Json<AuthRequest>) -> (StatusCode, Json<Option<SessionId>>) {
|
||||
|
@ -1,4 +1,7 @@
|
||||
use axum::{routing::{get, post}, Json, Router};
|
||||
use axum::{
|
||||
routing::{get, post},
|
||||
Json, Router,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
core::Core,
|
||||
@ -27,12 +30,19 @@ pub fn routes(core: Core) -> Router {
|
||||
mod test {
|
||||
use std::path::PathBuf;
|
||||
|
||||
use axum::http::StatusCode;
|
||||
use axum_test::TestServer;
|
||||
use cool_asserts::assert_matches;
|
||||
use result_extended::ResultExt;
|
||||
|
||||
use crate::{asset_db::FsAssets, core::Core, database::DbConn};
|
||||
use super::*;
|
||||
use crate::{
|
||||
asset_db::FsAssets,
|
||||
core::Core,
|
||||
database::{Database, DbConn, SessionId, UserId},
|
||||
};
|
||||
|
||||
fn setup() -> (Core, TestServer) {
|
||||
fn setup_without_admin() -> (Core, TestServer) {
|
||||
let memory_db: Option<PathBuf> = None;
|
||||
let conn = DbConn::new(memory_db);
|
||||
let core = Core::new(FsAssets::new(PathBuf::from("/home/savanni/Pictures")), conn);
|
||||
@ -41,14 +51,75 @@ mod test {
|
||||
(core, server)
|
||||
}
|
||||
|
||||
async fn setup_admin_enabled() -> (Core, TestServer) {
|
||||
let memory_db: Option<PathBuf> = None;
|
||||
let conn = DbConn::new(memory_db);
|
||||
conn.save_user(Some(UserId::from("admin")), "admin", "aoeu", true, true)
|
||||
.await
|
||||
.unwrap();
|
||||
let core = Core::new(FsAssets::new(PathBuf::from("/home/savanni/Pictures")), conn);
|
||||
let app = routes(core.clone());
|
||||
let server = TestServer::new(app).unwrap();
|
||||
(core, server)
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn it_returns_a_healthcheck() {
|
||||
let (_core, server) = setup();
|
||||
let (core, server) = setup_without_admin();
|
||||
|
||||
let response = server.get("/api/v1/health").await;
|
||||
response.assert_status_ok();
|
||||
|
||||
let b: crate::handlers::HealthCheck = response.json();
|
||||
|
||||
assert_eq!(b, crate::handlers::HealthCheck { ok: false });
|
||||
|
||||
assert_matches!(
|
||||
core.save_user(Some(UserId::from("admin")), "admin", "aoeu", true, true)
|
||||
.await,
|
||||
ResultExt::Ok(_)
|
||||
);
|
||||
|
||||
let response = server.get("/api/v1/health").await;
|
||||
response.assert_status_ok();
|
||||
let b: crate::handlers::HealthCheck = response.json();
|
||||
assert_eq!(b, crate::handlers::HealthCheck { ok: true });
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn it_authenticates_a_user() {
|
||||
let (_core, server) = setup_admin_enabled().await;
|
||||
|
||||
let response = server
|
||||
.post("/api/v1/auth")
|
||||
.json(&AuthRequest {
|
||||
username: "admin".to_owned(),
|
||||
password: "wrong".to_owned(),
|
||||
})
|
||||
.await;
|
||||
response.assert_status(StatusCode::UNAUTHORIZED);
|
||||
|
||||
let response = server
|
||||
.post("/api/v1/auth")
|
||||
.json(&AuthRequest {
|
||||
username: "unknown".to_owned(),
|
||||
password: "wrong".to_owned(),
|
||||
})
|
||||
.await;
|
||||
response.assert_status(StatusCode::UNAUTHORIZED);
|
||||
|
||||
let response = server
|
||||
.post("/api/v1/auth")
|
||||
.json(&AuthRequest {
|
||||
username: "admin".to_owned(),
|
||||
password: "aoeu".to_owned(),
|
||||
})
|
||||
.await;
|
||||
response.assert_status_ok();
|
||||
let session_id: Option<SessionId> = response.json();
|
||||
assert!(session_id.is_some());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn it_returns_user_profile() {
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user