170 lines
5.1 KiB
Python
170 lines
5.1 KiB
Python
"""
|
|
防封模块 — 账号生命周期管理
|
|
管理账号从注册到成熟的各阶段操作限制。
|
|
|
|
阶段定义:
|
|
- 新号期 (0-7天):严格限制,以养号为主
|
|
- 成长期 (8-30天):逐步放宽,日常操作
|
|
- 成熟期 (30天+):正常使用限制
|
|
"""
|
|
|
|
import logging
|
|
import time
|
|
from enum import Enum
|
|
from typing import Dict, Optional
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
_redis = None
|
|
_redis_last_check: float = 0.0
|
|
_REDIS_CHECK_INTERVAL = 60.0
|
|
|
|
|
|
async def _get_redis():
|
|
global _redis, _redis_last_check
|
|
now = time.time()
|
|
if _redis is not None:
|
|
if now - _redis_last_check > _REDIS_CHECK_INTERVAL:
|
|
try:
|
|
await _redis.ping()
|
|
_redis_last_check = now
|
|
except Exception:
|
|
logger.warning("Redis 连接失效,重置")
|
|
_redis = None
|
|
if _redis is not None:
|
|
return _redis
|
|
try:
|
|
import redis.asyncio as aioredis
|
|
from config import settings
|
|
_redis = aioredis.from_url(settings.REDIS_URL, decode_responses=True)
|
|
await _redis.ping()
|
|
_redis_last_check = now
|
|
return _redis
|
|
except Exception:
|
|
_redis = None
|
|
return None
|
|
|
|
|
|
_memory_accounts: Dict[str, dict] = {}
|
|
|
|
|
|
class AccountPhase(str, Enum):
|
|
NEW = "new" # 0-7天
|
|
GROWING = "growing" # 8-30天
|
|
MATURE = "mature" # 30天+
|
|
|
|
|
|
PHASE_RULES = {
|
|
AccountPhase.NEW: {
|
|
"max_daily_add_friend": 10,
|
|
"max_daily_send_message": 20,
|
|
"max_daily_post_moments": 2,
|
|
"max_daily_group_send": 5,
|
|
"required_warm_up": True,
|
|
"description": "新号期:严格限制,优先养号",
|
|
},
|
|
AccountPhase.GROWING: {
|
|
"max_daily_add_friend": 30,
|
|
"max_daily_send_message": 80,
|
|
"max_daily_post_moments": 4,
|
|
"max_daily_group_send": 30,
|
|
"required_warm_up": False,
|
|
"description": "成长期:逐步放宽",
|
|
},
|
|
AccountPhase.MATURE: {
|
|
"max_daily_add_friend": 50,
|
|
"max_daily_send_message": 200,
|
|
"max_daily_post_moments": 5,
|
|
"max_daily_group_send": 50,
|
|
"required_warm_up": False,
|
|
"description": "成熟期:正常操作",
|
|
},
|
|
}
|
|
|
|
|
|
class AccountLifecycleManager:
|
|
"""账号生命周期管理器(单例)"""
|
|
|
|
async def register_account(
|
|
self, device_id: str, platform: str, register_timestamp: Optional[float] = None
|
|
):
|
|
"""
|
|
注册/绑定一个账号。
|
|
device_id+platform 唯一标识。
|
|
register_timestamp: 账号注册时间戳,不传则用当前时间。
|
|
"""
|
|
ts = register_timestamp or time.time()
|
|
key = f"acct:{device_id}:{platform}"
|
|
data = {"register_ts": ts, "platform": platform, "device_id": device_id}
|
|
r = await _get_redis()
|
|
if r:
|
|
try:
|
|
import json
|
|
await r.set(key, json.dumps(data), ex=86400 * 365)
|
|
return
|
|
except Exception:
|
|
pass
|
|
_memory_accounts[key] = data
|
|
|
|
async def get_phase(self, device_id: str, platform: str) -> AccountPhase:
|
|
key = f"acct:{device_id}:{platform}"
|
|
data = None
|
|
r = await _get_redis()
|
|
if r:
|
|
try:
|
|
import json
|
|
raw = await r.get(key)
|
|
if raw:
|
|
data = json.loads(raw)
|
|
except Exception:
|
|
pass
|
|
if not data:
|
|
data = _memory_accounts.get(key)
|
|
if not data:
|
|
return AccountPhase.NEW
|
|
|
|
age_days = (time.time() - data.get("register_ts", 0)) / 86400
|
|
if age_days <= 7:
|
|
return AccountPhase.NEW
|
|
elif age_days <= 30:
|
|
return AccountPhase.GROWING
|
|
return AccountPhase.MATURE
|
|
|
|
async def is_new_account(self, device_id: str, platform: str) -> bool:
|
|
phase = await self.get_phase(device_id, platform)
|
|
return phase == AccountPhase.NEW
|
|
|
|
async def get_rules(self, device_id: str, platform: str) -> dict:
|
|
phase = await self.get_phase(device_id, platform)
|
|
return {
|
|
"phase": phase.value,
|
|
**PHASE_RULES[phase],
|
|
}
|
|
|
|
async def check_allowed(
|
|
self, device_id: str, platform: str, action: str
|
|
) -> Dict[str, any]:
|
|
"""
|
|
检查某操作在当前生命周期是否允许(仅做检查,不消耗配额)。
|
|
返回 {"allowed": bool, "phase": str, "reason": str}
|
|
"""
|
|
phase = await self.get_phase(device_id, platform)
|
|
rules = PHASE_RULES[phase]
|
|
|
|
if phase == AccountPhase.NEW and rules.get("required_warm_up"):
|
|
high_risk_actions = {
|
|
"batch_add_friend", "batch_send", "send_red_packet",
|
|
"transfer", "open_mini_program",
|
|
}
|
|
if action in high_risk_actions:
|
|
return {
|
|
"allowed": False,
|
|
"phase": phase.value,
|
|
"reason": f"新号期禁止高风险操作: {action}",
|
|
}
|
|
|
|
return {"allowed": True, "phase": phase.value, "reason": ""}
|
|
|
|
|
|
account_lifecycle = AccountLifecycleManager()
|