refactor: remove passkey login
This commit is contained in:
@@ -909,31 +909,7 @@ def _migrate_to_v20(conn):
|
||||
|
||||
|
||||
def _migrate_to_v21(conn):
|
||||
"""迁移到版本21 - Passkey 认证设备表"""
|
||||
cursor = conn.cursor()
|
||||
|
||||
cursor.execute(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS passkeys (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
owner_type TEXT NOT NULL,
|
||||
owner_id INTEGER NOT NULL,
|
||||
device_name TEXT NOT NULL,
|
||||
credential_id TEXT UNIQUE NOT NULL,
|
||||
public_key TEXT NOT NULL,
|
||||
sign_count INTEGER DEFAULT 0,
|
||||
transports TEXT DEFAULT '',
|
||||
aaguid TEXT DEFAULT '',
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
last_used_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
"""
|
||||
)
|
||||
cursor.execute("CREATE INDEX IF NOT EXISTS idx_passkeys_owner ON passkeys(owner_type, owner_id)")
|
||||
cursor.execute(
|
||||
"CREATE INDEX IF NOT EXISTS idx_passkeys_owner_last_used ON passkeys(owner_type, owner_id, last_used_at)"
|
||||
)
|
||||
|
||||
"""迁移到版本21 - 旧认证设备功能已移除,保留版本号兼容历史数据库。"""
|
||||
conn.commit()
|
||||
|
||||
|
||||
|
||||
173
db/passkeys.py
173
db/passkeys.py
@@ -1,173 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import annotations
|
||||
|
||||
import sqlite3
|
||||
|
||||
import db_pool
|
||||
from db.utils import get_cst_now_str
|
||||
|
||||
_OWNER_TYPES = {"user", "admin"}
|
||||
|
||||
|
||||
def _normalize_owner_type(owner_type: str) -> str:
|
||||
normalized = str(owner_type or "").strip().lower()
|
||||
if normalized not in _OWNER_TYPES:
|
||||
raise ValueError(f"invalid owner_type: {owner_type}")
|
||||
return normalized
|
||||
|
||||
|
||||
def list_passkeys(owner_type: str, owner_id: int) -> list[dict]:
|
||||
owner = _normalize_owner_type(owner_type)
|
||||
with db_pool.get_db() as conn:
|
||||
cursor = conn.cursor()
|
||||
cursor.execute(
|
||||
"""
|
||||
SELECT id, owner_type, owner_id, device_name, credential_id, transports,
|
||||
sign_count, aaguid, created_at, last_used_at
|
||||
FROM passkeys
|
||||
WHERE owner_type = ? AND owner_id = ?
|
||||
ORDER BY datetime(created_at) DESC, id DESC
|
||||
""",
|
||||
(owner, int(owner_id)),
|
||||
)
|
||||
return [dict(row) for row in cursor.fetchall()]
|
||||
|
||||
|
||||
def count_passkeys(owner_type: str, owner_id: int) -> int:
|
||||
owner = _normalize_owner_type(owner_type)
|
||||
with db_pool.get_db() as conn:
|
||||
cursor = conn.cursor()
|
||||
cursor.execute(
|
||||
"SELECT COUNT(*) AS count FROM passkeys WHERE owner_type = ? AND owner_id = ?",
|
||||
(owner, int(owner_id)),
|
||||
)
|
||||
row = cursor.fetchone()
|
||||
if not row:
|
||||
return 0
|
||||
try:
|
||||
return int(row["count"] or 0)
|
||||
except Exception:
|
||||
try:
|
||||
return int(row[0] or 0)
|
||||
except Exception:
|
||||
return 0
|
||||
|
||||
|
||||
def get_passkey_by_credential_id(credential_id: str) -> dict | None:
|
||||
credential = str(credential_id or "").strip()
|
||||
if not credential:
|
||||
return None
|
||||
|
||||
with db_pool.get_db() as conn:
|
||||
cursor = conn.cursor()
|
||||
cursor.execute(
|
||||
"""
|
||||
SELECT id, owner_type, owner_id, device_name, credential_id, public_key,
|
||||
sign_count, transports, aaguid, created_at, last_used_at
|
||||
FROM passkeys
|
||||
WHERE credential_id = ?
|
||||
""",
|
||||
(credential,),
|
||||
)
|
||||
row = cursor.fetchone()
|
||||
return dict(row) if row else None
|
||||
|
||||
|
||||
def get_passkey_by_id(owner_type: str, owner_id: int, passkey_id: int) -> dict | None:
|
||||
owner = _normalize_owner_type(owner_type)
|
||||
|
||||
with db_pool.get_db() as conn:
|
||||
cursor = conn.cursor()
|
||||
cursor.execute(
|
||||
"""
|
||||
SELECT id, owner_type, owner_id, device_name, credential_id, public_key,
|
||||
sign_count, transports, aaguid, created_at, last_used_at
|
||||
FROM passkeys
|
||||
WHERE id = ? AND owner_type = ? AND owner_id = ?
|
||||
""",
|
||||
(int(passkey_id), owner, int(owner_id)),
|
||||
)
|
||||
row = cursor.fetchone()
|
||||
return dict(row) if row else None
|
||||
|
||||
|
||||
def create_passkey(
|
||||
owner_type: str,
|
||||
owner_id: int,
|
||||
*,
|
||||
credential_id: str,
|
||||
public_key: str,
|
||||
sign_count: int,
|
||||
device_name: str,
|
||||
transports: str = "",
|
||||
aaguid: str = "",
|
||||
) -> int | None:
|
||||
owner = _normalize_owner_type(owner_type)
|
||||
now = get_cst_now_str()
|
||||
|
||||
with db_pool.get_db() as conn:
|
||||
cursor = conn.cursor()
|
||||
try:
|
||||
cursor.execute(
|
||||
"""
|
||||
INSERT INTO passkeys (
|
||||
owner_type,
|
||||
owner_id,
|
||||
device_name,
|
||||
credential_id,
|
||||
public_key,
|
||||
sign_count,
|
||||
transports,
|
||||
aaguid,
|
||||
created_at,
|
||||
last_used_at
|
||||
)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
(
|
||||
owner,
|
||||
int(owner_id),
|
||||
str(device_name or "").strip(),
|
||||
str(credential_id or "").strip(),
|
||||
str(public_key or "").strip(),
|
||||
int(sign_count or 0),
|
||||
str(transports or "").strip(),
|
||||
str(aaguid or "").strip(),
|
||||
now,
|
||||
now,
|
||||
),
|
||||
)
|
||||
conn.commit()
|
||||
return int(cursor.lastrowid)
|
||||
except sqlite3.IntegrityError:
|
||||
return None
|
||||
|
||||
|
||||
def update_passkey_usage(passkey_id: int, new_sign_count: int) -> bool:
|
||||
now = get_cst_now_str()
|
||||
with db_pool.get_db() as conn:
|
||||
cursor = conn.cursor()
|
||||
cursor.execute(
|
||||
"""
|
||||
UPDATE passkeys
|
||||
SET sign_count = ?,
|
||||
last_used_at = ?
|
||||
WHERE id = ?
|
||||
""",
|
||||
(int(new_sign_count or 0), now, int(passkey_id)),
|
||||
)
|
||||
conn.commit()
|
||||
return cursor.rowcount > 0
|
||||
|
||||
|
||||
def delete_passkey(owner_type: str, owner_id: int, passkey_id: int) -> bool:
|
||||
owner = _normalize_owner_type(owner_type)
|
||||
with db_pool.get_db() as conn:
|
||||
cursor = conn.cursor()
|
||||
cursor.execute(
|
||||
"DELETE FROM passkeys WHERE id = ? AND owner_type = ? AND owner_id = ?",
|
||||
(int(passkey_id), owner, int(owner_id)),
|
||||
)
|
||||
conn.commit()
|
||||
return cursor.rowcount > 0
|
||||
21
db/schema.py
21
db/schema.py
@@ -74,25 +74,6 @@ def ensure_schema(conn) -> None:
|
||||
"""
|
||||
)
|
||||
|
||||
# Passkey 认证设备表(用户/管理员)
|
||||
cursor.execute(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS passkeys (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
owner_type TEXT NOT NULL,
|
||||
owner_id INTEGER NOT NULL,
|
||||
device_name TEXT NOT NULL,
|
||||
credential_id TEXT UNIQUE NOT NULL,
|
||||
public_key TEXT NOT NULL,
|
||||
sign_count INTEGER DEFAULT 0,
|
||||
transports TEXT DEFAULT '',
|
||||
aaguid TEXT DEFAULT '',
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
last_used_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
"""
|
||||
)
|
||||
|
||||
# ==================== 安全防护:威胁检测相关表 ====================
|
||||
|
||||
# 威胁事件日志表
|
||||
@@ -448,8 +429,6 @@ def ensure_schema(conn) -> None:
|
||||
cursor.execute("CREATE INDEX IF NOT EXISTS idx_users_status_created_at ON users(status, created_at)")
|
||||
cursor.execute("CREATE INDEX IF NOT EXISTS idx_login_fingerprints_user ON login_fingerprints(user_id)")
|
||||
cursor.execute("CREATE INDEX IF NOT EXISTS idx_login_ips_user ON login_ips(user_id)")
|
||||
cursor.execute("CREATE INDEX IF NOT EXISTS idx_passkeys_owner ON passkeys(owner_type, owner_id)")
|
||||
cursor.execute("CREATE INDEX IF NOT EXISTS idx_passkeys_owner_last_used ON passkeys(owner_type, owner_id, last_used_at)")
|
||||
cursor.execute("CREATE INDEX IF NOT EXISTS idx_social_login_bindings_user ON social_login_bindings(user_id)")
|
||||
cursor.execute("CREATE INDEX IF NOT EXISTS idx_social_login_bindings_provider_uid ON social_login_bindings(provider, social_uid)")
|
||||
cursor.execute("CREATE INDEX IF NOT EXISTS idx_admin_social_login_bindings_admin ON admin_social_login_bindings(admin_id)")
|
||||
|
||||
Reference in New Issue
Block a user