mdbq 4.0.97__py3-none-any.whl → 4.0.99__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of mdbq might be problematic. Click here for more details.
- mdbq/__version__.py +1 -1
- mdbq/auth/auth_backend.py +129 -68
- {mdbq-4.0.97.dist-info → mdbq-4.0.99.dist-info}/METADATA +1 -1
- {mdbq-4.0.97.dist-info → mdbq-4.0.99.dist-info}/RECORD +6 -6
- {mdbq-4.0.97.dist-info → mdbq-4.0.99.dist-info}/WHEEL +0 -0
- {mdbq-4.0.97.dist-info → mdbq-4.0.99.dist-info}/top_level.txt +0 -0
mdbq/__version__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
VERSION = '4.0.
|
|
1
|
+
VERSION = '4.0.99'
|
mdbq/auth/auth_backend.py
CHANGED
|
@@ -224,6 +224,7 @@ class StandaloneAuthManager:
|
|
|
224
224
|
device_id VARCHAR(255) CHARACTER SET ascii NOT NULL,
|
|
225
225
|
device_fingerprint VARCHAR(255) CHARACTER SET ascii NOT NULL,
|
|
226
226
|
login_domain VARCHAR(255) NOT NULL DEFAULT '' COMMENT '登录时的域名',
|
|
227
|
+
session_version INT UNSIGNED NOT NULL DEFAULT 1 COMMENT '会话版本号',
|
|
227
228
|
device_name VARCHAR(255) NOT NULL DEFAULT 'Unknown Device',
|
|
228
229
|
custom_name VARCHAR(255) DEFAULT NULL COMMENT '用户自定义设备名称',
|
|
229
230
|
device_type ENUM('mobile', 'desktop', 'tablet', 'unknown') NOT NULL DEFAULT 'unknown',
|
|
@@ -243,7 +244,7 @@ class StandaloneAuthManager:
|
|
|
243
244
|
trust_level ENUM('trusted', 'normal', 'suspicious') NOT NULL DEFAULT 'normal' COMMENT '设备信任级别',
|
|
244
245
|
|
|
245
246
|
UNIQUE KEY uk_device_sessions_device_id (device_id),
|
|
246
|
-
UNIQUE KEY
|
|
247
|
+
UNIQUE KEY uk_device_sessions_user_fingerprint_domain_version (user_id, device_fingerprint, login_domain, session_version),
|
|
247
248
|
KEY idx_device_sessions_user_id (user_id),
|
|
248
249
|
KEY idx_device_sessions_user_device (user_id, device_id),
|
|
249
250
|
KEY idx_device_sessions_last_activity (last_activity),
|
|
@@ -647,80 +648,63 @@ class StandaloneAuthManager:
|
|
|
647
648
|
try:
|
|
648
649
|
current_time_utc = datetime.now(timezone.utc)
|
|
649
650
|
|
|
650
|
-
#
|
|
651
|
+
# 软删除:将该用户在该域名下的相同设备指纹的所有活跃会话标记为非活跃
|
|
651
652
|
cursor.execute('''
|
|
652
|
-
|
|
653
|
+
UPDATE device_sessions
|
|
654
|
+
SET is_active = 0
|
|
653
655
|
WHERE user_id = %s AND device_fingerprint = %s AND login_domain = %s AND is_active = 1
|
|
654
656
|
''', (user_id, device_fingerprint, login_domain))
|
|
655
657
|
|
|
656
|
-
|
|
658
|
+
# 获取下一个版本号
|
|
659
|
+
cursor.execute('''
|
|
660
|
+
SELECT COALESCE(MAX(session_version), 0) + 1 as next_version
|
|
661
|
+
FROM device_sessions
|
|
662
|
+
WHERE user_id = %s AND device_fingerprint = %s AND login_domain = %s
|
|
663
|
+
''', (user_id, device_fingerprint, login_domain))
|
|
657
664
|
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
''', (ip_address, user_agent, current_time_utc,
|
|
671
|
-
full_device_info.get('device_name', 'Unknown Device'),
|
|
672
|
-
full_device_info.get('device_type', 'unknown'),
|
|
673
|
-
full_device_info.get('platform'),
|
|
674
|
-
full_device_info.get('browser'),
|
|
675
|
-
full_device_info.get('browser_version'),
|
|
676
|
-
full_device_info.get('screen_resolution'),
|
|
677
|
-
full_device_info.get('timezone_offset'),
|
|
678
|
-
full_device_info.get('language'),
|
|
679
|
-
full_device_info.get('hardware_concurrency'),
|
|
680
|
-
login_domain,
|
|
681
|
-
device_session_id))
|
|
682
|
-
else:
|
|
683
|
-
# 检查设备数量限制
|
|
684
|
-
cursor.execute('''
|
|
685
|
-
SELECT COUNT(*) as active_count FROM device_sessions
|
|
686
|
-
WHERE user_id = %s AND is_active = 1
|
|
687
|
-
''', (user_id,))
|
|
688
|
-
|
|
689
|
-
active_count = cursor.fetchone()['active_count']
|
|
690
|
-
|
|
691
|
-
if active_count >= self.auth_config['max_concurrent_devices']:
|
|
692
|
-
# 踢出最旧的设备
|
|
693
|
-
cursor.execute('''
|
|
694
|
-
SELECT id FROM device_sessions
|
|
695
|
-
WHERE user_id = %s AND is_active = 1
|
|
696
|
-
ORDER BY last_activity ASC
|
|
697
|
-
LIMIT %s
|
|
698
|
-
''', (user_id, active_count - self.auth_config['max_concurrent_devices'] + 1))
|
|
699
|
-
|
|
700
|
-
old_sessions = cursor.fetchall()
|
|
701
|
-
for old_session in old_sessions:
|
|
702
|
-
self._revoke_device_session(cursor, old_session['id'], 'device_limit')
|
|
703
|
-
|
|
704
|
-
# 创建新设备会话
|
|
665
|
+
next_version = cursor.fetchone()['next_version']
|
|
666
|
+
|
|
667
|
+
# 检查设备数量限制
|
|
668
|
+
cursor.execute('''
|
|
669
|
+
SELECT COUNT(*) as active_count FROM device_sessions
|
|
670
|
+
WHERE user_id = %s AND is_active = 1
|
|
671
|
+
''', (user_id,))
|
|
672
|
+
|
|
673
|
+
active_count = cursor.fetchone()['active_count']
|
|
674
|
+
|
|
675
|
+
if active_count >= self.auth_config['max_concurrent_devices']:
|
|
676
|
+
# 踢出最旧的设备
|
|
705
677
|
cursor.execute('''
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
''', (user_id, device_id, device_fingerprint, login_domain,
|
|
712
|
-
full_device_info.get('device_name', 'Unknown Device'),
|
|
713
|
-
full_device_info.get('device_type', 'unknown'),
|
|
714
|
-
full_device_info.get('platform'),
|
|
715
|
-
full_device_info.get('browser'),
|
|
716
|
-
full_device_info.get('browser_version'),
|
|
717
|
-
full_device_info.get('screen_resolution'),
|
|
718
|
-
full_device_info.get('timezone_offset'),
|
|
719
|
-
full_device_info.get('language'),
|
|
720
|
-
full_device_info.get('hardware_concurrency'),
|
|
721
|
-
ip_address, ip_address, user_agent, current_time_utc))
|
|
678
|
+
SELECT id FROM device_sessions
|
|
679
|
+
WHERE user_id = %s AND is_active = 1
|
|
680
|
+
ORDER BY last_activity ASC
|
|
681
|
+
LIMIT %s
|
|
682
|
+
''', (user_id, active_count - self.auth_config['max_concurrent_devices'] + 1))
|
|
722
683
|
|
|
723
|
-
|
|
684
|
+
old_sessions = cursor.fetchall()
|
|
685
|
+
for old_session in old_sessions:
|
|
686
|
+
self._revoke_device_session(cursor, old_session['id'], 'device_limit')
|
|
687
|
+
|
|
688
|
+
# 创建新设备会话(带版本号)
|
|
689
|
+
cursor.execute('''
|
|
690
|
+
INSERT INTO device_sessions (
|
|
691
|
+
user_id, device_id, device_fingerprint, login_domain, session_version, device_name, device_type,
|
|
692
|
+
platform, browser, browser_version, screen_resolution, timezone_offset,
|
|
693
|
+
language, hardware_concurrency, current_ip, first_ip, user_agent, last_activity
|
|
694
|
+
) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
|
|
695
|
+
''', (user_id, device_id, device_fingerprint, login_domain, next_version,
|
|
696
|
+
full_device_info.get('device_name', 'Unknown Device'),
|
|
697
|
+
full_device_info.get('device_type', 'unknown'),
|
|
698
|
+
full_device_info.get('platform'),
|
|
699
|
+
full_device_info.get('browser'),
|
|
700
|
+
full_device_info.get('browser_version'),
|
|
701
|
+
full_device_info.get('screen_resolution'),
|
|
702
|
+
full_device_info.get('timezone_offset'),
|
|
703
|
+
full_device_info.get('language'),
|
|
704
|
+
full_device_info.get('hardware_concurrency'),
|
|
705
|
+
ip_address, ip_address, user_agent, current_time_utc))
|
|
706
|
+
|
|
707
|
+
device_session_id = cursor.lastrowid
|
|
724
708
|
|
|
725
709
|
return device_session_id, device_id, full_device_info.get('device_name', 'Unknown Device')
|
|
726
710
|
|
|
@@ -1413,6 +1397,7 @@ class StandaloneAuthManager:
|
|
|
1413
1397
|
|
|
1414
1398
|
devices_list.append({
|
|
1415
1399
|
'device_id': device['device_id'],
|
|
1400
|
+
'device_fingerprint': device['device_fingerprint'], # 添加设备指纹
|
|
1416
1401
|
'device_name': display_name,
|
|
1417
1402
|
'custom_name': device['custom_name'],
|
|
1418
1403
|
'login_domain': device['login_domain'],
|
|
@@ -1679,6 +1664,82 @@ class StandaloneAuthManager:
|
|
|
1679
1664
|
cursor.close()
|
|
1680
1665
|
conn.close()
|
|
1681
1666
|
|
|
1667
|
+
def get_device_session_history(self, user_id, device_fingerprint, login_domain, limit=10):
|
|
1668
|
+
"""获取设备会话历史记录"""
|
|
1669
|
+
conn = self.pool.connection()
|
|
1670
|
+
cursor = conn.cursor()
|
|
1671
|
+
|
|
1672
|
+
try:
|
|
1673
|
+
cursor.execute('''
|
|
1674
|
+
SELECT device_id, session_version, device_name, current_ip, first_ip,
|
|
1675
|
+
last_activity, created_at, is_active, trust_level
|
|
1676
|
+
FROM device_sessions
|
|
1677
|
+
WHERE user_id = %s AND device_fingerprint = %s AND login_domain = %s
|
|
1678
|
+
ORDER BY session_version DESC
|
|
1679
|
+
LIMIT %s
|
|
1680
|
+
''', (user_id, device_fingerprint, login_domain, limit))
|
|
1681
|
+
|
|
1682
|
+
sessions = cursor.fetchall()
|
|
1683
|
+
|
|
1684
|
+
return [
|
|
1685
|
+
{
|
|
1686
|
+
'device_id': session['device_id'],
|
|
1687
|
+
'session_version': session['session_version'],
|
|
1688
|
+
'device_name': session['device_name'],
|
|
1689
|
+
'current_ip': session['current_ip'],
|
|
1690
|
+
'first_ip': session['first_ip'],
|
|
1691
|
+
'last_activity': session['last_activity'].isoformat() if session['last_activity'] else None,
|
|
1692
|
+
'created_at': session['created_at'].isoformat() if session['created_at'] else None,
|
|
1693
|
+
'is_active': session['is_active'],
|
|
1694
|
+
'trust_level': session['trust_level']
|
|
1695
|
+
}
|
|
1696
|
+
for session in sessions
|
|
1697
|
+
]
|
|
1698
|
+
|
|
1699
|
+
finally:
|
|
1700
|
+
cursor.close()
|
|
1701
|
+
conn.close()
|
|
1702
|
+
|
|
1703
|
+
def cleanup_old_device_sessions(self, user_id=None, days_threshold=90):
|
|
1704
|
+
"""清理旧的非活跃设备会话记录"""
|
|
1705
|
+
conn = self.pool.connection()
|
|
1706
|
+
cursor = conn.cursor()
|
|
1707
|
+
|
|
1708
|
+
try:
|
|
1709
|
+
current_time_utc = datetime.now(timezone.utc)
|
|
1710
|
+
threshold_time = current_time_utc - timedelta(days=days_threshold)
|
|
1711
|
+
|
|
1712
|
+
if user_id:
|
|
1713
|
+
# 清理特定用户的旧记录
|
|
1714
|
+
cursor.execute('''
|
|
1715
|
+
DELETE FROM device_sessions
|
|
1716
|
+
WHERE user_id = %s AND is_active = 0 AND last_activity < %s
|
|
1717
|
+
''', (user_id, threshold_time))
|
|
1718
|
+
else:
|
|
1719
|
+
# 清理所有用户的旧记录
|
|
1720
|
+
cursor.execute('''
|
|
1721
|
+
DELETE FROM device_sessions
|
|
1722
|
+
WHERE is_active = 0 AND last_activity < %s
|
|
1723
|
+
''', (threshold_time,))
|
|
1724
|
+
|
|
1725
|
+
cleaned_count = cursor.rowcount
|
|
1726
|
+
|
|
1727
|
+
return {
|
|
1728
|
+
'success': True,
|
|
1729
|
+
'cleaned_count': cleaned_count,
|
|
1730
|
+
'message': f'成功清理 {cleaned_count} 条旧设备会话记录'
|
|
1731
|
+
}
|
|
1732
|
+
|
|
1733
|
+
except Exception as e:
|
|
1734
|
+
return {
|
|
1735
|
+
'success': False,
|
|
1736
|
+
'cleaned_count': 0,
|
|
1737
|
+
'message': f'清理旧设备会话记录失败: {str(e)}'
|
|
1738
|
+
}
|
|
1739
|
+
finally:
|
|
1740
|
+
cursor.close()
|
|
1741
|
+
conn.close()
|
|
1742
|
+
|
|
1682
1743
|
|
|
1683
1744
|
# Flask集成装饰器
|
|
1684
1745
|
def require_auth(auth_manager):
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
mdbq/__init__.py,sha256=Il5Q9ATdX8yXqVxtP_nYqUhExzxPC_qk_WXQ_4h0exg,16
|
|
2
|
-
mdbq/__version__.py,sha256=
|
|
2
|
+
mdbq/__version__.py,sha256=3pgeM4FRzKH3kfbXDpPMNe-aq2Qy0ytSAFcNGAwqiMk,18
|
|
3
3
|
mdbq/auth/__init__.py,sha256=pnPMAt63sh1B6kEvmutUuro46zVf2v2YDAG7q-jV_To,24
|
|
4
|
-
mdbq/auth/auth_backend.py,sha256=
|
|
4
|
+
mdbq/auth/auth_backend.py,sha256=cUL9oWzzFSuJgvqeo4ognl8NiMvaIWNgJMaG7ZCLvnA,79391
|
|
5
5
|
mdbq/auth/rate_limiter.py,sha256=e7K8pMQlZ1vm1N-c0HBH8tbAwzcmXSRiAl81JNZ369g,26192
|
|
6
6
|
mdbq/js/__init__.py,sha256=hpMi3_ZKwIWkzc0LnKL-SY9AS-7PYFHq0izYTgEvxjc,30
|
|
7
7
|
mdbq/js/jc.py,sha256=FOc6HOOTJwnoZLZmgmaE1SQo9rUnVhXmefhKMD2MlDA,13229
|
|
@@ -33,7 +33,7 @@ mdbq/route/routes.py,sha256=QVGfTvDgu0CpcKCvk1ra74H8uojgqTLUav1fnVAqLEA,29433
|
|
|
33
33
|
mdbq/selenium/__init__.py,sha256=AKzeEceqZyvqn2dEDoJSzDQnbuENkJSHAlbHAD0u0ZI,10
|
|
34
34
|
mdbq/selenium/get_driver.py,sha256=1NTlVUE6QsyjTrVVVqTO2LOnYf578ccFWlWnvIXGtic,20903
|
|
35
35
|
mdbq/spider/__init__.py,sha256=RBMFXGy_jd1HXZhngB2T2XTvJqki8P_Fr-pBcwijnew,18
|
|
36
|
-
mdbq-4.0.
|
|
37
|
-
mdbq-4.0.
|
|
38
|
-
mdbq-4.0.
|
|
39
|
-
mdbq-4.0.
|
|
36
|
+
mdbq-4.0.99.dist-info/METADATA,sha256=H_Sa_C5vsfH6M3ynHCuTXb5XpJ-yXXssIweqINggiqU,364
|
|
37
|
+
mdbq-4.0.99.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
38
|
+
mdbq-4.0.99.dist-info/top_level.txt,sha256=2FQ-uLnCSB-OwFiWntzmwosW3X2Xqsg0ewh1axsaylA,5
|
|
39
|
+
mdbq-4.0.99.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|