db&webapi, primitive session tokens
adds a temporary auth method to users which does not require a password or similar. This is just for testing right now and assumes a self-hosted no-threats environment. Also adds a user_key state to keep track of authed users. These currently *DO NOT EXPIRE* which is pretty bad haha. The entire auth system will be redone.
This commit is contained in:
parent
949a984d0c
commit
b089f62bcd
5 changed files with 86 additions and 3 deletions
|
|
@ -1,24 +1,42 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
use koucha::{
|
use koucha::{
|
||||||
AdapterBuilder,
|
Adapter, AdapterBuilder, db::{User, UserKey as DbUserKey}
|
||||||
Adapter,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::types::UserKey;
|
||||||
|
|
||||||
mod routes;
|
mod routes;
|
||||||
mod types;
|
mod types;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct AppState {
|
struct AppState {
|
||||||
pub adapter: Adapter,
|
pub adapter: Adapter,
|
||||||
|
// TODO: Set up UserKey expirations
|
||||||
|
auth_map: HashMap<UserKey, DbUserKey>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl AppState {
|
||||||
|
fn create_user_key(&mut self, db_user_key: DbUserKey) -> UserKey {
|
||||||
|
let key = UserKey::new();
|
||||||
|
self.auth_map.insert(key.clone(), db_user_key);
|
||||||
|
key
|
||||||
|
}
|
||||||
|
#[allow(dead_code)]
|
||||||
|
fn user_from_key(&self, key: &UserKey) -> Option<DbUserKey> {
|
||||||
|
self.auth_map.get(key).map(DbUserKey::clone)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
let db_url = std::env::var("DATABASE_URL").unwrap();
|
let db_url = std::env::var("DATABASE_URL").unwrap();
|
||||||
let adapter = AdapterBuilder::new()
|
let adapter = AdapterBuilder::new()
|
||||||
.database_url(&db_url)
|
.database_url(&db_url)
|
||||||
.create().await.unwrap();
|
.create().await.unwrap();
|
||||||
|
let auth_map = HashMap::new();
|
||||||
|
|
||||||
let app = routes::router().with_state(AppState { adapter });
|
let app = routes::router().with_state(AppState { adapter, auth_map });
|
||||||
|
|
||||||
let listener = tokio::net::TcpListener::bind("0.0.0.0:4142").await.unwrap();
|
let listener = tokio::net::TcpListener::bind("0.0.0.0:4142").await.unwrap();
|
||||||
axum::serve(listener, app).await.unwrap();
|
axum::serve(listener, app).await.unwrap();
|
||||||
|
|
|
||||||
41
koucha/src/bin/webapi/routes/create_session.rs
Normal file
41
koucha/src/bin/webapi/routes/create_session.rs
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
use axum::{Json, extract::State};
|
||||||
|
use koucha::db::User as DbUser;
|
||||||
|
use reqwest::StatusCode;
|
||||||
|
use serde::{Serialize, Deserialize};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
AppState, routes::{ApiError, ApiResult, ApiResponse}, types::UserKey
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
pub struct Input {
|
||||||
|
pub user_name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct Output {
|
||||||
|
user_key: UserKey,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn handler(
|
||||||
|
State(mut state): State<AppState>,
|
||||||
|
Json(body): Json<Input>,
|
||||||
|
) -> ApiResult<Output> {
|
||||||
|
let dbuser = DbUser::temporary_auth(
|
||||||
|
state.adapter.get_pool(),
|
||||||
|
&body.user_name
|
||||||
|
).await.map_err(|_e| {
|
||||||
|
// TODO: Logging
|
||||||
|
ApiError {
|
||||||
|
status: StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
error: "InternalError",
|
||||||
|
message: String::from(
|
||||||
|
"Error authentiating user ".to_owned() + &body.user_name
|
||||||
|
),
|
||||||
|
}
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let key = state.create_user_key(dbuser.key());
|
||||||
|
|
||||||
|
Ok(ApiResponse(StatusCode::OK, Output { user_key: key }))
|
||||||
|
}
|
||||||
|
|
@ -11,6 +11,7 @@ use axum::{
|
||||||
};
|
};
|
||||||
use reqwest::StatusCode;
|
use reqwest::StatusCode;
|
||||||
|
|
||||||
|
mod create_session;
|
||||||
mod get_users;
|
mod get_users;
|
||||||
mod new_user;
|
mod new_user;
|
||||||
|
|
||||||
|
|
@ -28,6 +29,7 @@ pub struct ApiError {
|
||||||
|
|
||||||
pub fn router() -> Router<AppState> {
|
pub fn router() -> Router<AppState> {
|
||||||
Router::new()
|
Router::new()
|
||||||
|
.route("/create_session", post(create_session::handler))
|
||||||
.route("/get_users", get(get_users::handler))
|
.route("/get_users", get(get_users::handler))
|
||||||
.route("/new_user", post(new_user::handler))
|
.route("/new_user", post(new_user::handler))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,17 @@
|
||||||
|
use chrono::Utc;
|
||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct User {
|
pub struct User {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||||
|
pub struct UserKey(String);
|
||||||
|
impl UserKey {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
UserKey(
|
||||||
|
Utc::now().to_rfc3339()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,17 @@ pub struct User {
|
||||||
impl User {
|
impl User {
|
||||||
pub fn key(&self) -> UserKey { self.key }
|
pub fn key(&self) -> UserKey { self.key }
|
||||||
pub fn name(&self) -> &str { &self.name }
|
pub fn name(&self) -> &str { &self.name }
|
||||||
|
|
||||||
|
pub async fn temporary_auth(
|
||||||
|
pool: &AdapterPool,
|
||||||
|
name: &str,
|
||||||
|
) -> Result<Self> {
|
||||||
|
sqlx::query_as!(
|
||||||
|
UnparsedUser,
|
||||||
|
"SELECT id as `id!`, name FROM users WHERE name = ?",
|
||||||
|
name
|
||||||
|
).fetch_one(&pool.0).await?.parse()
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn get(pool: &AdapterPool, key: UserKey) -> Result<Self> {
|
pub async fn get(pool: &AdapterPool, key: UserKey) -> Result<Self> {
|
||||||
sqlx::query_as!(
|
sqlx::query_as!(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue