Per-app end-user table for the v1.1.8 users::* SDK. Distinct from admin_users (control-plane operators) — same Argon2id password hash shape but everything else (uniqueness scope, ownership, lifecycle) independent. - Uniqueness on (app_id, lower(email)) — case-insensitive within an app; same email may exist across two apps. - AppUserRepository trait + Postgres impl; every method takes app_id explicitly so cross-app reads are unmistakable at the call site (matches v1.1.3 cross-app discipline). - Public AppUserRow never includes the password hash; the credentials shape is its own struct returned only by the login lookup. - Cursor-based list keyed on (created_at, id). - Reserved a timing-flat dummy Argon2id PHC constant in auth.rs for the upcoming login path so the bad-email and good-email branches share wall-clock cost. - Added AppUserId + InvitationId id types in shared::ids. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
59 lines
1.3 KiB
Rust
59 lines
1.3 KiB
Rust
use serde::{Deserialize, Serialize};
|
|
use uuid::Uuid;
|
|
|
|
macro_rules! id_type {
|
|
($name:ident) => {
|
|
#[derive(
|
|
Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize,
|
|
)]
|
|
#[serde(transparent)]
|
|
pub struct $name(pub Uuid);
|
|
|
|
impl $name {
|
|
#[must_use]
|
|
pub fn new() -> Self {
|
|
Self(Uuid::new_v4())
|
|
}
|
|
|
|
#[must_use]
|
|
pub fn into_inner(self) -> Uuid {
|
|
self.0
|
|
}
|
|
}
|
|
|
|
impl Default for $name {
|
|
fn default() -> Self {
|
|
Self::new()
|
|
}
|
|
}
|
|
|
|
impl From<Uuid> for $name {
|
|
fn from(u: Uuid) -> Self {
|
|
Self(u)
|
|
}
|
|
}
|
|
|
|
impl From<$name> for Uuid {
|
|
fn from(id: $name) -> Self {
|
|
id.0
|
|
}
|
|
}
|
|
|
|
impl std::fmt::Display for $name {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
self.0.fmt(f)
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
id_type!(ScriptId);
|
|
id_type!(ExecutionId);
|
|
id_type!(RequestId);
|
|
id_type!(AdminUserId);
|
|
id_type!(AppId);
|
|
id_type!(ApiKeyId);
|
|
id_type!(TriggerId);
|
|
id_type!(AppUserId);
|
|
id_type!(InvitationId);
|