Full-depth rename per the approved plan; the 'claw' product vocabulary (claws, /claws routes, clawId, Claw Chat) stays — it is now the brand. - Display brand: Clawmates (manifest, titles, hero, login/rail logo 'clawmates'); default host app.clawmates.work; registry ghcr.io/clawmates - Crates tc-* -> cm-* (16 crates + all imports); binaries clawmates-server/broker/bundler; images clawmates/*; env prefix CLAWMATES_* (+ CM_TEST_DATABASE_URL / CM_LIVE_LLM); config clawmates.toml; helm chart deploy/helm/clawmates with clawmates-* resources; db names clawmates*; sockets /run/clawmates; cookie cm_session; kind cluster clawmates-test; seccomp node profile clawmates-agent-profile.json - All 9 Playwright brand assertions updated in lockstep; historical spec document left untouched as the only remaining 'TeamClaw' - Local env migrated: dev pg clawmates-dev-pg/clawmates_dev, shared test server clawmates-test-pg, kind cluster recreated with image + profile, compose images rebuilt under clawmates/* Verified end to end: 161 Rust + 68 frontend tests, 29 Playwright journeys, 4 live kind tests, helm/install/LOC/placeholder gates, and the clean-room install rehearsal serving the clawmates login page from a signed bundle of the rebuilt images. Co-Authored-By: Claude Fable 5 <[email protected]>
36 lines
1.1 KiB
Rust
36 lines
1.1 KiB
Rust
use base64::engine::general_purpose::URL_SAFE_NO_PAD;
|
|
use base64::Engine;
|
|
use rand_core::{OsRng, RngCore};
|
|
use sha2::{Digest, Sha256};
|
|
|
|
/// An opaque bearer token handed to the client exactly once at login.
|
|
/// Only its hash is persisted.
|
|
pub struct SessionToken(String);
|
|
|
|
impl std::fmt::Debug for SessionToken {
|
|
/// Redacted so tokens cannot leak through logs or panic messages.
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
f.write_str("SessionToken(<redacted>)")
|
|
}
|
|
}
|
|
|
|
impl SessionToken {
|
|
pub(crate) fn generate() -> SessionToken {
|
|
let mut bytes = [0u8; 32];
|
|
OsRng.fill_bytes(&mut bytes);
|
|
SessionToken(URL_SAFE_NO_PAD.encode(bytes))
|
|
}
|
|
|
|
/// The secret value to return to the client. Deliberately not `Display`
|
|
/// so tokens cannot leak into logs by accident.
|
|
pub fn secret(&self) -> &str {
|
|
&self.0
|
|
}
|
|
}
|
|
|
|
/// Hash used as the storage key for a token.
|
|
pub(crate) fn hash_token(secret: &str) -> String {
|
|
let digest = Sha256::digest(secret.as_bytes());
|
|
URL_SAFE_NO_PAD.encode(digest)
|
|
}
|