feat(tauth): rework TAuth

This commit is contained in:
Alois 2026-09-14 19:31:37 +02:00
commit 3685babebf
Signed by: alois
SSH key fingerprint: SHA256:GBzT2DXvAuGV9XIV5W3WrzVpjU54FThmxHXdbz95J24
31 changed files with 3418 additions and 502 deletions

View file

@ -10,8 +10,9 @@ pub use protocol::{
LocalRequest, LocalUserState, LogEntriesResponse, LogEntry, MetricSample,
OmikronStatusResponse, ReconcileAction, RequestEnvelope, ResponseEnvelope, ResponsePayload,
ResponseResult, SecretString, StartupPhase, StateSnapshot, StatusResponse, SupervisorKind,
TaskSummary, TuCredentialPreview, UpdateStatusResponse, UserDetailResponse, UserDiagnostics,
UserOperationKind, UserOperationSummary, UserReconcileResult, UserSummary,
TAuthAppSummary, TAuthConnectionInput, TaskSummary, TuCredentialPreview, UpdateStatusResponse,
UserDetailResponse, UserDiagnostics, UserOperationKind, UserOperationSummary,
UserReconcileResult, UserSummary,
};
pub use transport::{MAX_MESSAGE_SIZE, read_msg, write_msg};

View file

@ -45,6 +45,23 @@ pub enum LocalRequest {
GetStatus,
ListTasks,
ListUsers,
ListTAuthApps,
GetTAuthApp {
app_id: String,
},
CreateTAuthApp {
owner_user_id: i64,
domain: String,
name: String,
redirects: Vec<String>,
connection: TAuthConnectionInput,
},
ExportTAuthApp {
app_id: String,
},
DeleteTAuthApp {
app_id: String,
},
CreateInvitation {
authority: InvitationAuthority,
lifetime_seconds: u64,
@ -79,11 +96,11 @@ pub enum LocalRequest {
GetUserDiagnostics {
user_id: i64,
},
RevokeTrustedApp {
RevokeTAuthGrant {
user_id: i64,
app_id: String,
},
RevokeAllTrustedApps {
RevokeAllTAuthGrants {
user_id: i64,
},
ExportUserCredential {
@ -161,6 +178,8 @@ impl LocalRequest {
Self::GetStatus
| Self::ListTasks
| Self::ListUsers
| Self::ListTAuthApps
| Self::GetTAuthApp { .. }
| Self::ListInvitations { .. }
| Self::GetDaemonStatus
| Self::GetOmikronStatus
@ -174,6 +193,9 @@ impl LocalRequest {
Self::ReconnectOmikron | Self::ReloadConfig => IpcRole::Operate,
Self::CreateUser { .. }
| Self::CreateTAuthApp { .. }
| Self::ExportTAuthApp { .. }
| Self::DeleteTAuthApp { .. }
| Self::CreateInvitation { .. }
| Self::RevokeInvitation { .. }
| Self::InspectTuCredential { .. }
@ -181,8 +203,8 @@ impl LocalRequest {
| Self::ReconcileUser { .. }
| Self::ForceDetachUser { .. }
| Self::ForgetReleasedUser { .. }
| Self::RevokeTrustedApp { .. }
| Self::RevokeAllTrustedApps { .. }
| Self::RevokeTAuthGrant { .. }
| Self::RevokeAllTAuthGrants { .. }
| Self::ExportUserCredential { .. }
| Self::PurgeUserData { .. }
| Self::ReleaseUser { .. }
@ -265,6 +287,18 @@ pub enum ResponsePayload {
Status(StatusResponse),
Tasks(Vec<TaskSummary>),
Users(Vec<UserSummary>),
TAuthApps(Vec<TAuthAppSummary>),
TAuthApp(TAuthAppSummary),
TAuthAppCreated {
app: TAuthAppSummary,
credential: SecretString,
txt_record: String,
manifest_template: String,
},
TAuthAppCredentialExport {
app_id: String,
credential: SecretString,
},
InvitationCreated(InvitationCreated),
Invitations(Vec<InvitationSummary>),
InvitationUpdated(InvitationSummary),
@ -311,6 +345,29 @@ pub struct OmikronStatusResponse {
pub iota_id: Option<u64>,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
#[serde(tag = "mode", rename_all = "snake_case")]
pub enum TAuthConnectionInput {
Hosted {
omega_url: String,
},
ForcedOmikron {
omikron_url: String,
omikron_public_key: String,
},
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct TAuthAppSummary {
pub app_id: String,
pub owner_user_id: i64,
pub domain: String,
pub public_key: String,
pub connection_mode: String,
pub endpoint_url: String,
pub created_at: i64,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct ComponentStatusResponse {
pub id: ComponentId,
@ -324,7 +381,7 @@ pub struct UserDetailResponse {
pub username: String,
pub display_name: Option<String>,
pub created_at: i64,
pub trusted_apps: Vec<String>,
pub tauth_grants: Vec<String>,
pub state: LocalUserState,
pub data_present: bool,
pub credential_status: CredentialStatus,
@ -467,7 +524,7 @@ pub struct UserDiagnostics {
pub local_state: LocalUserState,
pub data_present: bool,
pub credential_status: CredentialStatus,
pub trusted_app_count: usize,
pub tauth_grant_count: usize,
pub pending_operation: Option<String>,
}

View file

@ -15,6 +15,11 @@ pub const COMMANDS: &[&str] = &[
"users forget ",
"users apps revoke ",
"users apps revoke-all ",
"apps list",
"apps show ",
"apps create hosted ",
"apps create forced-omikron ",
"apps delete ",
"omikron status",
"reconnect",
"identity rotate",
@ -97,16 +102,61 @@ pub fn parse(line: &str) -> Option<LocalRequest> {
user_id: id_str.parse::<i64>().ok()?,
}),
["user" | "users", "apps", "revoke", id_str, app_id] => {
Some(LocalRequest::RevokeTrustedApp {
Some(LocalRequest::RevokeTAuthGrant {
user_id: id_str.parse::<i64>().ok()?,
app_id: app_id.to_string(),
})
}
["user" | "users", "apps", "revoke-all", id_str] => {
Some(LocalRequest::RevokeAllTrustedApps {
Some(LocalRequest::RevokeAllTAuthGrants {
user_id: id_str.parse::<i64>().ok()?,
})
}
["apps", "list"] => Some(LocalRequest::ListTAuthApps),
["apps", "show", app_id] => Some(LocalRequest::GetTAuthApp {
app_id: app_id.to_string(),
}),
[
"apps",
"create",
"hosted",
owner,
domain,
name,
redirect,
omega_url,
] => Some(LocalRequest::CreateTAuthApp {
owner_user_id: owner.parse().ok()?,
domain: domain.to_string(),
name: name.to_string(),
redirects: vec![redirect.to_string()],
connection: crate::TAuthConnectionInput::Hosted {
omega_url: omega_url.to_string(),
},
}),
[
"apps",
"create",
"forced-omikron",
owner,
domain,
name,
redirect,
omikron_url,
omikron_public_key,
] => Some(LocalRequest::CreateTAuthApp {
owner_user_id: owner.parse().ok()?,
domain: domain.to_string(),
name: name.to_string(),
redirects: vec![redirect.to_string()],
connection: crate::TAuthConnectionInput::ForcedOmikron {
omikron_url: omikron_url.to_string(),
omikron_public_key: omikron_public_key.to_string(),
},
}),
["apps", "delete", app_id, "confirm"] => Some(LocalRequest::DeleteTAuthApp {
app_id: app_id.to_string(),
}),
["reconnect"] => Some(LocalRequest::ReconnectOmikron),
["regenerate", "keys"] | ["identity", "rotate"] => Some(LocalRequest::RotateIotaIdentity),
["reload"] | ["restart"] => Some(LocalRequest::RequestProcessExit {
@ -174,11 +224,11 @@ mod tests {
));
assert!(matches!(
parse("users apps revoke 42 desktop"),
Some(LocalRequest::RevokeTrustedApp { user_id: 42, .. })
Some(LocalRequest::RevokeTAuthGrant { user_id: 42, .. })
));
assert!(matches!(
parse("users apps revoke-all 42"),
Some(LocalRequest::RevokeAllTrustedApps { user_id: 42 })
Some(LocalRequest::RevokeAllTAuthGrants { user_id: 42 })
));
assert!(matches!(
parse("identity rotate"),