mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-09-29 01:42:21 +00:00
Replace local no-auth startup with a shared dev-token flow for CLI-managed servers. This provisions and validates dev tokens, preserves dev-token provenance through browser sessions, and teaches local CLI and web clients how to authenticate against local Unix and TCP servers.
99 lines
2.4 KiB
Rust
99 lines
2.4 KiB
Rust
use std::fs;
|
|
|
|
use fabro_util::Home;
|
|
use fabro_util::dev_token::{
|
|
DEV_TOKEN_PREFIX, generate_dev_token, load_or_create_dev_token, validate_dev_token_format,
|
|
};
|
|
|
|
#[test]
|
|
fn generate_has_correct_prefix_and_length() {
|
|
let token = generate_dev_token();
|
|
|
|
assert!(token.starts_with(DEV_TOKEN_PREFIX));
|
|
assert_eq!(token.len(), 74);
|
|
assert!(validate_dev_token_format(&token));
|
|
}
|
|
|
|
#[test]
|
|
fn generate_is_unique() {
|
|
assert_ne!(generate_dev_token(), generate_dev_token());
|
|
}
|
|
|
|
#[test]
|
|
fn validate_format_accepts_valid() {
|
|
let token = format!("{DEV_TOKEN_PREFIX}{}", "ab".repeat(32));
|
|
|
|
assert!(validate_dev_token_format(&token));
|
|
}
|
|
|
|
#[test]
|
|
fn validate_format_rejects_short() {
|
|
let token = format!("{DEV_TOKEN_PREFIX}{}", "ab".repeat(31));
|
|
|
|
assert!(!validate_dev_token_format(&token));
|
|
}
|
|
|
|
#[test]
|
|
fn validate_format_rejects_non_hex() {
|
|
let token = format!("{DEV_TOKEN_PREFIX}{}zz", "ab".repeat(31));
|
|
|
|
assert!(!validate_dev_token_format(&token));
|
|
}
|
|
|
|
#[test]
|
|
fn validate_format_rejects_wrong_prefix() {
|
|
let token = format!("fabro_nope_{}", "ab".repeat(32));
|
|
|
|
assert!(!validate_dev_token_format(&token));
|
|
}
|
|
|
|
#[test]
|
|
fn load_or_create_creates_file() {
|
|
let dir = tempfile::tempdir().unwrap();
|
|
let path = dir.path().join("dev-token");
|
|
|
|
let token = load_or_create_dev_token(&path).unwrap();
|
|
|
|
assert!(validate_dev_token_format(&token));
|
|
assert_eq!(fs::read_to_string(&path).unwrap(), token);
|
|
#[cfg(unix)]
|
|
{
|
|
use std::os::unix::fs::PermissionsExt;
|
|
|
|
let mode = fs::metadata(&path).unwrap().permissions().mode() & 0o777;
|
|
assert_eq!(mode, 0o600);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn load_or_create_reads_existing() {
|
|
let dir = tempfile::tempdir().unwrap();
|
|
let path = dir.path().join("dev-token");
|
|
let token = format!("{DEV_TOKEN_PREFIX}{}", "cd".repeat(32));
|
|
fs::write(&path, &token).unwrap();
|
|
|
|
let loaded = load_or_create_dev_token(&path).unwrap();
|
|
|
|
assert_eq!(loaded, token);
|
|
}
|
|
|
|
#[test]
|
|
fn load_or_create_rejects_malformed_file() {
|
|
let dir = tempfile::tempdir().unwrap();
|
|
let path = dir.path().join("dev-token");
|
|
fs::write(&path, "not-a-token").unwrap();
|
|
|
|
let error = load_or_create_dev_token(&path).unwrap_err();
|
|
|
|
assert!(error.to_string().contains("invalid"));
|
|
}
|
|
|
|
#[test]
|
|
fn home_dev_token_path_is_relative_to_root() {
|
|
let home = Home::new("/tmp/fabro-home");
|
|
|
|
assert_eq!(
|
|
home.dev_token_path(),
|
|
std::path::Path::new("/tmp/fabro-home/dev-token")
|
|
);
|
|
}
|