From 3360d3c8c784dbe028afc41754b7e2dfe4f67b49 Mon Sep 17 00:00:00 2001 From: CleverWild Date: Sun, 15 Mar 2026 19:24:21 +0100 Subject: [PATCH] feat(poc): add db and auth modules with terrors error chains --- server/crates/arbiter-terrors-poc/src/auth.rs | 64 +++++++++++++++++++ server/crates/arbiter-terrors-poc/src/db.rs | 28 ++++++++ .../crates/arbiter-terrors-poc/src/errors.rs | 3 + server/crates/arbiter-terrors-poc/src/main.rs | 2 + 4 files changed, 97 insertions(+) create mode 100644 server/crates/arbiter-terrors-poc/src/auth.rs create mode 100644 server/crates/arbiter-terrors-poc/src/db.rs diff --git a/server/crates/arbiter-terrors-poc/src/auth.rs b/server/crates/arbiter-terrors-poc/src/auth.rs new file mode 100644 index 0000000..d4e352a --- /dev/null +++ b/server/crates/arbiter-terrors-poc/src/auth.rs @@ -0,0 +1,64 @@ +use terrors::OneOf; +use crate::errors::{Internal, InvalidSignature, NotRegistered}; + +pub fn verify_signature(_nonce: u32, sig: &str) -> Result<(), OneOf<(InvalidSignature,)>> { + if sig != "ok" { + return Err(OneOf::new(InvalidSignature)); + } + Ok(()) +} + +pub fn authenticate( + id: u32, + sig: &str, +) -> Result> { + if id == 0 { + return Err(OneOf::new(NotRegistered)); + } + + let nonce = crate::db::get_nonce(id) + .map_err(|e| e.broaden::<(NotRegistered, InvalidSignature, Internal), _>())?; + verify_signature(nonce, sig) + .map_err(|e| e.broaden::<(NotRegistered, InvalidSignature, Internal), _>())?; + + Ok(nonce) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn verify_signature_ok() { + assert!(verify_signature(42, "ok").is_ok()); + } + + #[test] + fn verify_signature_bad() { + let err = verify_signature(42, "bad").unwrap_err(); + assert!(err.narrow::().is_ok()); + } + + #[test] + fn authenticate_success() { + assert_eq!(authenticate(1, "ok").unwrap(), 42); + } + + #[test] + fn authenticate_not_registered() { + let err = authenticate(0, "ok").unwrap_err(); + assert!(err.narrow::().is_ok()); + } + + #[test] + fn authenticate_invalid_signature() { + let err = authenticate(1, "bad").unwrap_err(); + assert!(err.narrow::().is_ok()); + } + + #[test] + fn authenticate_internal_error() { + let err = authenticate(99, "ok").unwrap_err(); + assert!(err.narrow::().is_ok()); + } +} diff --git a/server/crates/arbiter-terrors-poc/src/db.rs b/server/crates/arbiter-terrors-poc/src/db.rs new file mode 100644 index 0000000..b025505 --- /dev/null +++ b/server/crates/arbiter-terrors-poc/src/db.rs @@ -0,0 +1,28 @@ +use terrors::OneOf; +use crate::errors::Internal; + +// Simulates fetching a nonce from a database. +// id=99 is a sentinel that triggers an Internal error. +pub fn get_nonce(id: u32) -> Result> { + if id == 99 { + return Err(OneOf::new(Internal("db pool unavailable".into()))); + } + Ok(42) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn get_nonce_returns_nonce_for_valid_id() { + assert_eq!(get_nonce(1).unwrap(), 42); + } + + #[test] + fn get_nonce_returns_internal_error_for_sentinel() { + let err = get_nonce(99).unwrap_err(); + let internal = err.take::(); + assert_eq!(internal.0, "db pool unavailable"); + } +} diff --git a/server/crates/arbiter-terrors-poc/src/errors.rs b/server/crates/arbiter-terrors-poc/src/errors.rs index 0ef0061..b49d15b 100644 --- a/server/crates/arbiter-terrors-poc/src/errors.rs +++ b/server/crates/arbiter-terrors-poc/src/errors.rs @@ -9,8 +9,11 @@ pub enum ProtoError { } // Internal terrors types +#[derive(Debug)] pub struct NotRegistered; +#[derive(Debug)] pub struct InvalidSignature; +#[derive(Debug)] pub struct Internal(pub String); impl From for ProtoError { diff --git a/server/crates/arbiter-terrors-poc/src/main.rs b/server/crates/arbiter-terrors-poc/src/main.rs index f18efb5..a3bef62 100644 --- a/server/crates/arbiter-terrors-poc/src/main.rs +++ b/server/crates/arbiter-terrors-poc/src/main.rs @@ -1,3 +1,5 @@ mod errors; +mod db; +mod auth; fn main() {}