Aug 26 - Enhance security 3
CI / Python lint (flake8) (push) Has been cancelled
CI / Python syntax check (push) Has been cancelled
CI / Alembic migration chain (push) Has been cancelled
CI / JavaScript syntax check (push) Has been cancelled
CI / Pytest (push) Has been cancelled
CI / Build extension zip (push) Has been cancelled

This commit is contained in:
2026-08-26 13:54:48 -04:00
parent 6c1bef73c8
commit cc216b0d98
16 changed files with 11056 additions and 43 deletions
+87
View File
@@ -0,0 +1,87 @@
"""
Regression tests for share expiry failing open (review finding #10).
create_share parsed expires_days inside `try: ... except: pass`, so any value it
could not parse silently became "never expires" — the opposite of what the user
asked for, with no error to notice.
"""
from datetime import datetime, timedelta, timezone
from tests.conftest import add_item, auth_headers, make_user
def _share(client, token, item_id, recipient='friend@example.com', **extra):
body = {
'item_id': item_id,
'recipient_email': recipient,
'enc_data': 'ECDH-CT',
'iv': 'ECDH-IV',
'item_name': 'password',
'item_type': 'password',
}
body.update(extra)
return client.post('/api/sharing', headers=auth_headers(token), json=body)
def test_valid_expiry_is_applied(client, app):
token, _ = make_user(client)
item_id = add_item(client, token)
res = _share(client, token, item_id, expires_days=7)
assert res.status_code == 201, res.get_json()
expires_at = res.get_json()['expires_at']
assert expires_at is not None
parsed = datetime.fromisoformat(expires_at)
expected = datetime.now(timezone.utc).replace(tzinfo=None) + timedelta(days=7)
assert abs((parsed - expected).total_seconds()) < 60
def test_null_expiry_means_never(client, app):
token, _ = make_user(client)
item_id = add_item(client, token)
res = _share(client, token, item_id, expires_days=None)
assert res.status_code == 201
assert res.get_json()['expires_at'] is None
def test_omitted_expiry_means_never(client, app):
token, _ = make_user(client)
item_id = add_item(client, token)
res = _share(client, token, item_id)
assert res.status_code == 201
assert res.get_json()['expires_at'] is None
def test_unparseable_expiry_is_rejected_not_silently_dropped(client, app):
"""The bug: 'seven' used to yield a share that never expires."""
token, _ = make_user(client)
for bad in ('seven', '7 days', {}, [], 'NaN', ''):
item_id = add_item(client, token)
res = _share(client, token, item_id, expires_days=bad)
assert res.status_code == 400, (
f'expires_days={bad!r} accepted; share would never expire'
)
assert 'expires_days' in res.get_json()['error']
def test_out_of_range_expiry_is_rejected(client, app):
token, _ = make_user(client)
for bad in (-1, -30, 4000):
item_id = add_item(client, token)
res = _share(client, token, item_id, expires_days=bad)
assert res.status_code == 400, f'expires_days={bad!r} accepted'
def test_zero_expiry_means_never(client, app):
"""0 is 'no expiry', consistent with null — not 'expires immediately'."""
token, _ = make_user(client)
item_id = add_item(client, token)
res = _share(client, token, item_id, expires_days=0)
assert res.status_code == 201
assert res.get_json()['expires_at'] is None