Files

158 lines
5.4 KiB
Markdown

# 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-sha256` with per-record salt and iterations
- 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:
- `walletId`
- `currentBackupPassword`
- `recoveryPassphrase`
- `recoveryPassphraseConfirm`
- `managedEnabled` (`1`)
- `emergencyLoginEnabled` (`1` or 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:
- `recoveryPassphrase`
- `adminCode`
- 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 (`admin` or delegated MSP admin)
- params:
- `targetUserId`
- `expiresMinutes` (default 15, bounded)
- behavior:
- issues one-time recovery code for target user,
- returns code and expiration.
- `POST /api/admin/recovery/emergency`
- auth: ops admin
- params:
- `targetUserId`
- `durationHours` (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_enabled`
- `user_recovery_emergency_login_enabled`
- `user_recovery_wallet_id`
- `user_recovery_escrow_blob`
- `user_recovery_escrow_updated_at`
- `user_recovery_failed_attempts`
- `user_recovery_locked_until`
- `user_recovery_emergency_until`
- `user_recovery_emergency_required`
- `user_recovery_emergency_started_by`
- `user_recovery_emergency_started_at`
App-scope key:
- `recovery_admin_code_registry`
## Verify on devcloud
Use your normal compose file + env file pattern:
```bash
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:
1. User enables managed recovery in personal settings.
2. Admin issues recovery code for that user.
3. User reveals backup password with admin code + recovery passphrase.
4. Admin triggers emergency reset (if user opted in).
5. 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.