aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-hub/tests/test_hub_api.py
diff options
context:
space:
mode:
Diffstat (limited to 'packages/meshbay-hub/tests/test_hub_api.py')
-rw-r--r--packages/meshbay-hub/tests/test_hub_api.py56
1 files changed, 52 insertions, 4 deletions
diff --git a/packages/meshbay-hub/tests/test_hub_api.py b/packages/meshbay-hub/tests/test_hub_api.py
index 5e9e6c2..37e8e4f 100644
--- a/packages/meshbay-hub/tests/test_hub_api.py
+++ b/packages/meshbay-hub/tests/test_hub_api.py
@@ -621,6 +621,54 @@ async def test_password_rehash_on_login(client, app):
assert r.status_code == 200
+@pytest.mark.asyncio
+async def test_a_v3_auth_key_hash_is_rewritten_at_the_current_parameters(client, db_session):
+ """Every account registered before the 64 MiB change holds a v3 (256 MB)
+ hash. It must keep signing in, and be rewritten on the way through —
+ otherwise the old cost is paid at every sign-in for ever."""
+ import os
+
+ from cryptography.hazmat.primitives.kdf.argon2 import Argon2id
+ from meshbay_hub.auth import (
+ _ARGON2_KEY_LEN,
+ _ARGON2_LANES,
+ _ARGON2_VERSIONS,
+ current_pw_version,
+ )
+ from meshbay_hub.db.models import User
+ from sqlalchemy import select
+
+ assert current_pw_version() > 3
+ assert _ARGON2_VERSIONS[current_pw_version()]["memory_cost"] == 65536
+
+ key = "dGVzdGF1dGhrZXl0ZXN0YXV0aGtleXRlc3RhdXRo"
+ r = await client.post("/v1/users/register", json={
+ "username": "v3holder", "email": "v3holder@test.com", "auth_key": key})
+ assert r.status_code == 201, r.text
+
+ salt = os.urandom(16)
+ v3 = _ARGON2_VERSIONS[3]
+ user = (await db_session.execute(
+ select(User).where(User.username == "v3holder"))).scalar_one()
+ user.pw_hash = Argon2id(salt=salt, length=_ARGON2_KEY_LEN, iterations=v3["iterations"],
+ lanes=_ARGON2_LANES, memory_cost=v3["memory_cost"]).derive(key.encode())
+ user.pw_salt, user.pw_version = salt, 3
+ await db_session.commit()
+
+ r = await client.post("/v1/users/login", json={"username": "v3holder", "auth_key": key})
+ assert r.status_code == 200, r.text
+
+ db_session.expire_all()
+ user = (await db_session.execute(
+ select(User).where(User.username == "v3holder"))).scalar_one()
+ assert user.pw_version == current_pw_version()
+ assert user.pw_hash != Argon2id(salt=salt, length=_ARGON2_KEY_LEN, iterations=3,
+ lanes=_ARGON2_LANES, memory_cost=65536).derive(key.encode())
+
+ r = await client.post("/v1/users/login", json={"username": "v3holder", "auth_key": key})
+ assert r.status_code == 200, r.text
+
+
# ── WebRTC signaling (9.2) ──────────────────────────────────────────────────
@pytest.mark.asyncio
@@ -764,7 +812,8 @@ async def test_webapp_html_includes_scripts(client):
@pytest.mark.asyncio
async def test_register_with_auth_key(client, app):
- """Registration with auth_key sets pw_version 3."""
+ """Registration with auth_key sets the current auth_key pw_version."""
+ from meshbay_hub.auth import current_pw_version
from meshbay_hub.db.engine import get_db
from meshbay_hub.db.models import User
from sqlalchemy import select
@@ -783,7 +832,7 @@ async def test_register_with_auth_key(client, app):
async for db in get_db():
result = await db.execute(select(User).where(User.username == "authuser"))
user = result.scalar_one()
- assert user.pw_version == 3
+ assert user.pw_version == current_pw_version()
break
@@ -932,12 +981,11 @@ async def test_login_legacy_migration(client, app):
})
assert r.status_code == 200
- # Verify pw_version is now 3 (migrated)
+ # Verify pw_version is now the current auth_key version (migrated)
async for db in get_db():
result = await db.execute(select(User).where(User.username == "migrateuser"))
user = result.scalar_one()
assert user.pw_version == current_pw_version()
- assert user.pw_version == 3
break
# Login again with auth_key only → should succeed (migrated account)