mdbq 4.0.95__py3-none-any.whl → 4.0.96__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 +168 -25
- {mdbq-4.0.95.dist-info → mdbq-4.0.96.dist-info}/METADATA +1 -1
- {mdbq-4.0.95.dist-info → mdbq-4.0.96.dist-info}/RECORD +6 -6
- {mdbq-4.0.95.dist-info → mdbq-4.0.96.dist-info}/WHEEL +0 -0
- {mdbq-4.0.95.dist-info → mdbq-4.0.96.dist-info}/top_level.txt +0 -0
mdbq/__version__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
VERSION = '4.0.
|
|
1
|
+
VERSION = '4.0.96'
|
mdbq/auth/auth_backend.py
CHANGED
|
@@ -221,24 +221,34 @@ class StandaloneAuthManager:
|
|
|
221
221
|
CREATE TABLE IF NOT EXISTS device_sessions (
|
|
222
222
|
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
|
223
223
|
user_id BIGINT UNSIGNED NOT NULL,
|
|
224
|
-
device_id VARCHAR(
|
|
225
|
-
device_fingerprint VARCHAR(
|
|
226
|
-
device_name VARCHAR(
|
|
224
|
+
device_id VARCHAR(255) CHARACTER SET ascii NOT NULL,
|
|
225
|
+
device_fingerprint VARCHAR(255) CHARACTER SET ascii NOT NULL,
|
|
226
|
+
device_name VARCHAR(255) NOT NULL DEFAULT 'Unknown Device',
|
|
227
|
+
custom_name VARCHAR(255) DEFAULT NULL COMMENT '用户自定义设备名称',
|
|
227
228
|
device_type ENUM('mobile', 'desktop', 'tablet', 'unknown') NOT NULL DEFAULT 'unknown',
|
|
228
229
|
platform VARCHAR(50) DEFAULT NULL,
|
|
229
230
|
browser VARCHAR(50) DEFAULT NULL,
|
|
230
|
-
|
|
231
|
+
browser_version VARCHAR(40) DEFAULT NULL,
|
|
232
|
+
screen_resolution VARCHAR(40) DEFAULT NULL COMMENT '屏幕分辨率',
|
|
233
|
+
timezone_offset INT DEFAULT NULL COMMENT '时区偏移(分钟)',
|
|
234
|
+
language VARCHAR(20) DEFAULT NULL COMMENT '浏览器语言',
|
|
235
|
+
hardware_concurrency TINYINT UNSIGNED DEFAULT NULL COMMENT 'CPU核心数',
|
|
236
|
+
current_ip VARCHAR(45) NOT NULL COMMENT '当前IP地址',
|
|
237
|
+
first_ip VARCHAR(45) NOT NULL COMMENT '首次登录IP',
|
|
231
238
|
user_agent TEXT NOT NULL,
|
|
232
239
|
last_activity TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
|
|
233
240
|
created_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
|
234
241
|
is_active TINYINT(1) NOT NULL DEFAULT 1,
|
|
242
|
+
trust_level ENUM('trusted', 'normal', 'suspicious') NOT NULL DEFAULT 'normal' COMMENT '设备信任级别',
|
|
235
243
|
|
|
236
244
|
UNIQUE KEY uk_device_sessions_device_id (device_id),
|
|
245
|
+
UNIQUE KEY uk_device_sessions_user_fingerprint (user_id, device_fingerprint),
|
|
237
246
|
KEY idx_device_sessions_user_id (user_id),
|
|
238
247
|
KEY idx_device_sessions_user_device (user_id, device_id),
|
|
239
248
|
KEY idx_device_sessions_last_activity (last_activity),
|
|
240
249
|
KEY idx_device_sessions_is_active (is_active),
|
|
241
250
|
KEY idx_device_sessions_fingerprint (device_fingerprint),
|
|
251
|
+
KEY idx_device_sessions_trust_level (trust_level),
|
|
242
252
|
|
|
243
253
|
CONSTRAINT fk_device_sessions_user_id
|
|
244
254
|
FOREIGN KEY (user_id)
|
|
@@ -611,10 +621,20 @@ class StandaloneAuthManager:
|
|
|
611
621
|
except jwt.InvalidTokenError:
|
|
612
622
|
return None
|
|
613
623
|
|
|
614
|
-
def create_or_update_device_session(self, user_id, ip_address, user_agent):
|
|
624
|
+
def create_or_update_device_session(self, user_id, ip_address, user_agent, device_info=None):
|
|
615
625
|
"""创建或更新设备会话"""
|
|
616
|
-
|
|
617
|
-
|
|
626
|
+
# 解析用户代理获取基本信息
|
|
627
|
+
parsed_ua = self._parse_user_agent(user_agent)
|
|
628
|
+
|
|
629
|
+
# 合并设备信息
|
|
630
|
+
full_device_info = {
|
|
631
|
+
'user_agent': user_agent,
|
|
632
|
+
'platform': parsed_ua.get('platform'),
|
|
633
|
+
**parsed_ua,
|
|
634
|
+
**(device_info or {})
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
device_fingerprint = self._generate_device_fingerprint(full_device_info)
|
|
618
638
|
device_id = secrets.token_urlsafe(32)
|
|
619
639
|
|
|
620
640
|
conn = self.pool.connection()
|
|
@@ -638,12 +658,22 @@ class StandaloneAuthManager:
|
|
|
638
658
|
|
|
639
659
|
cursor.execute('''
|
|
640
660
|
UPDATE device_sessions
|
|
641
|
-
SET
|
|
642
|
-
device_name = %s, device_type = %s, platform = %s, browser = %s
|
|
661
|
+
SET current_ip = %s, user_agent = %s, last_activity = %s,
|
|
662
|
+
device_name = %s, device_type = %s, platform = %s, browser = %s,
|
|
663
|
+
browser_version = %s, screen_resolution = %s, timezone_offset = %s,
|
|
664
|
+
language = %s, hardware_concurrency = %s
|
|
643
665
|
WHERE id = %s
|
|
644
666
|
''', (ip_address, user_agent, current_time_utc,
|
|
645
|
-
|
|
646
|
-
|
|
667
|
+
full_device_info.get('device_name', 'Unknown Device'),
|
|
668
|
+
full_device_info.get('device_type', 'unknown'),
|
|
669
|
+
full_device_info.get('platform'),
|
|
670
|
+
full_device_info.get('browser'),
|
|
671
|
+
full_device_info.get('browser_version'),
|
|
672
|
+
full_device_info.get('screen_resolution'),
|
|
673
|
+
full_device_info.get('timezone_offset'),
|
|
674
|
+
full_device_info.get('language'),
|
|
675
|
+
full_device_info.get('hardware_concurrency'),
|
|
676
|
+
device_session_id))
|
|
647
677
|
else:
|
|
648
678
|
# 检查设备数量限制
|
|
649
679
|
cursor.execute('''
|
|
@@ -670,15 +700,24 @@ class StandaloneAuthManager:
|
|
|
670
700
|
cursor.execute('''
|
|
671
701
|
INSERT INTO device_sessions (
|
|
672
702
|
user_id, device_id, device_fingerprint, device_name, device_type,
|
|
673
|
-
platform, browser,
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
703
|
+
platform, browser, browser_version, screen_resolution, timezone_offset,
|
|
704
|
+
language, hardware_concurrency, current_ip, first_ip, user_agent, last_activity
|
|
705
|
+
) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
|
|
706
|
+
''', (user_id, device_id, device_fingerprint,
|
|
707
|
+
full_device_info.get('device_name', 'Unknown Device'),
|
|
708
|
+
full_device_info.get('device_type', 'unknown'),
|
|
709
|
+
full_device_info.get('platform'),
|
|
710
|
+
full_device_info.get('browser'),
|
|
711
|
+
full_device_info.get('browser_version'),
|
|
712
|
+
full_device_info.get('screen_resolution'),
|
|
713
|
+
full_device_info.get('timezone_offset'),
|
|
714
|
+
full_device_info.get('language'),
|
|
715
|
+
full_device_info.get('hardware_concurrency'),
|
|
716
|
+
ip_address, ip_address, user_agent, current_time_utc))
|
|
678
717
|
|
|
679
718
|
device_session_id = cursor.lastrowid
|
|
680
719
|
|
|
681
|
-
return device_session_id, device_id,
|
|
720
|
+
return device_session_id, device_id, full_device_info.get('device_name', 'Unknown Device')
|
|
682
721
|
|
|
683
722
|
finally:
|
|
684
723
|
cursor.close()
|
|
@@ -1214,10 +1253,34 @@ class StandaloneAuthManager:
|
|
|
1214
1253
|
WHERE id = %s
|
|
1215
1254
|
''', (device_session_id,))
|
|
1216
1255
|
|
|
1217
|
-
def _generate_device_fingerprint(self,
|
|
1218
|
-
"""
|
|
1219
|
-
|
|
1220
|
-
|
|
1256
|
+
def _generate_device_fingerprint(self, device_info):
|
|
1257
|
+
"""
|
|
1258
|
+
生成稳定的设备指纹
|
|
1259
|
+
|
|
1260
|
+
Args:
|
|
1261
|
+
device_info (dict): 设备信息
|
|
1262
|
+
- user_agent: 用户代理
|
|
1263
|
+
- screen_resolution: 屏幕分辨率
|
|
1264
|
+
- timezone_offset: 时区偏移
|
|
1265
|
+
- language: 浏览器语言
|
|
1266
|
+
- hardware_concurrency: CPU核心数
|
|
1267
|
+
- platform: 平台信息
|
|
1268
|
+
"""
|
|
1269
|
+
# 提取稳定的设备特征
|
|
1270
|
+
stable_features = [
|
|
1271
|
+
device_info.get('user_agent', ''),
|
|
1272
|
+
device_info.get('screen_resolution', ''),
|
|
1273
|
+
str(device_info.get('timezone_offset', 0)),
|
|
1274
|
+
device_info.get('language', ''),
|
|
1275
|
+
str(device_info.get('hardware_concurrency', 0)),
|
|
1276
|
+
device_info.get('platform', ''),
|
|
1277
|
+
]
|
|
1278
|
+
|
|
1279
|
+
# 过滤空值并连接
|
|
1280
|
+
fingerprint_data = ':'.join(filter(None, stable_features))
|
|
1281
|
+
|
|
1282
|
+
# 生成SHA256哈希
|
|
1283
|
+
return hashlib.sha256(fingerprint_data.encode('utf-8')).hexdigest()[:32]
|
|
1221
1284
|
|
|
1222
1285
|
def _parse_user_agent(self, user_agent):
|
|
1223
1286
|
"""解析User-Agent获取设备信息"""
|
|
@@ -1320,8 +1383,10 @@ class StandaloneAuthManager:
|
|
|
1320
1383
|
|
|
1321
1384
|
try:
|
|
1322
1385
|
cursor.execute('''
|
|
1323
|
-
SELECT device_id, device_fingerprint, device_name,
|
|
1324
|
-
|
|
1386
|
+
SELECT device_id, device_fingerprint, device_name, custom_name, device_type,
|
|
1387
|
+
platform, browser, browser_version, screen_resolution, timezone_offset,
|
|
1388
|
+
language, hardware_concurrency, current_ip, first_ip,
|
|
1389
|
+
last_activity, created_at, is_active, trust_level
|
|
1325
1390
|
FROM device_sessions
|
|
1326
1391
|
WHERE user_id = %s AND is_active = 1
|
|
1327
1392
|
ORDER BY last_activity DESC
|
|
@@ -1336,13 +1401,24 @@ class StandaloneAuthManager:
|
|
|
1336
1401
|
if is_current:
|
|
1337
1402
|
current_device_id = device['device_id']
|
|
1338
1403
|
|
|
1404
|
+
# 生成显示名称(优先使用自定义名称)
|
|
1405
|
+
display_name = device['custom_name'] or device['device_name']
|
|
1406
|
+
|
|
1339
1407
|
devices_list.append({
|
|
1340
1408
|
'device_id': device['device_id'],
|
|
1341
|
-
'device_name':
|
|
1409
|
+
'device_name': display_name,
|
|
1410
|
+
'custom_name': device['custom_name'],
|
|
1342
1411
|
'device_type': device['device_type'],
|
|
1343
1412
|
'platform': device['platform'],
|
|
1344
1413
|
'browser': device['browser'],
|
|
1345
|
-
'
|
|
1414
|
+
'browser_version': device['browser_version'],
|
|
1415
|
+
'screen_resolution': device['screen_resolution'],
|
|
1416
|
+
'timezone_offset': device['timezone_offset'],
|
|
1417
|
+
'language': device['language'],
|
|
1418
|
+
'hardware_concurrency': device['hardware_concurrency'],
|
|
1419
|
+
'current_ip': device['current_ip'],
|
|
1420
|
+
'first_ip': device['first_ip'],
|
|
1421
|
+
'trust_level': device['trust_level'],
|
|
1346
1422
|
'last_activity': device['last_activity'].isoformat() if device['last_activity'] else None,
|
|
1347
1423
|
'created_at': device['created_at'].isoformat() if device['created_at'] else None,
|
|
1348
1424
|
'is_current': is_current
|
|
@@ -1528,6 +1604,73 @@ class StandaloneAuthManager:
|
|
|
1528
1604
|
cursor.close()
|
|
1529
1605
|
conn.close()
|
|
1530
1606
|
|
|
1607
|
+
def rename_device(self, user_id, device_id, custom_name):
|
|
1608
|
+
"""重命名设备"""
|
|
1609
|
+
conn = self.pool.connection()
|
|
1610
|
+
cursor = conn.cursor()
|
|
1611
|
+
|
|
1612
|
+
try:
|
|
1613
|
+
# 验证设备是否属于该用户
|
|
1614
|
+
cursor.execute('''
|
|
1615
|
+
SELECT id FROM device_sessions
|
|
1616
|
+
WHERE user_id = %s AND device_id = %s AND is_active = 1
|
|
1617
|
+
''', (user_id, device_id))
|
|
1618
|
+
|
|
1619
|
+
device = cursor.fetchone()
|
|
1620
|
+
|
|
1621
|
+
if not device:
|
|
1622
|
+
return {'success': False, 'message': '设备不存在或已失效'}
|
|
1623
|
+
|
|
1624
|
+
# 更新自定义名称
|
|
1625
|
+
cursor.execute('''
|
|
1626
|
+
UPDATE device_sessions
|
|
1627
|
+
SET custom_name = %s
|
|
1628
|
+
WHERE id = %s
|
|
1629
|
+
''', (custom_name.strip() if custom_name else None, device['id']))
|
|
1630
|
+
|
|
1631
|
+
return {'success': True, 'message': '设备重命名成功'}
|
|
1632
|
+
|
|
1633
|
+
except Exception as e:
|
|
1634
|
+
return {'success': False, 'message': f'设备重命名失败: {str(e)}'}
|
|
1635
|
+
finally:
|
|
1636
|
+
cursor.close()
|
|
1637
|
+
conn.close()
|
|
1638
|
+
|
|
1639
|
+
def set_device_trust_level(self, user_id, device_id, trust_level):
|
|
1640
|
+
"""设置设备信任级别"""
|
|
1641
|
+
if trust_level not in ['trusted', 'normal', 'suspicious']:
|
|
1642
|
+
return {'success': False, 'message': '无效的信任级别'}
|
|
1643
|
+
|
|
1644
|
+
conn = self.pool.connection()
|
|
1645
|
+
cursor = conn.cursor()
|
|
1646
|
+
|
|
1647
|
+
try:
|
|
1648
|
+
# 验证设备是否属于该用户
|
|
1649
|
+
cursor.execute('''
|
|
1650
|
+
SELECT id FROM device_sessions
|
|
1651
|
+
WHERE user_id = %s AND device_id = %s AND is_active = 1
|
|
1652
|
+
''', (user_id, device_id))
|
|
1653
|
+
|
|
1654
|
+
device = cursor.fetchone()
|
|
1655
|
+
|
|
1656
|
+
if not device:
|
|
1657
|
+
return {'success': False, 'message': '设备不存在或已失效'}
|
|
1658
|
+
|
|
1659
|
+
# 更新信任级别
|
|
1660
|
+
cursor.execute('''
|
|
1661
|
+
UPDATE device_sessions
|
|
1662
|
+
SET trust_level = %s
|
|
1663
|
+
WHERE id = %s
|
|
1664
|
+
''', (trust_level, device['id']))
|
|
1665
|
+
|
|
1666
|
+
return {'success': True, 'message': '设备信任级别更新成功'}
|
|
1667
|
+
|
|
1668
|
+
except Exception as e:
|
|
1669
|
+
return {'success': False, 'message': f'设备信任级别更新失败: {str(e)}'}
|
|
1670
|
+
finally:
|
|
1671
|
+
cursor.close()
|
|
1672
|
+
conn.close()
|
|
1673
|
+
|
|
1531
1674
|
|
|
1532
1675
|
# Flask集成装饰器
|
|
1533
1676
|
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=upYmcfx0UWjE76j0j97qCRGjDZGCKhrJ15LsMJQXb8E,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=R0qwedMEtJxbKcDUkl1ELl4lVTunFeiXsa_Xo3LHiQU,76455
|
|
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.96.dist-info/METADATA,sha256=XQFXH6TeJlSgpYJN7v8h_H0x0-qUJyh36kV-X4TzOBc,364
|
|
37
|
+
mdbq-4.0.96.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
38
|
+
mdbq-4.0.96.dist-info/top_level.txt,sha256=2FQ-uLnCSB-OwFiWntzmwosW3X2Xqsg0ewh1axsaylA,5
|
|
39
|
+
mdbq-4.0.96.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|