Compare commits

..

1 Commits

Author SHA1 Message Date
eb7e394cf0 Next release (#27)
All checks were successful
Rust Build / Check (push) Successful in 53s
Rust Build / Test Suite (push) Successful in 1m2s
Rust Build / Rustfmt (push) Successful in 32s
Rust Build / Clippy (push) Successful in 59s
Rust Build / build (push) Successful in 1m20s
Reviewed-on: #27
2025-04-12 00:27:47 +00:00
17 changed files with 106 additions and 2619 deletions

View File

@@ -5,8 +5,6 @@ pkg/
# Ignore git directory # Ignore git directory
.git/ .git/
.gitea/
# Ignore environment files (configure via docker-compose instead) # Ignore environment files (configure via docker-compose instead)
.env* .env*

View File

@@ -1,6 +0,0 @@
SECRET_KEY=refero34o8rfhfjn983thf39fhc943rf923n3h
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}

View File

@@ -1,6 +1,2 @@
SECRET_KEY=refero34o8rfhfjn983thf39fhc943rf923n3h DATABASE_URL=postgres://username:password@localhost/database_name
POSTGRES_AUTH_USER=icarus_op_test SECRET_KEY=refero34o8rfhfjn983thf39fhc943rf923n3h
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}

View File

@@ -17,7 +17,7 @@ jobs:
- name: Install Rust - name: Install Rust
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
toolchain: 1.88.0 toolchain: 1.86.0
components: cargo components: cargo
- name: Extract Version from Cargo.toml - name: Extract Version from Cargo.toml
@@ -50,4 +50,4 @@ jobs:
body: | body: |
Release of version ${{ steps.version.outputs.project_tag_release }} Release of version ${{ steps.version.outputs.project_tag_release }}
# draft: false # draft: false
# prerelease: ${{ startsWith(github.ref, 'v') == false }} # prerelease if not a valid release tag # prerelease: ${{ startsWith(github.ref, 'v') == false }} # prerelease if not a valid release tag

View File

@@ -18,7 +18,7 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: actions-rust-lang/setup-rust-toolchain@v1 - uses: actions-rust-lang/setup-rust-toolchain@v1
with: with:
toolchain: 1.88.0 toolchain: 1.86.0
- run: | - run: |
mkdir -p ~/.ssh mkdir -p ~/.ssh
echo "${{ secrets.MYREPO_TOKEN }}" > ~/.ssh/icarus_models_deploy_key echo "${{ secrets.MYREPO_TOKEN }}" > ~/.ssh/icarus_models_deploy_key
@@ -53,7 +53,7 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: actions-rust-lang/setup-rust-toolchain@v1 - uses: actions-rust-lang/setup-rust-toolchain@v1
with: with:
toolchain: 1.88.0 toolchain: 1.86.0
# --- Add this step for explicit verification --- # --- Add this step for explicit verification ---
- name: Verify Docker Environment - name: Verify Docker Environment
run: | run: |
@@ -94,7 +94,7 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: actions-rust-lang/setup-rust-toolchain@v1 - uses: actions-rust-lang/setup-rust-toolchain@v1
with: with:
toolchain: 1.88.0 toolchain: 1.86.0
- run: rustup component add rustfmt - run: rustup component add rustfmt
- run: | - run: |
mkdir -p ~/.ssh mkdir -p ~/.ssh
@@ -113,7 +113,7 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: actions-rust-lang/setup-rust-toolchain@v1 - uses: actions-rust-lang/setup-rust-toolchain@v1
with: with:
toolchain: 1.88.0 toolchain: 1.86.0
- run: rustup component add clippy - run: rustup component add clippy
- run: | - run: |
mkdir -p ~/.ssh mkdir -p ~/.ssh
@@ -132,7 +132,7 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: actions-rust-lang/setup-rust-toolchain@v1 - uses: actions-rust-lang/setup-rust-toolchain@v1
with: with:
toolchain: 1.88.0 toolchain: 1.86.0
- run: | - run: |
mkdir -p ~/.ssh mkdir -p ~/.ssh
echo "${{ secrets.MYREPO_TOKEN }}" > ~/.ssh/icarus_models_deploy_key echo "${{ secrets.MYREPO_TOKEN }}" > ~/.ssh/icarus_models_deploy_key

1
.gitignore vendored
View File

@@ -1,2 +1,3 @@
/target /target
Cargo.lock
.env .env

2527
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,8 @@
[package] [package]
name = "icarus_auth" name = "icarus_auth"
version = "0.3.10" version = "0.3.4"
edition = "2024" edition = "2024"
rust-version = "1.88" rust-version = "1.86"
[dependencies] [dependencies]
axum = { version = "0.8.3" } axum = { version = "0.8.3" }
@@ -13,13 +13,13 @@ tracing-subscriber = { version = "0.3.19" }
tower = { version = "0.5.2" } tower = { version = "0.5.2" }
hyper = { version = "1.6.0" } hyper = { version = "1.6.0" }
sqlx = { version = "0.8.3", features = ["postgres", "runtime-tokio-native-tls", "time", "uuid"] } 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"] } uuid = { version = "1.16.0", features = ["v4", "serde"] }
argon2 = { version = "0.5.3", features = ["std"] } # Use the latest 0.5.x version argon2 = { version = "0.5.3", features = ["std"] } # Use the latest 0.5.x version
rand = { version = "0.9" } rand = { version = "0.9" }
time = { version = "0.3.41", features = ["macros", "serde"] } time = { version = "0.3.41", features = ["macros", "serde"] }
josekit = { version = "0.10.1" } josekit = { version = "0.10.1" }
icarus_models = { git = "ssh://git@git.kundeng.us/phoenix/icarus_models.git", tag = "v0.4.3" } icarus_models = { git = "ssh://git@git.kundeng.us/phoenix/icarus_models.git", tag = "v0.4.1" }
icarus_envy = { git = "ssh://git@git.kundeng.us/phoenix/icarus_envy.git", tag = "v0.2.0-devel-dbe4dc67cb-950" }
[dev-dependencies] [dev-dependencies]
http-body-util = { version = "0.1.3" } http-body-util = { version = "0.1.3" }

View File

@@ -34,6 +34,8 @@ RUN --mount=type=ssh mkdir src && \
# Copy the actual source code # Copy the actual source code
COPY src ./src COPY src ./src
# If you have other directories like `templates` or `static`, copy them too # If you have other directories like `templates` or `static`, copy them too
# COPY templates ./templates
# COPY static ./static
COPY .env ./.env COPY .env ./.env
COPY migrations ./migrations COPY migrations ./migrations
@@ -62,6 +64,8 @@ COPY --from=builder /usr/src/app/target/release/icarus_auth .
# It's generally better to configure via environment variables in Docker though # It's generally better to configure via environment variables in Docker though
COPY --from=builder /usr/src/app/.env . COPY --from=builder /usr/src/app/.env .
COPY --from=builder /usr/src/app/migrations ./migrations COPY --from=builder /usr/src/app/migrations ./migrations
# COPY --from=builder /usr/src/app/templates ./templates
# COPY --from=builder /usr/src/app/static ./static
# Expose the port your Axum app listens on (e.g., 3000 or 8000) # Expose the port your Axum app listens on (e.g., 3000 or 8000)
EXPOSE 3000 EXPOSE 3000

View File

@@ -1,26 +0,0 @@
# 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
```

View File

@@ -2,34 +2,43 @@ version: '3.8' # Use a recent version
services: services:
# Your Rust Application Service # Your Rust Application Service
auth_api: app:
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 container_name: icarus_auth # Optional: Give the container a specific name
ports: ports:
# Map host port 8000 to container port 3000 (adjust as needed) # Map host port 8000 to container port 3000 (adjust as needed)
# Format: "HOST_PORT:CONTAINER_PORT"
- "8000:3000" - "8000:3000"
env_file: environment:
- .env # Pass environment variables to your Rust application
# RUST_LOG: info # Example: Set log level
# IMPORTANT: Configure DATABASE_URL to connect to the 'db' service
# The hostname 'db' matches the service name defined below.
DATABASE_URL: postgresql://icarus_op:password@db:5432/icarus_auth
# Add any other environment variables your app needs
# APP_HOST: 0.0.0.0
# APP_PORT: 3000
depends_on: depends_on:
auth_db: db:
condition: service_healthy # Wait for the DB to be healthy before starting the app condition: service_healthy # Wait for the DB to be healthy before starting the app
restart: unless-stopped # Optional: Restart policy restart: unless-stopped # Optional: Restart policy
# PostgreSQL Database Service # PostgreSQL Database Service
auth_db: db:
image: postgres:17.4-alpine # Use an official Postgres image (Alpine variant is smaller) image: postgres:17.4-alpine # Use an official Postgres image (Alpine variant is smaller)
container_name: icarus_auth_db # Optional: Give the container a specific name container_name: icarus_auth_db # Optional: Give the container a specific name
environment: environment:
# These MUST match the user, password, and database name in the DATABASE_URL above # These MUST match the user, password, and database name in the DATABASE_URL above
POSTGRES_USER: ${POSTGRES_AUTH_USER:-icarus_op} POSTGRES_USER: icarus_op
POSTGRES_PASSWORD: ${POSTGRES_AUTH_PASSWORD:-password} POSTGRES_PASSWORD: password
POSTGRES_DB: ${POSTGRES_AUTH_DB:-icarus_auth_db} POSTGRES_DB: icarus_auth
volumes: volumes:
# Persist database data using a named volume # Persist database data using a named volume
- postgres_data:/var/lib/postgresql/data - postgres_data:/var/lib/postgresql/data
ports: [] ports: []
# Optional: Expose port 5432 ONLY if you need to connect directly from your host machine (e.g., for debugging)
# - "5432:5432"
# pass:
healthcheck: healthcheck:
# Checks if Postgres is ready to accept connections # Checks if Postgres is ready to accept connections
test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"] test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"]
@@ -42,4 +51,4 @@ services:
# Define the named volume for data persistence # Define the named volume for data persistence
volumes: volumes:
postgres_data: postgres_data:
driver: local # Use the default local driver driver: local # Use the default local driver

13
docker_run.txt Normal file
View File

@@ -0,0 +1,13 @@
# Docker stuff
#Build app
docker-compose build --ssh default app
# Rebuild and bring up
docker-compose up -d --force-recreate app
# Bring it down
docker-compose down -v
# Pruning
docker system prune -a

View File

@@ -1,5 +1,3 @@
TODO: At some point, move this somewhere that is appropriate
# Make sure role has CREATEDB # Make sure role has CREATEDB
ALTER ROLE username_that_needs_permission CREATEDB; ALTER ROLE username_that_needs_permission CREATEDB;

View File

@@ -47,7 +47,7 @@ pub mod endpoint {
Ok(user) => { Ok(user) => {
if hashing::verify_password(&payload.password, user.password.clone()).unwrap() { if hashing::verify_password(&payload.password, user.password.clone()).unwrap() {
// Create token // Create token
let key = icarus_envy::environment::get_secret_key().await; let key = token_stuff::get_key().unwrap();
let (token_literal, duration) = token_stuff::create_token(&key).unwrap(); let (token_literal, duration) = token_stuff::create_token(&key).unwrap();
if token_stuff::verify_token(&key, &token_literal) { if token_stuff::verify_token(&key, &token_literal) {

View File

@@ -4,6 +4,14 @@ pub mod hashing;
pub mod repo; pub mod repo;
pub mod token_stuff; 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 { mod connection_settings {
pub const MAXCONN: u32 = 5; pub const MAXCONN: u32 = 5;
} }
@@ -11,11 +19,12 @@ mod connection_settings {
pub mod db { pub mod db {
use sqlx::postgres::PgPoolOptions; use sqlx::postgres::PgPoolOptions;
use std::env;
use crate::connection_settings; use crate::{connection_settings, keys};
pub async fn create_pool() -> Result<sqlx::PgPool, sqlx::Error> { pub async fn create_pool() -> Result<sqlx::PgPool, sqlx::Error> {
let database_url = icarus_envy::environment::get_db_url().await; let database_url = get_db_url().await;
println!("Database url: {:?}", database_url); println!("Database url: {:?}", database_url);
PgPoolOptions::new() PgPoolOptions::new()
@@ -24,6 +33,13 @@ pub mod db {
.await .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) { pub async fn migrations(pool: &sqlx::PgPool) {
// Run migrations using the sqlx::migrate! macro // Run migrations using the sqlx::migrate! macro
// Assumes your migrations are in a ./migrations folder relative to Cargo.toml // Assumes your migrations are in a ./migrations folder relative to Cargo.toml

View File

@@ -69,23 +69,24 @@ mod tests {
mod db_mgr { mod db_mgr {
use std::str::FromStr; use std::str::FromStr;
use icarus_auth::keys;
pub const LIMIT: usize = 6; pub const LIMIT: usize = 6;
pub async fn get_pool() -> Result<sqlx::PgPool, sqlx::Error> { pub async fn get_pool() -> Result<sqlx::PgPool, sqlx::Error> {
let tm_db_url = icarus_envy::environment::get_db_url().await; let tm_db_url = std::env::var(keys::DBURL).expect("DATABASE_URL must be present");
let tm_options = sqlx::postgres::PgConnectOptions::from_str(&tm_db_url).unwrap(); let tm_options = sqlx::postgres::PgConnectOptions::from_str(&tm_db_url).unwrap();
sqlx::PgPool::connect_with(tm_options).await sqlx::PgPool::connect_with(tm_options).await
} }
pub async fn generate_db_name() -> String { pub async fn generate_db_name() -> String {
let db_name = get_database_name().await.unwrap() let db_name =
+ &"_" get_database_name().unwrap() + &"_" + &uuid::Uuid::new_v4().to_string()[..LIMIT];
+ &uuid::Uuid::new_v4().to_string()[..LIMIT];
db_name db_name
} }
pub async fn connect_to_db(db_name: &str) -> Result<sqlx::PgPool, sqlx::Error> { pub async fn connect_to_db(db_name: &str) -> Result<sqlx::PgPool, sqlx::Error> {
let db_url = icarus_envy::environment::get_db_url().await; let db_url = std::env::var(keys::DBURL).expect("DATABASE_URL must be set for tests");
let options = sqlx::postgres::PgConnectOptions::from_str(&db_url)?.database(db_name); let options = sqlx::postgres::PgConnectOptions::from_str(&db_url)?.database(db_name);
sqlx::PgPool::connect_with(options).await sqlx::PgPool::connect_with(options).await
} }
@@ -111,21 +112,29 @@ mod tests {
Ok(()) Ok(())
} }
pub async fn get_database_name() -> Result<String, Box<dyn std::error::Error>> { pub fn get_database_name() -> Result<String, Box<dyn std::error::Error>> {
let database_url = icarus_envy::environment::get_db_url().await; dotenvy::dotenv().ok(); // Load .env file if it exists
let parsed_url = url::Url::parse(&database_url)?; match std::env::var(keys::DBURL) {
if parsed_url.scheme() == "postgres" || parsed_url.scheme() == "postgresql" { Ok(database_url) => {
match parsed_url let parsed_url = url::Url::parse(&database_url)?;
.path_segments() if parsed_url.scheme() == "postgres" || parsed_url.scheme() == "postgresql" {
.and_then(|segments| segments.last().map(|s| s.to_string())) match parsed_url
{ .path_segments()
Some(sss) => Ok(sss), .and_then(|segments| segments.last().map(|s| s.to_string()))
None => Err("Error parsing".into()), {
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())
} }
} else {
// Handle other database types if needed
Err("Error parsing".into())
} }
} }
} }

View File

@@ -12,6 +12,12 @@ pub const MESSAGE: &str = "Something random";
pub const ISSUER: &str = "icarus_auth"; pub const ISSUER: &str = "icarus_auth";
pub const AUDIENCE: &str = "icarus"; 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> { pub fn get_issued() -> time::Result<time::OffsetDateTime> {
Ok(time::OffsetDateTime::now_utc()) Ok(time::OffsetDateTime::now_utc())
} }
@@ -45,10 +51,7 @@ pub fn create_token(provided_key: &String) -> Result<(String, i64), josekit::Jos
payload.set_expires_at(&util::time_to_std_time(&expire).unwrap()); payload.set_expires_at(&util::time_to_std_time(&expire).unwrap());
let key: String = if provided_key.is_empty() { let key: String = if provided_key.is_empty() {
let rt = tokio::runtime::Runtime::new().unwrap(); get_key().unwrap()
// Block on the async function to get the result
rt.block_on(icarus_envy::environment::get_secret_key())
} else { } else {
provided_key.to_owned() provided_key.to_owned()
}; };
@@ -79,8 +82,7 @@ mod tests {
#[test] #[test]
fn test_tokenize() { fn test_tokenize() {
let rt = tokio::runtime::Runtime::new().unwrap(); let special_key = get_key().unwrap();
let special_key = rt.block_on(icarus_envy::environment::get_secret_key());
match create_token(&special_key) { match create_token(&special_key) {
Ok((token, _duration)) => { Ok((token, _duration)) => {
let result = verify_token(&special_key, &token); let result = verify_token(&special_key, &token);