mirror of
https://github.com/dani-garcia/vaultwarden.wiki.git
synced 2026-11-16 00:25:56 +02:00
* Add the account recovery V2 upgrade routes
GET /organizations/{orgId}/users/keys/pending-v2-upgrades lists, a page at a
time, the memberships whose account recovery key still wraps the member's V1
user key after an upgrade to V2 encryption, with the upgrade token the admin
re-wraps it from. POST .../v2-upgrades stores the re-wrapped keys in one
transaction, or unenrolls the members whose token holds no usable key. Only
Owners and Admins, an Admin never for Owners, and a membership that changed
since the read is skipped. GET /organizations/{orgId}/private-key gives the
organization's private key these need, to everyone with Manage users as
upstream. The SDK's encrypted migrator calls all three.
Enrolling in or withdrawing from account recovery drops a leftover upgrade
token, which would otherwise get a member who re-enrolled after the upgrade
unenrolled.
* Check membership for the organization public key in the handler
The public key routes serve the placeholder SSO organization's key to users
without an organization, so they couldn't require the member guard, but it
still ran for every request: it logged a membership error for each legitimate
v2 JIT password setup and authenticated the request twice. The routes now
authenticate once, return the placeholder key first, and check the membership
themselves, with the same rule as the guard.
* List attachments in sync with a stable URL
Sync and the cipher responses list each attachment with an unsigned URL of
upstream's form, which no longer changes on every sync nor costs a presign per
attachment on S3, and which isn't served without a token. The attachment routes
sign it: the cipher route and its admin variant, and the emergency access view's
route the web vault downloads through, which is added. The admin variant also
signs it for a member who can open the item themselves, because the web vault's
fallback to the listed URL no longer works.
* Seed the SDK live tests' vectors with their attachments
Sync now lists attachments with a stable URL, so the rotation test's before and after comparison holds with them.
Only the legacy attachments without a key of their own stay out: the SDK refuses to rotate a vault holding one.
61 lines
2.1 KiB
Python
61 lines
2.1 KiB
Python
"""Seeds one of the SDK's user test vectors, vault included, through vaultwarden's test seeder.
|
|
|
|
Usage: seed_vector.py <vector.json> <seeder url> <seeder username> <seeder password>
|
|
|
|
Prints the account's email and password, one per line. Exits 3, printing why, for a vector the tests can't log in
|
|
with (no master password), and 1 if the seeder refuses it.
|
|
"""
|
|
|
|
import base64
|
|
import json
|
|
import sys
|
|
import urllib.error
|
|
import urllib.request
|
|
import uuid
|
|
|
|
SKIP = 3
|
|
|
|
|
|
def main() -> int:
|
|
vector_file, seeder_url, username, password = sys.argv[1:5]
|
|
with open(vector_file, encoding="utf-8") as f:
|
|
vector = json.load(f)
|
|
|
|
has_master_password = any("masterPasswordUnlock" in method for method in vector.get("unlockMethods", []))
|
|
if not has_master_password or "password" not in vector.get("account", {}):
|
|
print("no master password")
|
|
return SKIP
|
|
|
|
# Without the legacy attachments that have no key of their own: the SDK refuses to rotate a vault holding one
|
|
# (`OldAttachments`), on any server.
|
|
for cipher in vector.get("vault", {}).get("ciphers", []):
|
|
encrypted = cipher.get("encrypted", {})
|
|
if encrypted.get("attachments"):
|
|
encrypted["attachments"] = [a for a in encrypted["attachments"] if a.get("key")] or None
|
|
|
|
credentials = base64.b64encode(f"{username}:{password}".encode()).decode()
|
|
request = urllib.request.Request(
|
|
f"{seeder_url}/seed",
|
|
data=json.dumps({"template": "TestVectorUserScene", "arguments": vector}).encode(),
|
|
method="POST",
|
|
headers={
|
|
"Authorization": f"Basic {credentials}",
|
|
"Content-Type": "application/json",
|
|
"X-Play-Id": f"sdk-live-tests-{uuid.uuid4()}",
|
|
},
|
|
)
|
|
try:
|
|
with urllib.request.urlopen(request) as response:
|
|
result = json.load(response)["result"]
|
|
except urllib.error.HTTPError as e:
|
|
print(f"The seeder refused {vector_file}: {e.code} {e.read().decode(errors='replace')}", file=sys.stderr)
|
|
return 1
|
|
|
|
print(result["email"])
|
|
print(vector["account"]["password"])
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|