Compare commits

...

16 Commits

Author SHA1 Message Date
phoenix 99390ce8b7 tsk-50: Create Special endpoint for services to obtain a token (#53)
Reviewed-on: #53
Co-authored-by: phoenix <kundeng00@pm.me>
Co-committed-by: phoenix <kundeng00@pm.me>
2025-08-03 23:09:50 +00:00
phoenix 5967ed5b13 minor refactoring (#52)
Reviewed-on: #52
Co-authored-by: phoenix <kundeng00@pm.me>
Co-committed-by: phoenix <kundeng00@pm.me>
2025-08-01 20:49:15 +00:00
phoenix be4d1109a7 Update rust in docker (#48)
Reviewed-on: #48
Co-authored-by: phoenix <kundeng00@pm.me>
Co-committed-by: phoenix <kundeng00@pm.me>
2025-07-13 23:01:16 +00:00
phoenix 4353414c69 Upgrade postgresql (#47)
Reviewed-on: #47

Closes #46

Co-authored-by: phoenix <kundeng00@pm.me>
Co-committed-by: phoenix <kundeng00@pm.me>
2025-07-12 19:32:56 +00:00
phoenix c176d0fcf3 Version bump (#45)
Reviewed-on: #45
Co-authored-by: phoenix <kundeng00@pm.me>
Co-committed-by: phoenix <kundeng00@pm.me>
2025-06-29 20:50:55 +00:00
phoenix c8b8d470dc Refactoring (#44)
Reviewed-on: #44
Co-authored-by: phoenix <kundeng00@pm.me>
Co-committed-by: phoenix <kundeng00@pm.me>
2025-06-29 20:39:04 +00:00
phoenix bcd0e607ef Update dependencies (#43)
Reviewed-on: #43
Co-authored-by: phoenix <kundeng00@pm.me>
Co-committed-by: phoenix <kundeng00@pm.me>
2025-06-29 20:26:58 +00:00
phoenix 70de6b862f rust std change (#42)
Reviewed-on: #42
Co-authored-by: phoenix <kundeng00@pm.me>
Co-committed-by: phoenix <kundeng00@pm.me>
2025-06-29 20:03:41 +00:00
phoenix 8c902b9d61 Version bump (#41)
Reviewed-on: #41
Co-authored-by: phoenix <kundeng00@pm.me>
Co-committed-by: phoenix <kundeng00@pm.me>
2025-06-01 23:41:05 +00:00
phoenix 480a428e8b Including cargo.lock in source control (#40)
Reviewed-on: #40
Co-authored-by: phoenix <kundeng00@pm.me>
Co-committed-by: phoenix <kundeng00@pm.me>
2025-06-01 23:23:24 +00:00
phoenix 02697b2fd9 Adding icarus_envy (#39)
Reviewed-on: #39
Co-authored-by: phoenix <kundeng00@pm.me>
Co-committed-by: phoenix <kundeng00@pm.me>
2025-06-01 23:02:09 +00:00
phoenix d4faa7976e Update icarus_models (#38)
Reviewed-on: #38
Co-authored-by: phoenix <kundeng00@pm.me>
Co-committed-by: phoenix <kundeng00@pm.me>
2025-05-28 23:26:17 +00:00
phoenix ed77cab700 Environment and docker changes (#37)
Reviewed-on: #37
Co-authored-by: phoenix <kundeng00@pm.me>
Co-committed-by: phoenix <kundeng00@pm.me>
2025-05-27 20:55:53 +00:00
phoenix 2c30abb5c6 Updated gitignore (#36)
Reviewed-on: #36
Co-authored-by: phoenix <kundeng00@pm.me>
Co-committed-by: phoenix <kundeng00@pm.me>
2025-05-27 20:23:50 +00:00
phoenix 1817ab01d6 Test fix (#35)
Reviewed-on: #35
Co-authored-by: phoenix <kundeng00@pm.me>
Co-committed-by: phoenix <kundeng00@pm.me>
2025-04-27 18:06:13 +00:00
phoenix 31be156be3 Added ssh default for building docker image (#33)
Reviewed-on: #33
Co-authored-by: phoenix <kundeng00@pm.me>
Co-committed-by: phoenix <kundeng00@pm.me>
2025-04-27 16:31:11 +00:00
21 changed files with 2899 additions and 189 deletions
+7
View File
@@ -0,0 +1,7 @@
SECRET_KEY=refero34o8rfhfjn983thf39fhc943rf923n3h
SERVICE_PASSPHRASE=iUOo1fxshf3y1tUGn1yU8l9raPApHCdinW0VdCHdRFEjqhR3Bf02aZzsKbLtaDFH
POSTGRES_AUTH_USER=icarus_op
POSTGRES_AUTH_PASSWORD=password
POSTGRES_AUTH_DB=icarus_auth_db
POSTGRES_AUTH_HOST=auth_db
DATABASE_URL=postgresql://${POSTGRES_AUTH_USER}:${POSTGRES_AUTH_PASSWORD}@${POSTGRES_AUTH_HOST}:5432/${POSTGRES_AUTH_DB}
+6 -5
View File
@@ -1,6 +1,7 @@
SECRET_KEY=refero34o8rfhfjn983thf39fhc943rf923n3h
POSTGRES_USER=icarus_op_test
POSTGRES_PASSWORD=password
POSTGRES_DB=icarus_auth_test_db
POSTGRES_HOST=localhost
DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:5432/${POSTGRES_DB}
SERVICE_PASSPHRASE=iUOo1fxshf3y1tUGn1yU8l9raPApHCdinW0VdCHdRFEjqhR3Bf02aZzsKbLtaDFH
POSTGRES_AUTH_USER=icarus_op_test
POSTGRES_AUTH_PASSWORD=password
POSTGRES_AUTH_DB=icarus_auth_test_db
POSTGRES_AUTH_HOST=localhost
DATABASE_URL=postgresql://${POSTGRES_AUTH_USER}:${POSTGRES_AUTH_PASSWORD}@${POSTGRES_AUTH_HOST}:5432/${POSTGRES_AUTH_DB}
+1 -3
View File
@@ -17,7 +17,7 @@ jobs:
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
toolchain: 1.86.0
toolchain: 1.88.0
components: cargo
- name: Extract Version from Cargo.toml
@@ -49,5 +49,3 @@ jobs:
release_name: Release ${{ steps.version.outputs.project_tag_release }}
body: |
Release of version ${{ steps.version.outputs.project_tag_release }}
# draft: false
# prerelease: ${{ startsWith(github.ref, 'v') == false }} # prerelease if not a valid release tag
+6 -6
View File
@@ -18,7 +18,7 @@ jobs:
- uses: actions/checkout@v4
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: 1.86.0
toolchain: 1.88.0
- run: |
mkdir -p ~/.ssh
echo "${{ secrets.MYREPO_TOKEN }}" > ~/.ssh/icarus_models_deploy_key
@@ -36,7 +36,7 @@ jobs:
# --- Add database service definition ---
services:
postgres:
image: postgres:17.4 # Or pin to a more specific version like 14.9
image: postgres:17.5
env:
# Use secrets for DB init, with fallbacks for flexibility
POSTGRES_USER: ${{ secrets.DB_TEST_USER || 'testuser' }}
@@ -53,7 +53,7 @@ jobs:
- uses: actions/checkout@v4
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: 1.86.0
toolchain: 1.88.0
# --- Add this step for explicit verification ---
- name: Verify Docker Environment
run: |
@@ -94,7 +94,7 @@ jobs:
- uses: actions/checkout@v4
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: 1.86.0
toolchain: 1.88.0
- run: rustup component add rustfmt
- run: |
mkdir -p ~/.ssh
@@ -113,7 +113,7 @@ jobs:
- uses: actions/checkout@v4
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: 1.86.0
toolchain: 1.88.0
- run: rustup component add clippy
- run: |
mkdir -p ~/.ssh
@@ -132,7 +132,7 @@ jobs:
- uses: actions/checkout@v4
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: 1.86.0
toolchain: 1.88.0
- run: |
mkdir -p ~/.ssh
echo "${{ secrets.MYREPO_TOKEN }}" > ~/.ssh/icarus_models_deploy_key
+2 -1
View File
@@ -1,3 +1,4 @@
/target
Cargo.lock
.env
.env.local
.env.docker
Generated
+2611
View File
File diff suppressed because it is too large Load Diff
+14 -14
View File
@@ -1,27 +1,27 @@
[package]
name = "icarus_auth"
version = "0.3.4"
version = "0.4.2"
edition = "2024"
rust-version = "1.86"
rust-version = "1.88"
[dependencies]
axum = { version = "0.8.3" }
serde = { version = "1.0.218", features = ["derive"] }
serde_json = { version = "1.0.139" }
tokio = { version = "1.44.1", features = ["rt-multi-thread"] }
axum = { version = "0.8.4" }
serde = { version = "1.0.219", features = ["derive"] }
serde_json = { version = "1.0.140" }
tokio = { version = "1.45.1", features = ["rt-multi-thread"] }
tracing-subscriber = { version = "0.3.19" }
tower = { version = "0.5.2" }
hyper = { version = "1.6.0" }
sqlx = { version = "0.8.3", features = ["postgres", "runtime-tokio-native-tls", "time", "uuid"] }
dotenvy = { version = "0.15.7" }
uuid = { version = "1.16.0", features = ["v4", "serde"] }
sqlx = { version = "0.8.6", features = ["postgres", "runtime-tokio-native-tls", "time", "uuid"] }
uuid = { version = "1.17.0", features = ["v4", "serde"] }
argon2 = { version = "0.5.3", features = ["std"] } # Use the latest 0.5.x version
rand = { version = "0.9" }
rand = { version = "0.9.1" }
time = { version = "0.3.41", features = ["macros", "serde"] }
josekit = { version = "0.10.1" }
icarus_models = { git = "ssh://git@git.kundeng.us/phoenix/icarus_models.git", tag = "v0.4.1" }
josekit = { version = "0.10.3" }
icarus_models = { git = "ssh://git@git.kundeng.us/phoenix/icarus_models.git", tag = "v0.5.4-devel-1e95822b5a-111" }
icarus_envy = { git = "ssh://git@git.kundeng.us/phoenix/icarus_envy.git", tag = "v0.3.1-main-3cd42dab6b-006" }
[dev-dependencies]
http-body-util = { version = "0.1.3" }
url = { version = "2.5" }
once_cell = { version = "1.19" } # Useful for lazy initialization in tests/app setup
url = { version = "2.5.4" }
once_cell = { version = "1.21.3" } # Useful for lazy initialization in tests/app setup
+2 -2
View File
@@ -1,7 +1,7 @@
# Stage 1: Build the application
# Use a specific Rust version for reproducibility. Choose one that matches your development environment.
# Using slim variant for smaller base image
FROM rust:1.86 as builder
FROM rust:1.88 as builder
# Set the working directory inside the container
WORKDIR /usr/src/app
@@ -68,4 +68,4 @@ EXPOSE 3000
# Set the command to run your application
# Ensure this matches the binary name copied above
CMD ["./icarus_auth"]
CMD ["./icarus_auth"]
-20
View File
@@ -1,20 +0,0 @@
# Getting started
Take notice of the .env.sample file and create copies without the .sample in the name.
`.env.sample` -> `.env`
Ensure that all variables are populated and is correct.
## Docker
Build the images
```
docker compose build --ssh default auth_api
```
Bring it up
```
docker compose up -d --force-recreate auth_api
```
+26
View File
@@ -0,0 +1,26 @@
# Getting Started
Copy the `.env.sample` file to `.env` and ensure that the variables are populated. This project
can be used with regular hosting or with docker. For the sake of getting up to speed quickly,
Docker will be covered. Make sure docker is running and your ssh identity has been loaded.
Build image
```
docker compose build
```
Start images
```
docker compose up -d --force-recreate
```
Bring it down
```
docker compose down -v
```
Pruning
```
docker system prune -a
```
+8 -6
View File
@@ -3,7 +3,9 @@ version: '3.8' # Use a recent version
services:
# Your Rust Application Service
auth_api:
build: . # Tells docker-compose to build the Dockerfile in the current directory
build: # Tells docker-compose to build the Dockerfile in the current directory
context: .
ssh: ["default"] # Uses host's SSH agent
container_name: icarus_auth # Optional: Give the container a specific name
ports:
# Map host port 8000 to container port 3000 (adjust as needed)
@@ -17,13 +19,13 @@ services:
# PostgreSQL Database Service
auth_db:
image: postgres:17.4-alpine # Use an official Postgres image (Alpine variant is smaller)
image: postgres:17.5-alpine # Use an official Postgres image (Alpine variant is smaller)
container_name: icarus_auth_db # Optional: Give the container a specific name
environment:
# These MUST match the user, password, and database name in the DATABASE_URL above
POSTGRES_USER: ${POSTGRES_USER:-icarus_op}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-password}
POSTGRES_DB: ${POSTGRES_DB:-icarus_auth}
POSTGRES_USER: ${POSTGRES_AUTH_USER:-icarus_op}
POSTGRES_PASSWORD: ${POSTGRES_AUTH_PASSWORD:-password}
POSTGRES_DB: ${POSTGRES_AUTH_DB:-icarus_auth_db}
volumes:
# Persist database data using a named volume
- postgres_data:/var/lib/postgresql/data
@@ -40,4 +42,4 @@ services:
# Define the named volume for data persistence
volumes:
postgres_data:
driver: local # Use the default local driver
driver: local # Use the default local driver
-13
View File
@@ -1,13 +0,0 @@
# Docker stuff
#Build app
docker compose build --ssh default auth_api
# Rebuild and bring up
docker compose up -d --force-recreate auth_api
# Bring it down
docker compose down -v
# Pruning
docker system prune -a
@@ -20,3 +20,9 @@ CREATE TABLE IF NOT EXISTS "salt" (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
salt TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS "passphrase" (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
passphrase TEXT NOT NULL,
date_created TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
@@ -0,0 +1,2 @@
-- Add migration script here
INSERT INTO "passphrase" (passphrase) VALUES('iUOo1fxshf3y1tUGn1yU8l9raPApHCdinW0VdCHdRFEjqhR3Bf02aZzsKbLtaDFH');
+2
View File
@@ -1,3 +1,5 @@
TODO: At some point, move this somewhere that is appropriate
# Make sure role has CREATEDB
ALTER ROLE username_that_needs_permission CREATEDB;
+55 -2
View File
@@ -6,6 +6,13 @@ pub mod request {
pub username: String,
pub password: String,
}
pub mod service_login {
#[derive(Debug, serde::Deserialize, serde::Serialize)]
pub struct Request {
pub passphrase: String,
}
}
}
pub mod response {
@@ -16,6 +23,14 @@ pub mod response {
pub message: String,
pub data: Vec<icarus_models::login_result::LoginResult>,
}
pub mod service_login {
#[derive(Debug, Default, serde::Deserialize, serde::Serialize)]
pub struct Response {
pub message: String,
pub data: Vec<icarus_models::login_result::LoginResult>,
}
}
}
pub mod endpoint {
@@ -47,7 +62,7 @@ pub mod endpoint {
Ok(user) => {
if hashing::verify_password(&payload.password, user.password.clone()).unwrap() {
// Create token
let key = token_stuff::get_key().unwrap();
let key = icarus_envy::environment::get_secret_key().await;
let (token_literal, duration) = token_stuff::create_token(&key).unwrap();
if token_stuff::verify_token(&key, &token_literal) {
@@ -62,7 +77,7 @@ pub mod endpoint {
id: user.id,
username: user.username.clone(),
token: token_literal,
token_type: String::from(token_stuff::TOKENTYPE),
token_type: String::from(icarus_models::token::TOKEN_TYPE),
expiration: duration,
}],
}),
@@ -79,4 +94,42 @@ pub mod endpoint {
}
}
}
pub async fn service_login(
axum::Extension(pool): axum::Extension<sqlx::PgPool>,
axum::Json(payload): axum::Json<request::service_login::Request>,
) -> (
axum::http::StatusCode,
axum::Json<response::service_login::Response>,
) {
let mut response = response::service_login::Response::default();
match repo::service::valid_passphrase(&pool, &payload.passphrase).await {
Ok((id, _passphrase, _date_created)) => {
let key = icarus_envy::environment::get_secret_key().await;
let (token_literal, duration) = token_stuff::create_service_token(&key).unwrap();
if token_stuff::verify_token(&key, &token_literal) {
let login_result = icarus_models::login_result::LoginResult {
id,
username: String::from("service"),
token: token_literal,
token_type: String::from(icarus_models::token::TOKEN_TYPE),
expiration: duration,
};
response.data.push(login_result);
response.message = String::from("Successful");
(axum::http::StatusCode::OK, axum::Json(response))
} else {
(axum::http::StatusCode::OK, axum::Json(response))
}
}
Err(err) => {
response.message = err.to_string();
(axum::http::StatusCode::BAD_REQUEST, axum::Json(response))
}
}
}
}
+1
View File
@@ -7,4 +7,5 @@ pub mod endpoints {
pub const REGISTER: &str = "/api/v2/register";
pub const DBTEST: &str = "/api/v2/test/db";
pub const LOGIN: &str = "/api/v2/login";
pub const SERVICE_LOGIN: &str = "/api/v2/service/login";
}
+3 -18
View File
@@ -4,14 +4,6 @@ pub mod hashing;
pub mod repo;
pub mod token_stuff;
pub mod keys {
pub const DBURL: &str = "DATABASE_URL";
pub mod error {
pub const ERROR: &str = "DATABASE_URL must be set in .env";
}
}
mod connection_settings {
pub const MAXCONN: u32 = 5;
}
@@ -19,13 +11,12 @@ mod connection_settings {
pub mod db {
use sqlx::postgres::PgPoolOptions;
use std::env;
use crate::{connection_settings, keys};
use crate::connection_settings;
pub async fn create_pool() -> Result<sqlx::PgPool, sqlx::Error> {
let database_url = get_db_url().await;
println!("Database url: {:?}", database_url);
let database_url = icarus_envy::environment::get_db_url().await;
println!("Database url: {database_url}");
PgPoolOptions::new()
.max_connections(connection_settings::MAXCONN)
@@ -33,12 +24,6 @@ pub mod db {
.await
}
async fn get_db_url() -> String {
#[cfg(debug_assertions)] // Example: Only load .env in debug builds
dotenvy::dotenv().ok();
env::var(keys::DBURL).expect(keys::error::ERROR)
}
pub async fn migrations(pool: &sqlx::PgPool) {
// Run migrations using the sqlx::migrate! macro
// Assumes your migrations are in a ./migrations folder relative to Cargo.toml
+97 -50
View File
@@ -41,6 +41,10 @@ mod init {
callers::endpoints::LOGIN,
post(callers::login::endpoint::login),
)
.route(
callers::endpoints::SERVICE_LOGIN,
post(callers::login::endpoint::service_login),
)
}
pub async fn app() -> Router {
@@ -69,24 +73,23 @@ mod tests {
mod db_mgr {
use std::str::FromStr;
use icarus_auth::keys;
pub const LIMIT: usize = 6;
pub async fn get_pool() -> Result<sqlx::PgPool, sqlx::Error> {
let tm_db_url = std::env::var(keys::DBURL).expect("DATABASE_URL must be present");
let tm_db_url = icarus_envy::environment::get_db_url().await;
let tm_options = sqlx::postgres::PgConnectOptions::from_str(&tm_db_url).unwrap();
sqlx::PgPool::connect_with(tm_options).await
}
pub async fn generate_db_name() -> String {
let db_name =
get_database_name().unwrap() + &"_" + &uuid::Uuid::new_v4().to_string()[..LIMIT];
let db_name = get_database_name().await.unwrap()
+ &"_"
+ &uuid::Uuid::new_v4().to_string()[..LIMIT];
db_name
}
pub async fn connect_to_db(db_name: &str) -> Result<sqlx::PgPool, sqlx::Error> {
let db_url = std::env::var(keys::DBURL).expect("DATABASE_URL must be set for tests");
let db_url = icarus_envy::environment::get_db_url().await;
let options = sqlx::postgres::PgConnectOptions::from_str(&db_url)?.database(db_name);
sqlx::PgPool::connect_with(options).await
}
@@ -112,29 +115,21 @@ mod tests {
Ok(())
}
pub fn get_database_name() -> Result<String, Box<dyn std::error::Error>> {
dotenvy::dotenv().ok(); // Load .env file if it exists
pub async fn get_database_name() -> Result<String, Box<dyn std::error::Error>> {
let database_url = icarus_envy::environment::get_db_url().await;
match std::env::var(keys::DBURL) {
Ok(database_url) => {
let parsed_url = url::Url::parse(&database_url)?;
if parsed_url.scheme() == "postgres" || parsed_url.scheme() == "postgresql" {
match parsed_url
.path_segments()
.and_then(|segments| segments.last().map(|s| s.to_string()))
{
Some(sss) => Ok(sss),
None => Err("Error parsing".into()),
}
} else {
// Handle other database types if needed
Err("Error parsing".into())
}
}
Err(_) => {
// DATABASE_URL environment variable not found
Err("Error parsing".into())
let parsed_url = url::Url::parse(&database_url)?;
if parsed_url.scheme() == "postgres" || parsed_url.scheme() == "postgresql" {
match parsed_url
.path_segments()
.and_then(|segments| segments.last().map(|s| s.to_string()))
{
Some(sss) => Ok(sss),
None => Err("Error parsing".into()),
}
} else {
// Handle other database types if needed
Err("Error parsing".into())
}
}
}
@@ -163,6 +158,25 @@ mod tests {
})
}
pub mod requests {
use tower::ServiceExt; // for `call`, `oneshot`, and `ready`
pub async fn register(
app: &axum::Router,
usr: &icarus_auth::callers::register::request::Request,
) -> Result<axum::response::Response, std::convert::Infallible> {
let payload = super::get_test_register_payload(&usr);
let req = axum::http::Request::builder()
.method(axum::http::Method::POST)
.uri(crate::callers::endpoints::REGISTER)
.header(axum::http::header::CONTENT_TYPE, "application/json")
.body(axum::body::Body::from(payload.to_string()))
.unwrap();
app.clone().oneshot(req).await
}
}
#[tokio::test]
async fn test_hello_world() {
let app = init::app().await;
@@ -207,18 +221,8 @@ mod tests {
let app = init::routes().await.layer(axum::Extension(pool));
let usr = get_test_register_request();
let payload = get_test_register_payload(&usr);
let response = app
.oneshot(
Request::builder()
.method(axum::http::Method::POST)
.uri(callers::endpoints::REGISTER)
.header(axum::http::header::CONTENT_TYPE, "application/json")
.body(Body::from(payload.to_string()))
.unwrap(),
)
.await;
let response = requests::register(&app, &usr).await;
match response {
Ok(resp) => {
@@ -274,19 +278,8 @@ mod tests {
let app = init::routes().await.layer(axum::Extension(pool));
let usr = get_test_register_request();
let payload = get_test_register_payload(&usr);
let response = app
.clone()
.oneshot(
Request::builder()
.method(axum::http::Method::POST)
.uri(callers::endpoints::REGISTER)
.header(axum::http::header::CONTENT_TYPE, "application/json")
.body(Body::from(payload.to_string()))
.unwrap(),
)
.await;
let response = requests::register(&app, &usr).await;
match response {
Ok(resp) => {
@@ -350,4 +343,58 @@ mod tests {
let _ = db_mgr::drop_database(&tm_pool, &db_name).await;
}
#[tokio::test]
async fn test_service_login_user() {
let tm_pool = db_mgr::get_pool().await.unwrap();
let db_name = db_mgr::generate_db_name().await;
match db_mgr::create_database(&tm_pool, &db_name).await {
Ok(_) => {
println!("Success");
}
Err(e) => {
assert!(false, "Error: {:?}", e.to_string());
}
}
let pool = db_mgr::connect_to_db(&db_name).await.unwrap();
icarus_auth::db::migrations(&pool).await;
let app = init::routes().await.layer(axum::Extension(pool));
let passphrase =
String::from("iUOo1fxshf3y1tUGn1yU8l9raPApHCdinW0VdCHdRFEjqhR3Bf02aZzsKbLtaDFH");
let payload = serde_json::json!({
"passphrase": passphrase
});
match app
.oneshot(
Request::builder()
.method(axum::http::Method::POST)
.uri(callers::endpoints::SERVICE_LOGIN)
.header(axum::http::header::CONTENT_TYPE, "application/json")
.body(Body::from(payload.to_string()))
.unwrap(),
)
.await
{
Ok(response) => {
assert_eq!(StatusCode::OK, response.status(), "Status is not right");
let body = axum::body::to_bytes(response.into_body(), usize::MAX)
.await
.unwrap();
let parsed_body: callers::login::response::service_login::Response =
serde_json::from_slice(&body).unwrap();
let _login_result = &parsed_body.data[0];
}
Err(err) => {
assert!(false, "Error: {err:?}");
}
}
let _ = db_mgr::drop_database(&tm_pool, &db_name).await;
}
}
+32 -3
View File
@@ -57,7 +57,7 @@ pub mod user {
.fetch_optional(pool)
.await
.map_err(|e| {
eprintln!("Error updating time: {}", e);
eprintln!("Error updating time: {e}");
e
});
@@ -113,7 +113,7 @@ pub mod user {
.fetch_one(pool)
.await
.map_err(|e| {
eprintln!("Error inserting item: {}", e);
eprintln!("Error inserting item: {e}");
e
})?;
@@ -180,7 +180,7 @@ pub mod salt {
.fetch_one(pool)
.await
.map_err(|e| {
eprintln!("Error inserting item: {}", e);
eprintln!("Error inserting item: {e}");
e
})?;
@@ -195,3 +195,32 @@ pub mod salt {
}
}
}
pub mod service {
use sqlx::Row;
pub async fn valid_passphrase(
pool: &sqlx::PgPool,
passphrase: &String,
) -> Result<(uuid::Uuid, String, time::OffsetDateTime), sqlx::Error> {
let result = sqlx::query(
r#"
SELECT * FROM "passphrase" WHERE passphrase = $1
"#,
)
.bind(passphrase)
.fetch_one(pool)
.await;
match result {
Ok(row) => {
let id: uuid::Uuid = row.try_get("id")?;
let passphrase: String = row.try_get("passphrase")?;
let date_created: Option<time::OffsetDateTime> = row.try_get("date_created")?;
Ok((id, passphrase, date_created.unwrap()))
}
Err(err) => Err(err),
}
}
}
+18 -46
View File
@@ -1,23 +1,16 @@
use josekit::{
self,
jws::{JwsHeader, alg::hmac::HmacJwsAlgorithm::Hs256},
jwt::{self, JwtPayload},
jws::alg::hmac::HmacJwsAlgorithm::Hs256,
jwt::{self},
};
use time;
pub const TOKENTYPE: &str = "JWT";
pub const KEY_ENV: &str = "SECRET_KEY";
pub const MESSAGE: &str = "Something random";
pub const ISSUER: &str = "icarus_auth";
pub const AUDIENCE: &str = "icarus";
pub fn get_key() -> Result<String, dotenvy::Error> {
dotenvy::dotenv().ok();
let key = std::env::var(KEY_ENV).expect("SECRET_KEY_NOT_FOUND");
Ok(key)
}
pub fn get_issued() -> time::Result<time::OffsetDateTime> {
Ok(time::OffsetDateTime::now_utc())
}
@@ -27,43 +20,22 @@ pub fn get_expiration(issued: &time::OffsetDateTime) -> Result<time::OffsetDateT
Ok(*issued + duration_expire)
}
mod util {
pub fn time_to_std_time(
provided_time: &time::OffsetDateTime,
) -> Result<std::time::SystemTime, std::time::SystemTimeError> {
let converted = std::time::SystemTime::from(*provided_time);
Ok(converted)
}
pub fn create_token(provided_key: &String) -> Result<(String, i64), josekit::JoseError> {
let resource = icarus_models::token::TokenResource {
message: String::from(MESSAGE),
issuer: String::from(ISSUER),
audiences: vec![String::from(AUDIENCE)],
};
icarus_models::token::create_token(provided_key, &resource, time::Duration::hours(4))
}
pub fn create_token(provided_key: &String) -> Result<(String, i64), josekit::JoseError> {
let mut header = JwsHeader::new();
header.set_token_type(TOKENTYPE);
let mut payload = JwtPayload::new();
payload.set_subject(MESSAGE);
payload.set_issuer(ISSUER);
payload.set_audience(vec![AUDIENCE]);
match get_issued() {
Ok(issued) => {
let expire = get_expiration(&issued).unwrap();
payload.set_issued_at(&util::time_to_std_time(&issued).unwrap());
payload.set_expires_at(&util::time_to_std_time(&expire).unwrap());
let key: String = if provided_key.is_empty() {
get_key().unwrap()
} else {
provided_key.to_owned()
};
let signer = Hs256.signer_from_bytes(key.as_bytes()).unwrap();
Ok((
josekit::jwt::encode_with_signer(&payload, &header, &signer).unwrap(),
(expire - time::OffsetDateTime::UNIX_EPOCH).whole_seconds(),
))
}
Err(e) => Err(josekit::JoseError::InvalidClaim(e.into())),
}
pub fn create_service_token(provided: &String) -> Result<(String, i64), josekit::JoseError> {
let resource = icarus_models::token::TokenResource {
message: String::from("Service random"),
issuer: String::from(ISSUER),
audiences: vec![String::from(AUDIENCE)],
};
icarus_models::token::create_token(provided, &resource, time::Duration::hours(1))
}
pub fn verify_token(key: &String, token: &String) -> bool {
@@ -77,12 +49,12 @@ pub fn verify_token(key: &String, token: &String) -> bool {
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_tokenize() {
let special_key = get_key().unwrap();
let rt = tokio::runtime::Runtime::new().unwrap();
let special_key = rt.block_on(icarus_envy::environment::get_secret_key());
match create_token(&special_key) {
Ok((token, _duration)) => {
let result = verify_token(&special_key, &token);