Signed-off-by: Till Wegmueller <toasterson@gmail.com>
This commit is contained in:
Till Wegmueller 2026-01-06 12:31:51 +01:00
parent ecd6b00a1e
commit a949a3cbdb
No known key found for this signature in database
6 changed files with 144 additions and 86 deletions

View file

@ -341,7 +341,10 @@ mod tests {
assert!(execution.completed_at.is_some());
assert_eq!(execution.success, Some(0));
assert_eq!(execution.error_message, Some("Test error message".to_string()));
assert_eq!(
execution.error_message,
Some("Test error message".to_string())
);
assert!(execution.records_processed.is_none());
}

View file

@ -102,8 +102,8 @@ fn random_kid() -> String {
#[cfg(test)]
mod tests {
use super::*;
use tempfile::TempDir;
use std::path::PathBuf;
use tempfile::TempDir;
/// Helper to create test Keys config
fn test_keys_config(temp_dir: &TempDir) -> Keys {
@ -156,10 +156,9 @@ mod tests {
assert!(cfg.private_key_path.exists());
// Verify it contains valid JSON JWK
let content = fs::read_to_string(&cfg.private_key_path)
.expect("Failed to read private key");
let jwk: Jwk = serde_json::from_str(&content)
.expect("Failed to parse private key JSON");
let content =
fs::read_to_string(&cfg.private_key_path).expect("Failed to read private key");
let jwk: Jwk = serde_json::from_str(&content).expect("Failed to parse private key JSON");
assert_eq!(jwk.key_type(), "RSA");
assert!(jwk.parameter("d").is_some()); // Private exponent exists
@ -178,10 +177,8 @@ mod tests {
assert!(cfg.jwks_path.exists());
// Verify it contains valid JWKS structure
let content = fs::read_to_string(&cfg.jwks_path)
.expect("Failed to read JWKS");
let jwks: Value = serde_json::from_str(&content)
.expect("Failed to parse JWKS JSON");
let content = fs::read_to_string(&cfg.jwks_path).expect("Failed to read JWKS");
let jwks: Value = serde_json::from_str(&content).expect("Failed to parse JWKS JSON");
assert!(jwks.get("keys").is_some());
assert!(jwks["keys"].is_array());
@ -220,10 +217,7 @@ mod tests {
let jwk1 = manager1.private_jwk();
let jwk2 = manager2.private_jwk();
assert_eq!(
jwk1.parameter("n"),
jwk2.parameter("n")
);
assert_eq!(jwk1.parameter("n"), jwk2.parameter("n"));
}
#[tokio::test]
@ -239,11 +233,13 @@ mod tests {
let mut payload = JwtPayload::new();
payload.set_issuer("https://example.com");
payload.set_subject("user123");
let exp_time: std::time::SystemTime = (chrono::Utc::now() + chrono::Duration::hours(1)).into();
let exp_time: std::time::SystemTime =
(chrono::Utc::now() + chrono::Duration::hours(1)).into();
payload.set_expires_at(&exp_time);
// Sign the JWT
let token = manager.sign_jwt_rs256(&payload)
let token = manager
.sign_jwt_rs256(&payload)
.expect("Failed to sign JWT");
// Verify token is not empty and has 3 parts (header.payload.signature)
@ -252,10 +248,9 @@ mod tests {
assert_eq!(parts.len(), 3);
// Decode and verify header contains kid
let header_json = base64ct::Base64UrlUnpadded::decode_vec(parts[0])
.expect("Failed to decode header");
let header: Value = serde_json::from_slice(&header_json)
.expect("Failed to parse header");
let header_json =
base64ct::Base64UrlUnpadded::decode_vec(parts[0]).expect("Failed to decode header");
let header: Value = serde_json::from_slice(&header_json).expect("Failed to parse header");
assert_eq!(header["alg"], "RS256");
assert_eq!(header["kid"], "test-kid-123");
@ -311,7 +306,9 @@ mod tests {
// Verify all are valid base64url
for kid in [kid1, kid2, kid3] {
assert!(kid.chars().all(|c| c.is_ascii_alphanumeric() || c == '-' || c == '_'));
assert!(kid
.chars()
.all(|c| c.is_ascii_alphanumeric() || c == '-' || c == '_'));
}
}
}

View file

@ -160,8 +160,8 @@ mod tests {
let config_path = temp_dir.path().join("nonexistent.toml");
// Load settings with nonexistent file - should use defaults
let settings = Settings::load(config_path.to_str().unwrap())
.expect("Failed to load settings");
let settings =
Settings::load(config_path.to_str().unwrap()).expect("Failed to load settings");
assert_eq!(settings.server.host, "0.0.0.0");
assert_eq!(settings.server.port, 8080);
@ -194,8 +194,8 @@ private_key_path = "test_private.pem"
fs::write(&config_path, config_content).expect("Failed to write config");
// Load settings
let settings = Settings::load(config_path.to_str().unwrap())
.expect("Failed to load settings");
let settings =
Settings::load(config_path.to_str().unwrap()).expect("Failed to load settings");
assert_eq!(settings.server.host, "127.0.0.1");
assert_eq!(settings.server.port, 9090);
@ -204,7 +204,10 @@ private_key_path = "test_private.pem"
Some("https://idp.example.com".to_string())
);
assert_eq!(settings.server.allow_public_registration, true);
assert_eq!(settings.database.url, "postgresql://user:pass@localhost/testdb");
assert_eq!(
settings.database.url,
"postgresql://user:pass@localhost/testdb"
);
}
#[test]
@ -225,8 +228,8 @@ port = 8080
env::set_var("BARYCENTER__SERVER__HOST", "192.168.1.1");
// Load settings - env should override file
let settings = Settings::load(config_path.to_str().unwrap())
.expect("Failed to load settings");
let settings =
Settings::load(config_path.to_str().unwrap()).expect("Failed to load settings");
assert_eq!(settings.server.host, "192.168.1.1");
assert_eq!(settings.server.port, 9999);
@ -287,8 +290,8 @@ private_key_path = "relative/private.pem"
"#;
fs::write(&config_path, config_content).expect("Failed to write config");
let settings = Settings::load(config_path.to_str().unwrap())
.expect("Failed to load settings");
let settings =
Settings::load(config_path.to_str().unwrap()).expect("Failed to load settings");
// Paths should be normalized to absolute
assert!(settings.keys.jwks_path.is_absolute());
@ -296,7 +299,10 @@ private_key_path = "relative/private.pem"
// Should end with the relative path components
assert!(settings.keys.jwks_path.ends_with("relative/jwks.json"));
assert!(settings.keys.private_key_path.ends_with("relative/private.pem"));
assert!(settings
.keys
.private_key_path
.ends_with("relative/private.pem"));
}
#[test]

View file

@ -5,7 +5,8 @@ use base64ct::Encoding;
use chrono::Utc;
use rand::RngCore;
use sea_orm::{
ActiveModelTrait, ColumnTrait, Database, DatabaseConnection, EntityTrait, QueryFilter, QueryOrder, Set,
ActiveModelTrait, ColumnTrait, Database, DatabaseConnection, EntityTrait, QueryFilter,
QueryOrder, Set,
};
use serde::{Deserialize, Serialize};
use serde_json::Value;
@ -884,10 +885,7 @@ pub async fn update_passkey_name(
Ok(())
}
pub async fn delete_passkey(
db: &DatabaseConnection,
credential_id: &str,
) -> Result<(), CrabError> {
pub async fn delete_passkey(db: &DatabaseConnection, credential_id: &str) -> Result<(), CrabError> {
use entities::passkey::{Column, Entity};
Entity::delete_many()
@ -1306,7 +1304,10 @@ mod tests {
let past_timestamp = chrono::Utc::now().timestamp() - 600; // 10 minutes ago
Entity::update_many()
.col_expr(Column::ExpiresAt, sea_orm::sea_query::Expr::value(past_timestamp))
.col_expr(
Column::ExpiresAt,
sea_orm::sea_query::Expr::value(past_timestamp),
)
.filter(Column::Code.eq(&code.code))
.exec(db)
.await
@ -1358,7 +1359,11 @@ mod tests {
let test_db = TestDb::new().await;
let db = test_db.connection();
let token = issue_access_token(&db, "test_client_id", "test_subject", "openid profile",
let token = issue_access_token(
&db,
"test_client_id",
"test_subject",
"openid profile",
3600, // TTL
)
.await
@ -1372,7 +1377,11 @@ mod tests {
let test_db = TestDb::new().await;
let db = test_db.connection();
let token = issue_access_token(&db, "test_client_id", "test_subject", "openid profile",
let token = issue_access_token(
&db,
"test_client_id",
"test_subject",
"openid profile",
3600, // TTL
)
.await
@ -1393,7 +1402,11 @@ mod tests {
let test_db = TestDb::new().await;
let db = test_db.connection();
let token = issue_access_token(&db, "test_client_id", "test_subject", "openid profile",
let token = issue_access_token(
&db,
"test_client_id",
"test_subject",
"openid profile",
3600, // TTL
)
.await
@ -1406,7 +1419,10 @@ mod tests {
let past_timestamp = chrono::Utc::now().timestamp() - 7200; // 2 hours ago
Entity::update_many()
.col_expr(Column::ExpiresAt, sea_orm::sea_query::Expr::value(past_timestamp))
.col_expr(
Column::ExpiresAt,
sea_orm::sea_query::Expr::value(past_timestamp),
)
.filter(Column::Token.eq(&token.token))
.exec(db)
.await
@ -1425,7 +1441,11 @@ mod tests {
let test_db = TestDb::new().await;
let db = test_db.connection();
let token = issue_access_token(&db, "test_client_id", "test_subject", "openid profile",
let token = issue_access_token(
&db,
"test_client_id",
"test_subject",
"openid profile",
3600, // TTL
)
.await
@ -1456,7 +1476,11 @@ mod tests {
let db = test_db.connection();
// Create initial refresh token
let token1 = issue_refresh_token(&db, "test_subject", "test_client_id", "openid profile",
let token1 = issue_refresh_token(
&db,
"test_subject",
"test_client_id",
"openid profile",
86400, // TTL
None, // parent_token
)
@ -1464,7 +1488,14 @@ mod tests {
.expect("Failed to issue refresh token");
// Rotate to new token
let token2 = issue_refresh_token(&db, "test_client_id", "test_subject", "openid profile", 86400, Some(token1.token.clone()))
let token2 = issue_refresh_token(
&db,
"test_client_id",
"test_subject",
"openid profile",
86400,
Some(token1.token.clone()),
)
.await
.expect("Failed to rotate refresh token");
@ -1482,7 +1513,11 @@ mod tests {
let test_db = TestDb::new().await;
let db = test_db.connection();
let token = issue_refresh_token(&db, "test_subject", "test_client_id", "openid profile",
let token = issue_refresh_token(
&db,
"test_subject",
"test_client_id",
"openid profile",
86400, // TTL
None, // parent_token
)
@ -1604,7 +1639,13 @@ mod tests {
.await
.expect("Failed to create user");
update_user(&db, &user.subject, false, Some("test@example.com".to_string()), Some(true))
update_user(
&db,
&user.subject,
false,
Some("test@example.com".to_string()),
Some(true),
)
.await
.expect("Failed to update user");
@ -1627,7 +1668,13 @@ mod tests {
.await
.expect("Failed to create user");
update_user(&db, &user.subject, true, Some("new@example.com".to_string()), None)
update_user(
&db,
&user.subject,
true,
Some("new@example.com".to_string()),
None,
)
.await
.expect("Failed to update email");

View file

@ -134,7 +134,11 @@ async fn sync_user(db: &DatabaseConnection, user_def: &UserDefinition) -> Result
db,
&existing_user.subject,
user_def.enabled,
if !email_matches { user_def.email.clone() } else { None },
if !email_matches {
user_def.email.clone()
} else {
None
},
None, // requires_2fa not set during sync
)
.await

View file

@ -1723,7 +1723,8 @@ async fn login_submit(
.map(String::from);
let now = chrono::Utc::now().timestamp();
let session = match storage::create_session(&state.db, &subject, now, 3600, user_agent, None).await {
let session =
match storage::create_session(&state.db, &subject, now, 3600, user_agent, None).await {
Ok(s) => s,
Err(_) => {
let return_to = urlencoded(&form.return_to.unwrap_or_default());