feat(poc): add db and auth modules with terrors error chains

This commit is contained in:
CleverWild
2026-03-15 19:24:21 +01:00
parent 02980468db
commit 3360d3c8c7
4 changed files with 97 additions and 0 deletions

View File

@@ -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<u32, OneOf<(NotRegistered, InvalidSignature, Internal)>> {
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::<crate::errors::InvalidSignature, _>().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::<crate::errors::NotRegistered, _>().is_ok());
}
#[test]
fn authenticate_invalid_signature() {
let err = authenticate(1, "bad").unwrap_err();
assert!(err.narrow::<crate::errors::InvalidSignature, _>().is_ok());
}
#[test]
fn authenticate_internal_error() {
let err = authenticate(99, "ok").unwrap_err();
assert!(err.narrow::<crate::errors::Internal, _>().is_ok());
}
}

View File

@@ -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<u32, OneOf<(Internal,)>> {
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::<crate::errors::Internal>();
assert_eq!(internal.0, "db pool unavailable");
}
}

View File

@@ -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<NotRegistered> for ProtoError {

View File

@@ -1,3 +1,5 @@
mod errors;
mod db;
mod auth;
fn main() {}