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 CHANGED
@@ -1 +1 @@
1
- VERSION = '4.0.97'
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 uk_device_sessions_user_fingerprint_domain (user_id, device_fingerprint, login_domain),
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
- SELECT id, device_id FROM device_sessions
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
- existing_session = cursor.fetchone()
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
- if existing_session:
659
- # 更新现有设备会话
660
- device_session_id = existing_session['id']
661
- device_id = existing_session['device_id']
662
-
663
- cursor.execute('''
664
- UPDATE device_sessions
665
- SET current_ip = %s, user_agent = %s, last_activity = %s,
666
- device_name = %s, device_type = %s, platform = %s, browser = %s,
667
- browser_version = %s, screen_resolution = %s, timezone_offset = %s,
668
- language = %s, hardware_concurrency = %s, login_domain = %s
669
- WHERE id = %s
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
- INSERT INTO device_sessions (
707
- user_id, device_id, device_fingerprint, login_domain, device_name, device_type,
708
- platform, browser, browser_version, screen_resolution, timezone_offset,
709
- language, hardware_concurrency, current_ip, first_ip, user_agent, last_activity
710
- ) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
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
- device_session_id = cursor.lastrowid
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,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mdbq
3
- Version: 4.0.97
3
+ Version: 4.0.99
4
4
  Home-page: https://pypi.org/project/mdbq
5
5
  Author: xigua,
6
6
  Author-email: 2587125111@qq.com
@@ -1,7 +1,7 @@
1
1
  mdbq/__init__.py,sha256=Il5Q9ATdX8yXqVxtP_nYqUhExzxPC_qk_WXQ_4h0exg,16
2
- mdbq/__version__.py,sha256=Wugnfrfi17MIisDJ2bCMK15l65XkooAlWs6nIab3BTw,18
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=FYsBS2fvowfdfDkl4i2k64JwgN5PWOwVqNGjRoqtCLE,77215
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.97.dist-info/METADATA,sha256=6P2tfV2sppjE7Y0niKXl1bqeYLa_bYfcLqhSMNr1ygg,364
37
- mdbq-4.0.97.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
38
- mdbq-4.0.97.dist-info/top_level.txt,sha256=2FQ-uLnCSB-OwFiWntzmwosW3X2Xqsg0ewh1axsaylA,5
39
- mdbq-4.0.97.dist-info/RECORD,,
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