* Add revision_date to org policies
Org policy JSON responses never included a revisionDate field, unlike
every other synced entity. The official Bitwarden server always sets
it, and current official clients (recently migrated to the WASM SDK's
typed PolicyView) now assume it is always a valid date string. Its
absence deserializes to undefined client-side, which then throws
(RangeError: Invalid time value) when the client formats it, breaking
the whole policy sync pipeline and silently emptying the vault view in
the browser and desktop apps.
Adds a revision_date column (mirroring the existing pattern used by
Send), stamped on creation and bumped on every save.
* Fix migration correctness for org policy revision_date
Caught by review: SQLite rejects non-constant defaults in ALTER TABLE
ADD COLUMN, so the sqlite migration would fail outright on every
existing installation (vaultwarden's default backend) rather than the
postgresql setup this was developed against.
- sqlite/mysql: add the column with a constant placeholder default,
then backfill via UPDATE, since neither allows a volatile default
in ALTER TABLE ADD COLUMN (mysql does allow it, but a constant
keeps the three backends' migrations symmetric).
- mysql: use DATETIME instead of TIMESTAMP, matching this repo's
existing revision_date columns, and backfill with UTC_TIMESTAMP()
instead of a session-timezone-dependent CURRENT_TIMESTAMP.
- postgresql: backfill with `now() AT TIME ZONE 'utc'` instead of a
DEFAULT now(), since assigning timestamptz now() into this naive
TIMESTAMP column would otherwise cast through the server's TimeZone
GUC and store local wall-clock instead of UTC on non-UTC servers.
- mysql/postgresql: add a real down.sql (DROP COLUMN) instead of
leaving it empty.
* Move org policy revision_date migration after the latest one
---------
Co-authored-by: Daniel García <dani-garcia@users.noreply.github.com>
* Allow email-only /api/two-factor/send-email-login for mobile clients
Mobile clients (iOS) may call /api/two-factor/send-email-login with only the user's email and without a MasterPasswordHash or an AuthRequest. Permit email-only requests so the server will send the email 2FA token in that flow.\n\nModified: src/api/core/two_factor/email.rs
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix(email-2fa): use device-identifier fallback when no password hash submitted
iOS clients call /api/two-factor/send-email-login with an email and
DeviceIdentifier but without masterPasswordHash or authRequestId after
receiving a 2FA-required response from the token endpoint. The previous
empty else-block allowed any caller to trigger a 2FA email for any
account knowing only the email address.
Replace the empty block with a device-identifier-based fallback:
- Look up the most-recently-active device via find_by_device_for_email2fa.
- Verify the device's associated user email matches the submitted email.
- Log (debug) when the fallback path is exercised for operator visibility.
- Reject with the original error when no device identifier is provided or
when the device maps to a different account.
Fixes#7568
* Check the pending 2FA login for this user and device
Look up the pending 2FA login for the user and device instead of the
latest one on the device, answer a failed check with the same error and
IP/username log detail as a wrong password, and escape the device id in
the logs.
---------
Co-authored-by: Arunabha-Mukhopadhyay <dkarunabha2006@gmail.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* 2FA using userVerificationToken
* Fix 2FA Yubikeys
* TwoFactor.find_by_user_and_type take enum parameter not i32
* log_user_event take enum parameter not i32
* Fix 2fa webauthn
* Prevent 2FA claims reuse
* 2fa webauthn return keys when deleting
* 2fa reset twofactor_remember
* Reject 2FA verification tokens issued for another provider
The Email and Duo claims only have optional fields, so a userVerificationToken minted for another
provider deserialized into them and was accepted. Each provider's claims now reject unknown fields,
with a test that every token only parses as its own provider.
Also fix the email 2FA login in the Playwright user setup, which used an undefined `mailBuffer`.
---------
Co-authored-by: Timshel <timshel@users.noreply.github.com>
Co-authored-by: Daniel García <dani-garcia@users.noreply.github.com>
* Support new account recovery password payload
* Address account recovery review feedback
* Check the account recovery password before sending the recovery email
---------
Co-authored-by: Daniel García <dani-garcia@users.noreply.github.com>
Both notification hubs send a Ping every 15 seconds but ignore the
Pong, so the loop only ends on a Close frame, EOF or a socket error.
When a client disappears without the TCP connection being closed, for
example behind a reverse proxy or CDN that keeps the upstream
connection open, none of these ever happens. The connection, its file
descriptor and its map entry are then kept forever, until the process
runs out of file descriptors and stops accepting connections and
opening the database.
Keep track of when something was last received from the client, Pongs
included, and close the connection when nothing was received for 30
seconds. This is the default ClientTimeoutInterval of ASP.NET Core
SignalR, which the official server uses.
Fixes#7805
Co-authored-by: Cassian433 <262026629+Cassian433@users.noreply.github.com>
Co-authored-by: Daniel García <dani-garcia@users.noreply.github.com>
4 days ago
47 changed files with 1360 additions and 569 deletions
// and <https://github.com/bitwarden/server/blob/9030c42bf7d8f9ac2ff9fee85c39588d5eb81499/src/Api/Vault/Models/Request/CipherRequestModel.cs#L498-L519>
// and <https://github.com/bitwarden/server/blob/9030c42bf7d8f9ac2ff9fee85c39588d5eb81499/src/Api/Vault/Models/Request/CipherRequestModel.cs#L560-L604>