fix2 tokens

This commit is contained in:
Mateusz Gruszczyński
2026-08-03 01:35:05 +02:00
parent 49dad1a5f4
commit e3ee6319b9
25 changed files with 1420 additions and 223 deletions
+207
View File
@@ -0,0 +1,207 @@
#!/usr/bin/env python3
from __future__ import annotations
import hashlib
import re
import sqlite3
from datetime import datetime, timezone
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
MIGRATIONS = ROOT / "migrations" / "sqlite"
SQLITE_QUERIES = ROOT / "src" / "queries" / "sqlite.rs"
def query(name: str) -> str:
source = SQLITE_QUERIES.read_text()
pattern = rf'Query::{re.escape(name)}\s*=>\s*\{{\s*r#"(.*?)"#\s*\}}'
match = re.search(pattern, source, re.S)
if not match:
raise AssertionError(f"Query::{name} not found")
return match.group(1)
def parse_rfc3339(value: str) -> datetime:
parsed = datetime.fromisoformat(value.replace("Z", "+00:00"))
if parsed.tzinfo is None:
raise ValueError("timestamp must include timezone")
return parsed.astimezone(timezone.utc)
def active_permission(row: tuple[str, str, str | None] | None, now: datetime) -> str | None:
if row is None:
return None
permission, session_expires_at, link_expires_at = row
try:
if parse_rfc3339(session_expires_at) <= now:
return None
if link_expires_at is not None and parse_rfc3339(link_expires_at) <= now:
return None
except ValueError:
return None
return permission if permission in {"ro", "rw"} else None
def link_active(expires_at: str | None, now: datetime) -> bool:
if expires_at is None:
return True
try:
return parse_rfc3339(expires_at) > now
except ValueError:
return False
def apply(connection: sqlite3.Connection, paths: list[Path]) -> None:
for path in paths:
connection.executescript(path.read_text())
def main() -> None:
migrations = sorted(MIGRATIONS.glob("*.sql"))
before_sessions = [path for path in migrations if path.name < "0026_share_link_sessions.sql"]
session_migration = MIGRATIONS / "0026_share_link_sessions.sql"
db = sqlite3.connect(":memory:")
db.execute("PRAGMA foreign_keys = ON")
apply(db, before_sessions)
db.execute(
"INSERT INTO users (nickname, nickname_key, email, email_key, password_hash) "
"VALUES (?, ?, ?, ?, ?)",
("Owner", "owner", "owner@example.test", "owner@example.test", "hash"),
)
raw_link = "legacy-share-token"
share_hash = hashlib.sha256(raw_link.encode()).hexdigest()
db.execute(
"INSERT INTO resource_share_links "
"(token_hash, token, resource_kind, resource_slug, permission, expires_at, created_by) "
"VALUES (?, ?, 'workspace', 'private-space', 'ro', NULL, 1)",
(share_hash, raw_link),
)
db.executescript(session_migration.read_text())
assert db.execute(
"SELECT token FROM resource_share_links WHERE token_hash = ?", (share_hash,)
).fetchone() == (None,), "migration must erase persisted plaintext share tokens"
source_sql = query("SHARE_LINK_SESSION_SOURCE")
insert_sql = query("SHARE_SESSION_INSERT")
permission_sql = query("SHARE_SESSION_PERMISSION")
revoke_sessions_sql = query("SHARE_SESSIONS_DELETE_BY_LINK")
delete_expired_sql = query("SHARE_SESSIONS_DELETE_EXPIRED")
link_insert_sql = query("SHARE_LINK_INSERT")
sharing_list_sql = query("RESOURCE_SHARING_LINKS")
now = datetime(2026, 8, 2, 23, 0, tzinfo=timezone.utc)
source = db.execute(source_sql, (share_hash, "workspace", "private-space")).fetchone()
assert source == (share_hash, "ro", None)
session_raw = "opaque-browser-session"
session_hash = hashlib.sha256(session_raw.encode()).hexdigest()
db.execute(
insert_sql,
(
session_hash,
share_hash,
"workspace",
"private-space",
"2026-08-03T00:00:00+00:00",
),
)
def permission(slug: str = "private-space") -> str | None:
row = db.execute(permission_sql, (session_hash, "workspace", slug)).fetchone()
return active_permission(row, now)
assert permission() == "ro", "ro share session must remain read-only"
assert permission("another-space") is None, "session must be scoped to one resource"
db.execute(
"UPDATE resource_share_links SET permission = 'rw' WHERE token_hash = ?", (share_hash,)
)
assert permission() == "rw", "ro -> rw change must affect active sessions immediately"
db.execute(
"UPDATE resource_share_links SET permission = 'ro' WHERE token_hash = ?", (share_hash,)
)
assert permission() == "ro", "rw -> ro change must remove write access immediately"
db.execute(
"UPDATE resource_share_sessions SET expires_at = ? WHERE session_token_hash = ?",
("2026-08-02T22:59:59+00:00", session_hash),
)
assert permission() is None, "expired browser session must be denied"
db.execute(
"UPDATE resource_share_sessions SET expires_at = ? WHERE session_token_hash = ?",
("2026-08-03T00:00:00+00:00", session_hash),
)
# Offset timestamps are parsed chronologically rather than compared as text.
db.execute(
"UPDATE resource_share_links SET expires_at = ? WHERE token_hash = ?",
("2026-08-03T01:30:00+02:00", share_hash),
)
row = db.execute(permission_sql, (session_hash, "workspace", "private-space")).fetchone()
assert active_permission(row, now) == "ro"
later = datetime(2026, 8, 2, 23, 31, tzinfo=timezone.utc)
assert active_permission(row, later) is None, "expired link must invalidate its sessions"
db.execute(
"UPDATE resource_share_links SET expires_at = 'not-a-date' WHERE token_hash = ?",
(share_hash,),
)
row = db.execute(permission_sql, (session_hash, "workspace", "private-space")).fetchone()
assert active_permission(row, now) is None, "malformed expiration must fail closed"
assert not link_active("not-a-date", now)
db.execute(
"UPDATE resource_share_links SET expires_at = NULL, revoked_at = ? WHERE token_hash = ?",
("2026-08-02T23:05:00+00:00", share_hash),
)
assert db.execute(permission_sql, (session_hash, "workspace", "private-space")).fetchone() is None
deleted = db.execute(
revoke_sessions_sql, (share_hash, "workspace", "private-space")
).rowcount
assert deleted == 1, "revoking a link must remove all derived sessions"
# Newly created links persist only the hash; the plaintext column stays NULL.
second_raw = "one-time-returned-token"
second_hash = hashlib.sha256(second_raw.encode()).hexdigest()
db.execute(
link_insert_sql,
(second_hash, "workspace", "second-space", "rw", None, 1),
)
assert db.execute(
"SELECT token, permission FROM resource_share_links WHERE token_hash = ?", (second_hash,)
).fetchone() == (None, "rw")
listed_link = db.execute(sharing_list_sql, ("workspace", "second-space")).fetchone()
assert listed_link == (
second_hash,
"rw",
None,
listed_link[3],
), "management listing must never return the plaintext share token"
db.execute(
insert_sql,
(
hashlib.sha256(b"expired-row").hexdigest(),
second_hash,
"workspace",
"second-space",
"2026-08-02T22:00:00+00:00",
),
)
db.execute(delete_expired_sql, ("2026-08-02T23:00:00+00:00",))
assert db.execute(
"SELECT COUNT(*) FROM resource_share_sessions WHERE share_token_hash = ?", (second_hash,)
).fetchone() == (0,), "expired session cleanup must remove stale rows"
db.execute("DELETE FROM resource_share_links WHERE token_hash = ?", (second_hash,))
assert db.execute(
"SELECT COUNT(*) FROM resource_share_sessions WHERE share_token_hash = ?", (second_hash,)
).fetchone() == (0,), "link deletion must cascade to sessions"
print("share session SQL regression tests: 17 passed")
if __name__ == "__main__":
main()