Multi-user: email sign-in, invite/open registration, admin calls
- kv-proto: email on setup, AccountInfo.email/is_admin, ServerInfo.registration, admin DTOs. - kv-sync: prelogin by email or account id (setup QR / Emergency Kit), register with email, set_email, /v1/admin/* client calls. - kv-ffi: register_account(code, email), login(.., email), account_details, set_account_email, admin_create_invite. kv-wasm: the same plus the full admin API for the web vault. - Live test: two users on one server stay isolated; a new device signs in by email. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
@@ -62,7 +62,12 @@ export interface ItemDto {
|
||||
|
||||
export interface TotpCode { code: string; secondsRemaining: number; period: number; }
|
||||
|
||||
export interface ServerInfoDto { version: string; api: number; setupOpen: boolean; minClient: string; }
|
||||
export interface ServerInfoDto { version: string; api: number; setupOpen: boolean; minClient: string; registration: "invite" | "open" | null; }
|
||||
export interface AccountDetailsDto { email: string | null; isAdmin: boolean; }
|
||||
export interface AdminUserDto { accountId: string; email: string | null; isAdmin: boolean; disabled: boolean; createdAt: string; lastSeen: number | null; devices: number; items: number; storageBytes: number; }
|
||||
export interface InviteDto { inviteId: string; email: string | null; createdAt: number; expiresAt: number; used: boolean; revoked: boolean; }
|
||||
export interface InviteCreatedDto { inviteId: string; code: string; expiresAt: number; }
|
||||
export interface AdminSettingsDto { registration: "invite" | "open"; allowedDomains: string[]; }
|
||||
|
||||
export interface SyncReport {
|
||||
pulled: number;
|
||||
@@ -648,8 +653,12 @@ impl VaultCore {
|
||||
|
||||
/// First device only (the web vault is rarely that): registers the account with a fresh server.
|
||||
#[wasm_bindgen(js_name = registerAccount, unchecked_return_type = "Promise<void>")]
|
||||
pub fn register_account(&self, #[wasm_bindgen(js_name = "setupToken")] setup_token: String) -> Promise {
|
||||
self.write(move |s| async move { s.core.register_account(&setup_token).await })
|
||||
pub fn register_account(
|
||||
&self,
|
||||
#[wasm_bindgen(js_name = "setupToken")] setup_token: String,
|
||||
email: Option<String>,
|
||||
) -> Promise {
|
||||
self.write(move |s| async move { s.core.register_account(&setup_token, email).await })
|
||||
}
|
||||
|
||||
/// Logs in (and unlocks). Resolves `"pendingApproval"` until an enrolled device approves this
|
||||
@@ -660,9 +669,69 @@ impl VaultCore {
|
||||
#[wasm_bindgen(js_name = "masterPassword")] master_password: String,
|
||||
#[wasm_bindgen(js_name = "secretKey")] secret_key: String,
|
||||
totp: Option<String>,
|
||||
email: Option<String>,
|
||||
) -> Promise {
|
||||
let (pw, sk) = (zeroize::Zeroizing::new(master_password), zeroize::Zeroizing::new(secret_key));
|
||||
self.write(move |s| async move { s.core.login(&pw, &sk, totp).await })
|
||||
self.write(move |s| async move { s.core.login(&pw, &sk, totp, email).await })
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = accountDetails, unchecked_return_type = "Promise<AccountDetailsDto>")]
|
||||
pub fn account_details(&self) -> Promise {
|
||||
self.run(|s| async move { s.core.account_details().await })
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = setAccountEmail, unchecked_return_type = "Promise<void>")]
|
||||
pub fn set_account_email(&self, email: String) -> Promise {
|
||||
self.run(move |s| async move { s.core.set_account_email(&email).await })
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = adminUsers, unchecked_return_type = "Promise<AdminUserDto[]>")]
|
||||
pub fn admin_users(&self) -> Promise {
|
||||
self.run(|s| async move { s.core.admin_users().await })
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = adminUpdateUser, unchecked_return_type = "Promise<void>")]
|
||||
pub fn admin_update_user(
|
||||
&self,
|
||||
#[wasm_bindgen(js_name = "accountId")] account_id: String,
|
||||
disabled: Option<bool>,
|
||||
#[wasm_bindgen(js_name = "isAdmin")] is_admin: Option<bool>,
|
||||
) -> Promise {
|
||||
self.run(move |s| async move { s.core.admin_update_user(&account_id, disabled, is_admin).await })
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = adminDeleteUser, unchecked_return_type = "Promise<void>")]
|
||||
pub fn admin_delete_user(&self, #[wasm_bindgen(js_name = "accountId")] account_id: String) -> Promise {
|
||||
self.run(move |s| async move { s.core.admin_delete_user(&account_id).await })
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = adminInvites, unchecked_return_type = "Promise<InviteDto[]>")]
|
||||
pub fn admin_invites(&self) -> Promise {
|
||||
self.run(|s| async move { s.core.admin_invites().await })
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = adminCreateInvite, unchecked_return_type = "Promise<InviteCreatedDto>")]
|
||||
pub fn admin_create_invite(&self, email: Option<String>, days: Option<u32>) -> Promise {
|
||||
self.run(move |s| async move { s.core.admin_create_invite(email, days).await })
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = adminRevokeInvite, unchecked_return_type = "Promise<void>")]
|
||||
pub fn admin_revoke_invite(&self, #[wasm_bindgen(js_name = "inviteId")] invite_id: String) -> Promise {
|
||||
self.run(move |s| async move { s.core.admin_revoke_invite(&invite_id).await })
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = adminSettings, unchecked_return_type = "Promise<AdminSettingsDto>")]
|
||||
pub fn admin_settings(&self) -> Promise {
|
||||
self.run(|s| async move { s.core.admin_settings().await })
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = adminPutSettings, unchecked_return_type = "Promise<AdminSettingsDto>")]
|
||||
pub fn admin_put_settings(
|
||||
&self,
|
||||
registration: String,
|
||||
#[wasm_bindgen(js_name = "allowedDomains")] allowed_domains: Vec<String>,
|
||||
) -> Promise {
|
||||
self.run(move |s| async move { s.core.admin_put_settings(®istration, allowed_domains).await })
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = syncNow, unchecked_return_type = "Promise<SyncReport>")]
|
||||
|
||||
Reference in New Issue
Block a user