use async_trait::async_trait; use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use tranquil_types::{Did, Handle}; use uuid::Uuid; use crate::{ChannelVerificationStatus, CommsChannel, DbError, SsoProviderType}; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum WebauthnChallengeType { Registration, Authentication, } impl WebauthnChallengeType { pub fn as_str(self) -> &'static str { match self { Self::Registration => "registration", Self::Authentication => "authentication", } } } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, sqlx::Type)] #[sqlx(type_name = "account_type", rename_all = "snake_case")] pub enum AccountType { Personal, Delegated, } impl AccountType { pub fn is_delegated(&self) -> bool { matches!(self, Self::Delegated) } } #[derive(Debug, Clone)] pub struct UserRow { pub id: Uuid, pub did: Did, pub handle: Handle, pub email: Option, pub created_at: DateTime, pub deactivated_at: Option>, pub takedown_ref: Option, pub is_admin: bool, } #[derive(Debug, Clone)] pub struct UserWithKey { pub id: Uuid, pub did: Did, pub handle: Handle, pub email: Option, pub deactivated_at: Option>, pub takedown_ref: Option, pub is_admin: bool, pub key_bytes: Vec, pub encryption_version: Option, } #[derive(Debug, Clone)] pub struct UserStatus { pub deactivated_at: Option>, pub takedown_ref: Option, pub is_admin: bool, } #[derive(Debug, Clone)] pub struct UserEmailInfo { pub id: Uuid, pub handle: Handle, pub email: Option, pub email_verified: bool, } #[derive(Debug, Clone)] pub struct UserLoginCheck { pub did: Did, pub password_hash: Option, } #[derive(Debug, Clone)] pub struct UserLoginInfo { pub id: Uuid, pub did: Did, pub email: Option, pub password_hash: Option, pub password_required: bool, pub two_factor_enabled: bool, pub preferred_comms_channel: CommsChannel, pub deactivated_at: Option>, pub takedown_ref: Option, pub channel_verification: ChannelVerificationStatus, pub account_type: AccountType, } #[derive(Debug, Clone)] pub struct User2faStatus { pub id: Uuid, pub two_factor_enabled: bool, pub preferred_comms_channel: CommsChannel, pub channel_verification: ChannelVerificationStatus, } #[async_trait] pub trait UserRepository: Send + Sync { async fn get_by_did(&self, did: &Did) -> Result, DbError>; async fn get_by_handle(&self, handle: &Handle) -> Result, DbError>; async fn get_with_key_by_did(&self, did: &Did) -> Result, DbError>; async fn get_status_by_did(&self, did: &Did) -> Result, DbError>; async fn count_users(&self) -> Result; async fn get_session_access_expiry( &self, did: &Did, access_jti: &str, ) -> Result>, DbError>; async fn get_oauth_token_with_user( &self, token_id: &str, ) -> Result, DbError>; async fn get_user_info_by_did(&self, did: &Did) -> Result, DbError>; async fn get_any_admin_user_id(&self) -> Result, DbError>; async fn set_invites_disabled(&self, did: &Did, disabled: bool) -> Result; async fn search_accounts( &self, cursor_did: Option<&Did>, email_filter: Option<&str>, handle_filter: Option<&str>, limit: i64, ) -> Result, DbError>; async fn get_auth_info_by_did(&self, did: &Did) -> Result, DbError>; async fn get_by_email(&self, email: &str) -> Result, DbError>; async fn get_login_check_by_handle_or_email( &self, identifier: &str, ) -> Result, DbError>; async fn get_login_info_by_handle_or_email( &self, identifier: &str, ) -> Result, DbError>; async fn get_2fa_status_by_did(&self, did: &Did) -> Result, DbError>; async fn get_comms_prefs(&self, user_id: Uuid) -> Result, DbError>; async fn get_id_by_did(&self, did: &Did) -> Result, DbError>; async fn get_user_key_by_id(&self, user_id: Uuid) -> Result, DbError>; async fn get_id_and_handle_by_did(&self, did: &Did) -> Result, DbError>; async fn get_did_web_info_by_handle( &self, handle: &Handle, ) -> Result, DbError>; async fn get_did_web_overrides( &self, user_id: Uuid, ) -> Result, DbError>; async fn get_handle_by_did(&self, did: &Did) -> Result, DbError>; async fn is_account_active_by_did(&self, did: &Did) -> Result, DbError>; async fn get_user_for_deletion(&self, did: &Did) -> Result, DbError>; async fn check_handle_exists( &self, handle: &Handle, exclude_user_id: Uuid, ) -> Result; async fn update_handle(&self, user_id: Uuid, handle: &Handle) -> Result<(), DbError>; async fn get_user_with_key_by_did(&self, did: &Did) -> Result, DbError>; async fn is_account_migrated(&self, did: &Did) -> Result; async fn has_verified_comms_channel(&self, did: &Did) -> Result; async fn get_id_by_handle(&self, handle: &Handle) -> Result, DbError>; async fn get_email_info_by_did(&self, did: &Did) -> Result, DbError>; async fn check_email_exists(&self, email: &str, exclude_user_id: Uuid) -> Result; async fn update_email(&self, user_id: Uuid, email: &str) -> Result<(), DbError>; async fn set_email_verified(&self, user_id: Uuid, verified: bool) -> Result<(), DbError>; async fn check_email_verified_by_identifier( &self, identifier: &str, ) -> Result, DbError>; async fn check_channel_verified_by_did( &self, did: &Did, channel: CommsChannel, ) -> Result, DbError>; async fn admin_update_email(&self, did: &Did, email: &str) -> Result; async fn admin_update_handle(&self, did: &Did, handle: &Handle) -> Result; async fn admin_update_password(&self, did: &Did, password_hash: &str) -> Result; async fn set_admin_status(&self, did: &Did, is_admin: bool) -> Result<(), DbError>; async fn get_notification_prefs(&self, did: &Did) -> Result, DbError>; async fn get_id_handle_email_by_did( &self, did: &Did, ) -> Result, DbError>; async fn update_preferred_comms_channel( &self, did: &Did, channel: CommsChannel, ) -> Result<(), DbError>; async fn clear_discord(&self, user_id: Uuid) -> Result<(), DbError>; async fn clear_telegram(&self, user_id: Uuid) -> Result<(), DbError>; async fn clear_signal(&self, user_id: Uuid) -> Result<(), DbError>; async fn set_unverified_signal( &self, user_id: Uuid, signal_username: &str, ) -> Result<(), DbError>; async fn set_unverified_telegram( &self, user_id: Uuid, telegram_username: &str, ) -> Result<(), DbError>; async fn store_telegram_chat_id( &self, telegram_username: &str, chat_id: i64, handle: Option<&str>, ) -> Result, DbError>; async fn get_telegram_chat_id(&self, user_id: Uuid) -> Result, DbError>; async fn set_unverified_discord( &self, user_id: Uuid, discord_username: &str, ) -> Result<(), DbError>; async fn store_discord_user_id( &self, discord_username: &str, discord_id: &str, handle: Option<&str>, ) -> Result, DbError>; async fn get_verification_info( &self, did: &Did, ) -> Result, DbError>; async fn verify_email_channel(&self, user_id: Uuid, email: &str) -> Result; async fn verify_discord_channel(&self, user_id: Uuid, discord_id: &str) -> Result<(), DbError>; async fn verify_telegram_channel( &self, user_id: Uuid, telegram_username: &str, ) -> Result<(), DbError>; async fn verify_signal_channel( &self, user_id: Uuid, signal_username: &str, ) -> Result<(), DbError>; async fn set_email_verified_flag(&self, user_id: Uuid) -> Result<(), DbError>; async fn set_discord_verified_flag(&self, user_id: Uuid) -> Result<(), DbError>; async fn set_telegram_verified_flag(&self, user_id: Uuid) -> Result<(), DbError>; async fn set_signal_verified_flag(&self, user_id: Uuid) -> Result<(), DbError>; async fn has_totp_enabled(&self, did: &Did) -> Result; async fn has_passkeys(&self, did: &Did) -> Result; async fn get_password_hash_by_did(&self, did: &Did) -> Result, DbError>; async fn get_passkeys_for_user(&self, did: &Did) -> Result, DbError>; async fn get_passkey_by_credential_id( &self, credential_id: &[u8], ) -> Result, DbError>; async fn save_passkey( &self, did: &Did, credential_id: &[u8], public_key: &[u8], friendly_name: Option<&str>, ) -> Result; async fn update_passkey_counter( &self, credential_id: &[u8], new_counter: i32, ) -> Result; async fn delete_passkey(&self, id: Uuid, did: &Did) -> Result; async fn update_passkey_name(&self, id: Uuid, did: &Did, name: &str) -> Result; async fn save_webauthn_challenge( &self, did: &Did, challenge_type: WebauthnChallengeType, state_json: &str, ) -> Result; async fn load_webauthn_challenge( &self, did: &Did, challenge_type: WebauthnChallengeType, ) -> Result, DbError>; async fn delete_webauthn_challenge( &self, did: &Did, challenge_type: WebauthnChallengeType, ) -> Result<(), DbError>; async fn get_totp_record(&self, did: &Did) -> Result, DbError>; async fn get_totp_record_state(&self, did: &Did) -> Result, DbError>; async fn upsert_totp_secret( &self, did: &Did, secret_encrypted: &[u8], encryption_version: i32, ) -> Result<(), DbError>; async fn set_totp_verified(&self, did: &Did) -> Result<(), DbError>; async fn update_totp_last_used(&self, did: &Did) -> Result<(), DbError>; async fn delete_totp(&self, did: &Did) -> Result<(), DbError>; async fn get_unused_backup_codes(&self, did: &Did) -> Result, DbError>; async fn mark_backup_code_used(&self, code_id: Uuid) -> Result; async fn count_unused_backup_codes(&self, did: &Did) -> Result; async fn delete_backup_codes(&self, did: &Did) -> Result; async fn insert_backup_codes(&self, did: &Did, code_hashes: &[String]) -> Result<(), DbError>; async fn enable_totp_with_backup_codes( &self, did: &Did, code_hashes: &[String], ) -> Result<(), DbError>; async fn delete_totp_and_backup_codes(&self, did: &Did) -> Result<(), DbError>; async fn replace_backup_codes(&self, did: &Did, code_hashes: &[String]) -> Result<(), DbError>; async fn get_session_info_by_did(&self, did: &Did) -> Result, DbError>; async fn get_legacy_login_pref( &self, did: &Did, ) -> Result, DbError>; async fn update_legacy_login(&self, did: &Did, allow: bool) -> Result; async fn update_locale(&self, did: &Did, locale: &str) -> Result; async fn get_login_full_by_identifier( &self, identifier: &str, ) -> Result, DbError>; async fn get_confirm_signup_by_did( &self, did: &Did, ) -> Result, DbError>; async fn get_resend_verification_by_did( &self, did: &Did, ) -> Result, DbError>; async fn set_channel_verified(&self, did: &Did, channel: CommsChannel) -> Result<(), DbError>; async fn get_id_by_email_or_handle( &self, email: &str, handle: &str, ) -> Result, DbError>; async fn count_accounts_by_email(&self, email: &str) -> Result; async fn get_handles_by_email(&self, email: &str) -> Result, DbError>; async fn set_password_reset_code( &self, user_id: Uuid, code: &str, expires_at: DateTime, ) -> Result<(), DbError>; async fn get_user_by_reset_code( &self, code: &str, ) -> Result, DbError>; async fn clear_password_reset_code(&self, user_id: Uuid) -> Result<(), DbError>; async fn get_id_and_password_hash_by_did( &self, did: &Did, ) -> Result, DbError>; async fn update_password_hash(&self, user_id: Uuid, password_hash: &str) -> Result<(), DbError>; async fn reset_password_with_sessions( &self, user_id: Uuid, password_hash: &str, ) -> Result; async fn activate_account(&self, did: &Did) -> Result; async fn deactivate_account( &self, did: &Did, delete_after: Option>, ) -> Result; async fn has_password_by_did(&self, did: &Did) -> Result, DbError>; async fn get_password_info_by_did( &self, did: &Did, ) -> Result, DbError>; async fn remove_user_password(&self, user_id: Uuid) -> Result<(), DbError>; async fn set_new_user_password( &self, user_id: Uuid, password_hash: &str, ) -> Result<(), DbError>; async fn get_user_key_by_did(&self, did: &Did) -> Result, DbError>; async fn delete_account_complete(&self, user_id: Uuid, did: &Did) -> Result<(), DbError>; async fn set_user_takedown( &self, did: &Did, takedown_ref: Option<&str>, ) -> Result; async fn admin_delete_account_complete(&self, user_id: Uuid, did: &Did) -> Result<(), DbError>; async fn get_user_for_did_doc(&self, did: &Did) -> Result, DbError>; async fn get_user_for_did_doc_build( &self, did: &Did, ) -> Result, DbError>; async fn upsert_did_web_overrides( &self, user_id: Uuid, verification_methods: Option, also_known_as: Option>, ) -> Result<(), DbError>; async fn update_migrated_to_pds(&self, did: &Did, endpoint: &str) -> Result<(), DbError>; async fn get_user_for_passkey_setup( &self, did: &Did, ) -> Result, DbError>; async fn get_user_for_passkey_recovery( &self, identifier: &str, normalized_handle: &str, ) -> Result, DbError>; async fn set_recovery_token( &self, did: &Did, token_hash: &str, expires_at: DateTime, ) -> Result<(), DbError>; async fn get_user_for_recovery(&self, did: &Did) -> Result, DbError>; async fn get_accounts_scheduled_for_deletion( &self, limit: i64, ) -> Result, DbError>; async fn delete_account_with_firehose(&self, user_id: Uuid, did: &Did) -> Result; async fn create_password_account( &self, input: &CreatePasswordAccountInput, ) -> Result; async fn create_delegated_account( &self, input: &CreateDelegatedAccountInput, ) -> Result; async fn create_passkey_account( &self, input: &CreatePasskeyAccountInput, ) -> Result; async fn create_sso_account( &self, input: &CreateSsoAccountInput, ) -> Result; async fn reactivate_migration_account( &self, input: &MigrationReactivationInput, ) -> Result; async fn check_handle_available_for_new_account( &self, handle: &Handle, ) -> Result; async fn reserve_handle(&self, handle: &Handle, reserved_by: &str) -> Result; async fn release_handle_reservation(&self, handle: &Handle) -> Result<(), DbError>; async fn cleanup_expired_handle_reservations(&self) -> Result; async fn check_and_consume_invite_code(&self, code: &str) -> Result; async fn complete_passkey_setup( &self, input: &CompletePasskeySetupInput, ) -> Result<(), DbError>; async fn recover_passkey_account( &self, input: &RecoverPasskeyAccountInput, ) -> Result; async fn get_password_reset_info( &self, email: &str, ) -> Result, DbError>; async fn enable_totp_verified(&self, did: &Did, encrypted_secret: &[u8]) -> Result<(), DbError>; async fn set_two_factor_enabled(&self, did: &Did, enabled: bool) -> Result<(), DbError>; async fn expire_password_reset_code(&self, email: &str) -> Result<(), DbError>; } #[derive(Debug, Clone)] pub struct UserKeyWithId { pub id: Uuid, pub key_bytes: Vec, pub encryption_version: Option, } #[derive(Debug, Clone)] pub struct UserKeyInfo { pub key_bytes: Vec, pub encryption_version: Option, } #[derive(Debug, Clone)] pub struct UserIdAndHandle { pub id: Uuid, pub handle: Handle, } #[derive(Debug, Clone)] pub struct UserDidWebInfo { pub id: Uuid, pub did: Did, pub migrated_to_pds: Option, } #[derive(Debug, Clone)] pub struct DidWebOverrides { pub verification_methods: serde_json::Value, pub also_known_as: Vec, } #[derive(Debug, Clone)] pub struct UserCommsPrefs { pub email: Option, pub handle: Handle, pub preferred_channel: CommsChannel, pub preferred_locale: Option, pub telegram_chat_id: Option, pub discord_id: Option, pub signal_username: Option, } #[derive(Debug, Clone)] pub struct UserForVerification { pub id: Uuid, pub did: Did, pub email: Option, pub email_verified: bool, pub handle: Handle, } #[derive(Debug, Clone)] pub struct OAuthTokenWithUser { pub did: Did, pub expires_at: DateTime, pub deactivated_at: Option>, pub takedown_ref: Option, pub is_admin: bool, pub key_bytes: Option>, pub encryption_version: Option, } #[derive(Debug, Clone)] pub struct UserInfoForAuth { pub deactivated_at: Option>, pub takedown_ref: Option, pub is_admin: bool, pub key_bytes: Option>, pub encryption_version: Option, } #[derive(Debug, Clone)] pub struct AccountSearchResult { pub did: Did, pub handle: Handle, pub email: Option, pub created_at: DateTime, pub email_verified: bool, pub deactivated_at: Option>, pub invites_disabled: Option, } #[derive(Debug, Clone)] pub struct UserAuthInfo { pub id: Uuid, pub did: Did, pub password_hash: Option, pub deactivated_at: Option>, pub takedown_ref: Option, pub channel_verification: ChannelVerificationStatus, } #[derive(Debug, Clone)] pub struct NotificationPrefs { pub email: String, pub preferred_channel: CommsChannel, pub discord_id: Option, pub discord_username: Option, pub discord_verified: bool, pub telegram_username: Option, pub telegram_verified: bool, pub telegram_chat_id: Option, pub signal_username: Option, pub signal_verified: bool, } #[derive(Debug, Clone)] pub struct UserIdHandleEmail { pub id: Uuid, pub handle: Handle, pub email: Option, } #[derive(Debug, Clone)] pub struct UserVerificationInfo { pub id: Uuid, pub handle: Handle, pub email: Option, pub channel_verification: ChannelVerificationStatus, } #[derive(Debug, Clone)] pub struct StoredPasskey { pub id: Uuid, pub did: Did, pub credential_id: Vec, pub public_key: Vec, pub sign_count: i32, pub created_at: DateTime, pub last_used: Option>, pub friendly_name: Option, pub aaguid: Option>, pub transports: Option>, } impl StoredPasskey { pub fn credential_id_base64(&self) -> String { use base64::{Engine, engine::general_purpose::URL_SAFE_NO_PAD}; URL_SAFE_NO_PAD.encode(&self.credential_id) } } #[derive(Debug, Clone)] pub struct TotpRecord { pub secret_encrypted: Vec, pub encryption_version: i32, pub verified: bool, } #[derive(Debug, Clone)] pub struct VerifiedTotpRecord { pub secret_encrypted: Vec, pub encryption_version: i32, } #[derive(Debug, Clone)] pub struct UnverifiedTotpRecord { pub secret_encrypted: Vec, pub encryption_version: i32, } #[derive(Debug, Clone)] pub enum TotpRecordState { Verified(VerifiedTotpRecord), Unverified(UnverifiedTotpRecord), } impl TotpRecordState { pub fn is_verified(&self) -> bool { matches!(self, Self::Verified(_)) } pub fn as_verified(&self) -> Option<&VerifiedTotpRecord> { match self { Self::Verified(r) => Some(r), Self::Unverified(_) => None, } } pub fn as_unverified(&self) -> Option<&UnverifiedTotpRecord> { match self { Self::Unverified(r) => Some(r), Self::Verified(_) => None, } } pub fn into_verified(self) -> Option { match self { Self::Verified(r) => Some(r), Self::Unverified(_) => None, } } pub fn into_unverified(self) -> Option { match self { Self::Unverified(r) => Some(r), Self::Verified(_) => None, } } } impl From for TotpRecordState { fn from(record: TotpRecord) -> Self { if record.verified { Self::Verified(VerifiedTotpRecord { secret_encrypted: record.secret_encrypted, encryption_version: record.encryption_version, }) } else { Self::Unverified(UnverifiedTotpRecord { secret_encrypted: record.secret_encrypted, encryption_version: record.encryption_version, }) } } } #[derive(Debug, Clone)] pub struct StoredBackupCode { pub id: Uuid, pub code_hash: String, } #[derive(Debug, Clone)] pub struct UserSessionInfo { pub handle: Handle, pub email: Option, pub is_admin: bool, pub deactivated_at: Option>, pub takedown_ref: Option, pub preferred_locale: Option, pub preferred_comms_channel: CommsChannel, pub channel_verification: ChannelVerificationStatus, pub migrated_to_pds: Option, pub migrated_at: Option>, pub totp_enabled: bool, pub email_2fa_enabled: bool, } #[derive(Debug, Clone)] pub struct UserLegacyLoginPref { pub allow_legacy_login: bool, pub has_mfa: bool, } #[derive(Debug, Clone)] pub struct UserLoginFull { pub id: Uuid, pub did: Did, pub handle: Handle, pub password_hash: Option, pub email: Option, pub deactivated_at: Option>, pub takedown_ref: Option, pub channel_verification: ChannelVerificationStatus, pub allow_legacy_login: bool, pub migrated_to_pds: Option, pub preferred_comms_channel: CommsChannel, pub key_bytes: Vec, pub encryption_version: Option, pub totp_enabled: bool, pub email_2fa_enabled: bool, } #[derive(Debug, Clone)] pub struct UserConfirmSignup { pub id: Uuid, pub did: Did, pub handle: Handle, pub email: Option, pub channel: CommsChannel, pub discord_username: Option, pub telegram_username: Option, pub signal_username: Option, pub key_bytes: Vec, pub encryption_version: Option, } #[derive(Debug, Clone)] pub struct UserResendVerification { pub id: Uuid, pub handle: Handle, pub email: Option, pub channel: CommsChannel, pub discord_username: Option, pub telegram_username: Option, pub signal_username: Option, pub channel_verification: ChannelVerificationStatus, } #[derive(Debug, Clone)] pub struct UserResetCodeInfo { pub id: Uuid, pub did: Did, pub preferred_comms_channel: CommsChannel, pub expires_at: Option>, } #[derive(Debug, Clone)] pub struct UserPasswordInfo { pub id: Uuid, pub password_hash: Option, } #[derive(Debug, Clone)] pub struct UserIdAndPasswordHash { pub id: Uuid, pub password_hash: String, } #[derive(Debug, Clone)] pub struct PasswordResetResult { pub did: Did, pub session_jtis: Vec, } #[derive(Debug, Clone)] pub struct UserForDeletion { pub id: Uuid, pub password_hash: Option, pub handle: Handle, } #[derive(Debug, Clone)] pub struct ScheduledDeletionAccount { pub id: Uuid, pub did: Did, pub handle: Handle, } #[derive(Debug, Clone)] pub struct UserForDidDoc { pub id: Uuid, pub handle: Handle, pub deactivated_at: Option>, } #[derive(Debug, Clone)] pub struct UserForDidDocBuild { pub id: Uuid, pub handle: Handle, pub migrated_to_pds: Option, } #[derive(Debug, Clone)] pub struct UserForPasskeySetup { pub id: Uuid, pub handle: Handle, pub recovery_token: Option, pub recovery_token_expires_at: Option>, pub password_required: bool, } #[derive(Debug, Clone)] pub struct UserForPasskeyRecovery { pub id: Uuid, pub did: Did, pub handle: Handle, pub password_required: bool, } #[derive(Debug, Clone)] pub struct UserForRecovery { pub id: Uuid, pub did: Did, pub preferred_comms_channel: CommsChannel, pub recovery_token: Option, pub recovery_token_expires_at: Option>, } #[derive(Debug, Clone)] pub struct CreatePasswordAccountInput { pub handle: Handle, pub email: Option, pub did: Did, pub password_hash: String, pub preferred_comms_channel: CommsChannel, pub discord_username: Option, pub telegram_username: Option, pub signal_username: Option, pub deactivated_at: Option>, pub encrypted_key_bytes: Vec, pub encryption_version: i32, pub reserved_key_id: Option, pub commit_cid: String, pub repo_rev: String, pub genesis_block_cids: Vec>, pub invite_code: Option, pub birthdate_pref: Option, } #[derive(Debug, Clone, Default)] pub struct CreatePasswordAccountResult { pub user_id: Uuid, pub is_admin: bool, } #[derive(Debug, Clone)] pub enum CreateAccountError { HandleTaken, EmailTaken, DidExists, InvalidToken, Database(String), } #[derive(Debug, Clone)] pub struct CreateDelegatedAccountInput { pub handle: Handle, pub email: Option, pub did: Did, pub controller_did: Did, pub controller_scopes: String, pub encrypted_key_bytes: Vec, pub encryption_version: i32, pub commit_cid: String, pub repo_rev: String, pub genesis_block_cids: Vec>, pub invite_code: Option, } #[derive(Debug, Clone)] pub struct CreatePasskeyAccountInput { pub handle: Handle, pub email: String, pub did: Did, pub preferred_comms_channel: CommsChannel, pub discord_username: Option, pub telegram_username: Option, pub signal_username: Option, pub setup_token_hash: String, pub setup_expires_at: DateTime, pub deactivated_at: Option>, pub encrypted_key_bytes: Vec, pub encryption_version: i32, pub reserved_key_id: Option, pub commit_cid: String, pub repo_rev: String, pub genesis_block_cids: Vec>, pub invite_code: Option, pub birthdate_pref: Option, } #[derive(Debug, Clone)] pub struct CreateSsoAccountInput { pub handle: Handle, pub email: Option, pub did: Did, pub preferred_comms_channel: CommsChannel, pub discord_username: Option, pub telegram_username: Option, pub signal_username: Option, pub encrypted_key_bytes: Vec, pub encryption_version: i32, pub commit_cid: String, pub repo_rev: String, pub genesis_block_cids: Vec>, pub invite_code: Option, pub birthdate_pref: Option, pub sso_provider: SsoProviderType, pub sso_provider_user_id: String, pub sso_provider_username: Option, pub sso_provider_email: Option, pub sso_provider_email_verified: bool, pub pending_registration_token: String, } #[derive(Debug, Clone)] pub struct CompletePasskeySetupInput { pub user_id: Uuid, pub did: Did, pub app_password_name: String, pub app_password_hash: String, } #[derive(Debug, Clone)] pub struct RecoverPasskeyAccountInput { pub did: Did, pub password_hash: String, } #[derive(Debug, Clone)] pub struct RecoverPasskeyAccountResult { pub passkeys_deleted: u64, } #[derive(Debug, Clone)] pub struct MigrationReactivationInput { pub did: Did, pub new_handle: Handle, pub new_email: Option, } #[derive(Debug, Clone)] pub struct ReactivatedAccountInfo { pub user_id: Uuid, pub old_handle: Handle, } #[derive(Debug, Clone)] pub enum MigrationReactivationError { NotFound, NotDeactivated, HandleTaken, Database(String), }