同步操作将从 飞致云/SQLBot 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
import base64import hashlibimport inspectimport jsonimport loggingfrom datetime import datetime, timedelta, timezonefrom logging.handlers import RotatingFileHandlerfrom pathlib import Pathimport refrom urllib.parse import urlparsefrom fastapi import Requestfrom common.core.config import settingsfrom typing import Optionalimport jwtimport orjsonfrom jwt.exceptions import InvalidTokenErrorfrom common.core import securitydef generate_password_reset_token(email: str) -> str:delta = timedelta(hours=settings.EMAIL_RESET_TOKEN_EXPIRE_HOURS)now = datetime.now(timezone.utc)expires = now + deltaexp = expires.timestamp()encoded_jwt = jwt.encode({"exp": exp, "nbf": now, "sub": email},settings.SECRET_KEY,algorithm=security.ALGORITHM,)return encoded_jwtdef verify_password_reset_token(token: str) -> str | None:try:decoded_token = jwt.decode(token, settings.SECRET_KEY, algorithms=[security.ALGORITHM])return str(decoded_token["sub"])except InvalidTokenError:return Nonedef deepcopy_ignore_extra(src, dest):import copyfor attr in vars(src):if hasattr(dest, attr):src_value = getattr(src, attr)dest_value = copy.deepcopy(src_value) # deep copysetattr(dest, attr, dest_value)return destdef extract_nested_json(text):stack = []start_index = -1results = []for i, char in enumerate(text):if char in '{[':if not stack: # 记录起始位置start_index = istack.append(char)elif char in '}]':if stack and ((char == '}' and stack[-1] == '{') or (char == ']' and stack[-1] == '[')):stack.pop()if not stack: # 栈空时截取完整JSONjson_str = text[start_index:i + 1]try:orjson.loads(json_str) # 验证有效性results.append(json_str)except:passelse:stack = [] # 括号不匹配则重置if len(results) > 0 and results[0]:return results[0]return Nonedef string_to_numeric_hash(text: str, bits: Optional[int] = 64) -> int:hash_bytes = hashlib.sha256(text.encode()).digest()hash_num = int.from_bytes(hash_bytes, byteorder='big')max_bigint = 2**63 - 1return hash_num % max_bigintdef setup_logging():# 确保日志目录存在log_dir = Path(settings.LOG_DIR)log_dir.mkdir(parents=True, exist_ok=True)# 日志格式formatter = logging.Formatter(f'{settings.LOG_FORMAT}')# 控制台日志console_handler = logging.StreamHandler()console_handler.setLevel(settings.LOG_LEVEL)console_handler.setFormatter(formatter)# 文件日志处理器file_handlers = {'debug': logging.DEBUG,'info': logging.INFO,'warn': logging.WARNING,'error': logging.ERROR}# 主日志记录器root_logger = logging.getLogger()root_logger.setLevel(logging.DEBUG) # 设置最低级别# 添加控制台处理器root_logger.addHandler(console_handler)# 为每个级别创建文件处理器for level_name, level in file_handlers.items():file_path = log_dir / f"{level_name}.log"handler = RotatingFileHandler(file_path,maxBytes=10 * 1024 * 1024, # 10MBbackupCount=5,encoding='utf-8')handler.setLevel(level)handler.setFormatter(formatter)# 添加过滤器只处理特定级别日志if level_name == 'debug':handler.addFilter(lambda record: record.levelno == logging.DEBUG)elif level_name == 'info':handler.addFilter(lambda record: record.levelno == logging.INFO)elif level_name == 'warn':handler.addFilter(lambda record: record.levelno == logging.WARNING)elif level_name == 'error':handler.addFilter(lambda record: record.levelno >= logging.ERROR)root_logger.addHandler(handler)# SQL日志特殊处理if settings.LOG_LEVEL == "DEBUG" and settings.SQL_DEBUG:sql_logger = logging.getLogger('sqlalchemy.engine')sql_logger.setLevel(logging.DEBUG)sql_handler = RotatingFileHandler(log_dir / "sql.log",maxBytes=10 * 1024 * 1024,backupCount=2,encoding='utf-8')sql_handler.setFormatter(formatter)sql_logger.addHandler(sql_handler)setup_logging()class CallerLogger(logging.Logger):def __init__(self, logger: logging.Logger):self.logger = loggersuper().__init__(logger.name, logger.level)def _log(self, level, msg, args, exc_info=None, extra=None, stacklevel=3):if self.logger.isEnabledFor(level):self.logger._log(level, msg, args, exc_info=exc_info, extra=extra, stacklevel=stacklevel)class SQLBotLogUtil:@staticmethoddef _get_logger() -> logging.Logger:frame = inspect.currentframe()try:caller_frame = frame.f_back.f_backmodule_name = caller_frame.f_globals.get('__name__', '__main__')return CallerLogger(logging.getLogger(module_name))finally:del frame@staticmethoddef debug(msg: str, *args, **kwargs):logger = SQLBotLogUtil._get_logger()if logger.isEnabledFor(logging.DEBUG):logger._log(logging.DEBUG, msg, args, **kwargs)@staticmethoddef info(msg: str, *args, **kwargs):logger = SQLBotLogUtil._get_logger()if logger.isEnabledFor(logging.INFO):logger._log(logging.INFO, msg, args, **kwargs)@staticmethoddef warning(msg: str, *args, **kwargs):logger = SQLBotLogUtil._get_logger()if logger.isEnabledFor(logging.WARNING):logger._log(logging.WARNING, msg, args, **kwargs)@staticmethoddef error(msg: str, *args, exc_info: Optional[bool] = None, **kwargs):logger = SQLBotLogUtil._get_logger()if logger.isEnabledFor(logging.ERROR):logger._log(logging.ERROR,msg,args,exc_info=exc_info if exc_info is not None else True,**kwargs)@staticmethoddef exception(msg: str, *args, **kwargs):logger = SQLBotLogUtil._get_logger()if logger.isEnabledFor(logging.ERROR):logger._log(logging.ERROR, msg, args, exc_info=True, **kwargs)@staticmethoddef critical(msg: str, *args, **kwargs):logger = SQLBotLogUtil._get_logger()if logger.isEnabledFor(logging.CRITICAL):logger._log(logging.CRITICAL, msg, args, **kwargs)def prepare_for_orjson(data):if not data:return dataif isinstance(data, bytes):return base64.b64encode(data).decode('utf-8')elif isinstance(data, dict):return {k: prepare_for_orjson(v) for k, v in data.items()}elif isinstance(data, (list, tuple)):return [prepare_for_orjson(item) for item in data]else:return datadef prepare_model_arg(origin_arg: str):if not isinstance(origin_arg, str):return origin_argif not origin_arg.strip()[0] in {'{', '['}:return origin_argtry:return json.loads(origin_arg)except:return origin_argdef get_origin_from_referer(request: Request):referer = request.headers.get("referer")if not referer:return Nonetry:parsed = urlparse(referer)if not parsed.scheme or not parsed.hostname:return Noneport = parsed.portif port:if (parsed.scheme == "http" and port != 80) or \(parsed.scheme == "https" and port != 443):return f"{parsed.scheme}://{parsed.hostname}:{port}"return f"{parsed.scheme}://{parsed.hostname}"except Exception as e:SQLBotLogUtil.error(f"解析 Referer 出错: {e}")return refererdef origin_match_domain(origin: str, domain: str) -> bool:if not origin or not domain:return Falseorigin_normalized = origin.rstrip('/')for d in re.split(r'[,;]', domain):if d.strip().rstrip('/') == origin_normalized:return Truereturn Falsedef get_domain_list(domain: str) -> list[str]:domains = []if not domain:return domainsfor d in re.split(r'[,;]', domain):d_clean = d.strip().rstrip('/')if d_clean:domains.append(d_clean)return domainsdef equals_ignore_case(str1: str, *args: str) -> bool:if str1 is None:return None in argsfor arg in args:if arg is None:continueif str1.casefold() == arg.casefold():return Truereturn False
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。