liminal-protocol 0.10.0

Shared participant-lifecycle protocol types for liminal
Documentation
//! A credential's `Debug` names its type and length, never its bytes: a
//! secret or attempt token reaches logs and error text through `{:?}`.

use alloc::format;
use alloc::string::ToString;

use super::{
    AttachAttemptToken, AttachSecret, DetachAttemptToken, EnrollmentToken, LeaveAttemptToken,
    RecordAdmissionAttemptToken,
};

/// Bytes 200, 201, … — each three digits, so no byte's rendering can hide in
/// a type name or a length.
fn distinct<const N: usize>() -> [u8; N] {
    core::array::from_fn(|index| u8::try_from(200 + index).unwrap_or(u8::MAX))
}

/// `rendered` shows none of `bytes`, in decimal or in hex.
fn shows_none_of(rendered: &str, bytes: &[u8]) {
    for byte in bytes {
        assert!(
            !rendered.contains(&byte.to_string()) && !rendered.contains(&format!("{byte:02x}")),
            "{rendered} shows byte {byte}"
        );
    }
}

#[test]
fn an_attach_secret_debug_shows_no_byte() {
    let bytes = distinct::<32>();
    let rendered = format!("{:?}", AttachSecret::new(bytes));
    shows_none_of(&rendered, &bytes);
    assert_eq!(rendered, "AttachSecret(32 bytes)");
}

#[test]
fn an_attach_attempt_token_debug_shows_no_byte() {
    let bytes = distinct::<16>();
    let rendered = format!("{:?}", AttachAttemptToken::new(bytes));
    shows_none_of(&rendered, &bytes);
    assert_eq!(rendered, "AttachAttemptToken(16 bytes)");
}

#[test]
fn an_enrollment_token_debug_shows_no_byte() {
    let bytes = distinct::<16>();
    let rendered = format!("{:?}", EnrollmentToken::new(bytes));
    shows_none_of(&rendered, &bytes);
    assert_eq!(rendered, "EnrollmentToken(16 bytes)");
}

#[test]
fn a_detach_attempt_token_debug_shows_no_byte() {
    let bytes = distinct::<16>();
    let rendered = format!("{:?}", DetachAttemptToken::new(bytes));
    shows_none_of(&rendered, &bytes);
    assert_eq!(rendered, "DetachAttemptToken(16 bytes)");
}

#[test]
fn a_leave_attempt_token_debug_shows_no_byte() {
    let bytes = distinct::<16>();
    let rendered = format!("{:?}", LeaveAttemptToken::new(bytes));
    shows_none_of(&rendered, &bytes);
    assert_eq!(rendered, "LeaveAttemptToken(16 bytes)");
}

#[test]
fn a_record_admission_attempt_token_debug_shows_no_byte() {
    let bytes = distinct::<16>();
    let rendered = format!("{:?}", RecordAdmissionAttemptToken::new(bytes));
    shows_none_of(&rendered, &bytes);
    assert_eq!(rendered, "RecordAdmissionAttemptToken(16 bytes)");
}

/// A request carrying a credential shows none of its bytes either: a
/// containing type's derived `Debug` delegates to the credential's.
#[test]
fn a_debug_of_a_containing_value_shows_no_credential_byte() {
    let secret = distinct::<32>();
    let rendered = format!("{:?}", Some((AttachSecret::new(secret), 7_u8)));
    shows_none_of(&rendered, &secret);
}