5.4 KiB
5.4 KiB
NuQloud Managed Recovery + Emergency Access
This document describes the managed recovery and emergency-access flow added to qortal_integration.
Goal
- Keep decentralized auth primary.
- Provide optional recovery support for users who opt in.
- Ensure admins cannot read recovery data at rest.
- Require both admin and user participation for recovery reveal.
User-facing behavior
In Personal Settings (/settings/user/connected-accounts, section NuQloud for Nextcloud):
- User can opt in to Managed Recovery.
- User can optionally opt in to Emergency Temporary Login Reset.
- User chooses:
- linked wallet/account
- current backup password (verified against wallet backup API)
- recovery passphrase (local secret known only to user)
- User can later reveal backup password only with:
- recovery passphrase, and
- admin-issued one-time recovery code.
Admin flow is available in Administration settings -> NuQloud for Nextcloud -> Recovery Operations:
- Check target user recovery status.
- Issue one-time recovery code (configurable TTL).
- Start emergency temporary-login window (configurable duration).
Security model
- The backup password is encrypted server-side into an escrow blob:
- cipher:
aes-256-gcm - key derivation:
pbkdf2-sha256with per-record salt and iterations
- cipher:
- Admin recovery codes are:
- short-lived,
- one-time use,
- stored hashed with HMAC in app config registry.
- Recovery reveal has lockout controls:
- failed attempt counter,
- temporary lock window after repeated failures.
- Emergency reset is explicit opt-in and time-bounded.
What this is and is not
- This is an app-level encrypted escrow model, not raw plaintext storage.
- This is not zero-knowledge from the server runtime perspective during active recovery execution.
- This does not currently hard-disable centralized login globally; it adds emergency controls around it.
- Passwords app mirroring is not yet implemented in this pass.
Endpoints
All routes are under /apps/qortal_integration.
User endpoints
-
GET /api/user/recovery/status- auth: authenticated user
- returns current recovery/enrollment/emergency state for the current user.
-
POST /api/user/recovery/enroll- auth: authenticated user
- params:
walletIdcurrentBackupPasswordrecoveryPassphraserecoveryPassphraseConfirmmanagedEnabled(1)emergencyLoginEnabled(1or empty)
- behavior:
- verifies wallet backup password first,
- encrypts escrow blob,
- persists managed recovery settings.
-
POST /api/user/recovery/disable- auth: authenticated user
- clears managed recovery configuration for current user.
-
POST /api/user/recovery/reveal- auth: authenticated user
- params:
recoveryPassphraseadminCode
- behavior:
- validates and consumes one-time admin code,
- decrypts escrow if passphrase is valid,
- returns backup password once.
-
POST /api/user/recovery/emergency/complete- auth: authenticated user
- marks emergency flow as completed after user replaces backup password.
Admin endpoints
-
POST /api/admin/recovery/code- auth: ops admin (
adminor delegated MSP admin) - params:
targetUserIdexpiresMinutes(default 15, bounded)
- behavior:
- issues one-time recovery code for target user,
- returns code and expiration.
- auth: ops admin (
-
POST /api/admin/recovery/emergency- auth: ops admin
- params:
targetUserIddurationHours(default 24, bounded)
- behavior:
- requires user opted into managed + emergency modes,
- sets temporary Nextcloud password for target user,
- sets emergency-required and emergency-expiry flags.
Stored app/user config keys
User-scope keys (IConfig::setUserValue, app qortal_integration):
user_recovery_managed_enableduser_recovery_emergency_login_enableduser_recovery_wallet_iduser_recovery_escrow_blobuser_recovery_escrow_updated_atuser_recovery_failed_attemptsuser_recovery_locked_untiluser_recovery_emergency_untiluser_recovery_emergency_requireduser_recovery_emergency_started_byuser_recovery_emergency_started_at
App-scope key:
recovery_admin_code_registry
Verify on devcloud
Use your normal compose file + env file pattern:
docker compose -f docker-compose.devprod.nossl.yml --env-file .env.devprod exec --user www-data nextcloud php -l /var/www/html/custom_apps/qortal_integration/lib/Controller/ApiController.php
docker compose -f docker-compose.devprod.nossl.yml --env-file .env.devprod exec --user www-data nextcloud php -l /var/www/html/custom_apps/qortal_integration/lib/Settings/PersonalSettings.php
docker compose -f docker-compose.devprod.nossl.yml --env-file .env.devprod exec --user www-data nextcloud php -l /var/www/html/custom_apps/qortal_integration/templates/personal.php
Functional smoke:
- User enables managed recovery in personal settings.
- Admin issues recovery code for that user.
- User reveals backup password with admin code + recovery passphrase.
- Admin triggers emergency reset (if user opted in).
- User logs in, rotates backup password, clicks emergency complete.
Known follow-up work
- Optionally integrate with Nextcloud Passwords app if a stable API contract is confirmed for target NC versions.
- Add hard enforcement of emergency completion in login/post-login policy flow if required.