|
|
@@ -1,20 +1,14 @@
|
|
|
|
from flask import Flask, jsonify, request, redirect, send_file, Response
|
|
|
|
import os, json, random, socket, logging, ipaddress, urllib.error, urllib.parse, urllib.request, threading
|
|
|
|
from datetime import datetime, date
|
|
|
|
from collections import defaultdict, deque
|
|
|
|
import ipaddress
|
|
|
|
from time import monotonic
|
|
|
|
|
|
|
|
from pathlib import Path
|
|
|
|
|
|
|
|
from datetime import date, datetime
|
|
|
|
from zoneinfo import ZoneInfo, available_timezones
|
|
|
|
from zoneinfo import ZoneInfo, available_timezones
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
from flask import Flask, jsonify, request, redirect, send_file, Response
|
|
|
|
from flask_cors import CORS
|
|
|
|
from flask_cors import CORS
|
|
|
|
from lunar_python import Solar
|
|
|
|
from lunar_python import Solar
|
|
|
|
import ip2region.searcher as xdb
|
|
|
|
from ip2region import searcher as xdb, util
|
|
|
|
import ip2region.util as util
|
|
|
|
|
|
|
|
from pathlib import Path
|
|
|
|
|
|
|
|
import json
|
|
|
|
|
|
|
|
import random
|
|
|
|
|
|
|
|
import urllib.error
|
|
|
|
|
|
|
|
import urllib.parse
|
|
|
|
|
|
|
|
import urllib.request
|
|
|
|
|
|
|
|
import logging
|
|
|
|
|
|
|
|
import socket
|
|
|
|
|
|
|
|
import os
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class LowercasePathMiddleware:
|
|
|
|
class LowercasePathMiddleware:
|
|
|
@@ -98,6 +92,34 @@ for item in RIDDLE_DATA:
|
|
|
|
RIDDLE_RIDDLE_MAP[riddle_lower].append(item)
|
|
|
|
RIDDLE_RIDDLE_MAP[riddle_lower].append(item)
|
|
|
|
RIDDLE_ANSWER_MAP[answer_lower].append(item)
|
|
|
|
RIDDLE_ANSWER_MAP[answer_lower].append(item)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
RATE_LIMIT = 30
|
|
|
|
|
|
|
|
RATE_WINDOW_SECONDS = 60
|
|
|
|
|
|
|
|
_request_times = defaultdict(deque)
|
|
|
|
|
|
|
|
_rate_limit_lock = threading.Lock()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@app.before_request
|
|
|
|
|
|
|
|
def enforce_rate_limit():
|
|
|
|
|
|
|
|
now = monotonic()
|
|
|
|
|
|
|
|
forwarded_for = request.headers.get("X-Forwarded-For", "")
|
|
|
|
|
|
|
|
client_ip = forwarded_for.split(",", 1)[0].strip() or request.remote_addr or "unknown"
|
|
|
|
|
|
|
|
with _rate_limit_lock:
|
|
|
|
|
|
|
|
timestamps = _request_times[client_ip]
|
|
|
|
|
|
|
|
cutoff = now - RATE_WINDOW_SECONDS
|
|
|
|
|
|
|
|
while timestamps and timestamps[0] <= cutoff:
|
|
|
|
|
|
|
|
timestamps.popleft()
|
|
|
|
|
|
|
|
if len(timestamps) >= RATE_LIMIT:
|
|
|
|
|
|
|
|
retry_after = max(1, int(timestamps[0] + RATE_WINDOW_SECONDS - now + 0.999))
|
|
|
|
|
|
|
|
response = jsonify({
|
|
|
|
|
|
|
|
"error": "请求过于频繁,请稍后再试",
|
|
|
|
|
|
|
|
"limit": f"{RATE_LIMIT}/min",
|
|
|
|
|
|
|
|
"retry_after": retry_after,
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
response.status_code = 429
|
|
|
|
|
|
|
|
response.headers["Retry-After"] = str(retry_after)
|
|
|
|
|
|
|
|
return response
|
|
|
|
|
|
|
|
timestamps.append(now)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@app.route("/favicon.ico")
|
|
|
|
@app.route("/favicon.ico")
|
|
|
|
def favicon():
|
|
|
|
def favicon():
|
|
|
@@ -143,7 +165,7 @@ def lunar():
|
|
|
|
args_lower = {k.lower(): v for k, v in request.args.items()}
|
|
|
|
args_lower = {k.lower(): v for k, v in request.args.items()}
|
|
|
|
if set(args_lower.keys()) - {"date"}:
|
|
|
|
if set(args_lower.keys()) - {"date"}:
|
|
|
|
return jsonify({
|
|
|
|
return jsonify({
|
|
|
|
"error": f"{set(args_lower.keys()) - {"date"}}参数非法",
|
|
|
|
"error": "{}参数非法".format(set(args_lower.keys()) - {"date"}),
|
|
|
|
"allowed_params": ["date=YYYY-MM-DD"],
|
|
|
|
"allowed_params": ["date=YYYY-MM-DD"],
|
|
|
|
})
|
|
|
|
})
|
|
|
|
ds = args_lower.get("date", "").strip()
|
|
|
|
ds = args_lower.get("date", "").strip()
|
|
|
@@ -201,7 +223,7 @@ def luck():
|
|
|
|
args_lower = {k.lower(): v for k, v in request.args.items()}
|
|
|
|
args_lower = {k.lower(): v for k, v in request.args.items()}
|
|
|
|
if set(args_lower.keys()) - {"id", "title", "type"}:
|
|
|
|
if set(args_lower.keys()) - {"id", "title", "type"}:
|
|
|
|
return jsonify({
|
|
|
|
return jsonify({
|
|
|
|
"error": f"{set(args_lower.keys()) - {"id", "title", "type"}}参数非法",
|
|
|
|
"error": "{}参数非法".format(set(args_lower.keys()) - {"id", "title", "type"}),
|
|
|
|
"allowed_params": ["id=xxx", "title=xxx", "type=xxx"],
|
|
|
|
"allowed_params": ["id=xxx", "title=xxx", "type=xxx"],
|
|
|
|
})
|
|
|
|
})
|
|
|
|
luck_id = args_lower.get("id", "").strip()
|
|
|
|
luck_id = args_lower.get("id", "").strip()
|
|
|
@@ -259,7 +281,7 @@ def poem():
|
|
|
|
args_lower = {k.lower(): v for k, v in request.args.items()}
|
|
|
|
args_lower = {k.lower(): v for k, v in request.args.items()}
|
|
|
|
if set(args_lower.keys()) - {"id", "title", "author", "type", "full"}:
|
|
|
|
if set(args_lower.keys()) - {"id", "title", "author", "type", "full"}:
|
|
|
|
return jsonify({
|
|
|
|
return jsonify({
|
|
|
|
"error": f"{set(args_lower.keys()) - {"id", "title", "author", "type", "full"}}参数非法",
|
|
|
|
"error": "{}参数非法".format(set(args_lower.keys()) - {"id", "title", "author", "type", "full"}),
|
|
|
|
"allowed_params": ["id=xxx", "title=xxx", "author=xxx", "type=xxx", "full=true/false"],
|
|
|
|
"allowed_params": ["id=xxx", "title=xxx", "author=xxx", "type=xxx", "full=true/false"],
|
|
|
|
})
|
|
|
|
})
|
|
|
|
poem_id = args_lower.get("id", "").strip()
|
|
|
|
poem_id = args_lower.get("id", "").strip()
|
|
|
@@ -355,7 +377,7 @@ def ip():
|
|
|
|
args_lower = {k.lower(): v for k, v in request.args.items()}
|
|
|
|
args_lower = {k.lower(): v for k, v in request.args.items()}
|
|
|
|
if set(args_lower.keys()) - {"name"}:
|
|
|
|
if set(args_lower.keys()) - {"name"}:
|
|
|
|
return jsonify({
|
|
|
|
return jsonify({
|
|
|
|
"error": f"{set(args_lower.keys()) - {"name"}}参数非法",
|
|
|
|
"error": "{}参数非法".format(set(args_lower.keys()) - {"name"}),
|
|
|
|
"allowed_params": ["name=xxx"],
|
|
|
|
"allowed_params": ["name=xxx"],
|
|
|
|
})
|
|
|
|
})
|
|
|
|
query_name = args_lower.get("name", "").strip()
|
|
|
|
query_name = args_lower.get("name", "").strip()
|
|
|
@@ -425,7 +447,7 @@ def time_api():
|
|
|
|
args_lower = {k.lower(): v for k, v in request.args.items()}
|
|
|
|
args_lower = {k.lower(): v for k, v in request.args.items()}
|
|
|
|
if set(args_lower.keys()) - {"tz"}:
|
|
|
|
if set(args_lower.keys()) - {"tz"}:
|
|
|
|
return jsonify({
|
|
|
|
return jsonify({
|
|
|
|
"error": f"{set(args_lower.keys()) - {"tz"}}参数非法",
|
|
|
|
"error": "{}参数非法".format(set(args_lower.keys()) - {"tz"}),
|
|
|
|
"allowed_params": ["tz=xxx"],
|
|
|
|
"allowed_params": ["tz=xxx"],
|
|
|
|
})
|
|
|
|
})
|
|
|
|
tz = args_lower.get("tz", "").strip()
|
|
|
|
tz = args_lower.get("tz", "").strip()
|
|
|
@@ -490,7 +512,7 @@ def riddle():
|
|
|
|
args_lower = {k.lower(): v for k, v in request.args.items()}
|
|
|
|
args_lower = {k.lower(): v for k, v in request.args.items()}
|
|
|
|
if set(args_lower.keys()) - {"riddle", "answer"}:
|
|
|
|
if set(args_lower.keys()) - {"riddle", "answer"}:
|
|
|
|
return jsonify({
|
|
|
|
return jsonify({
|
|
|
|
"error": f"{set(args_lower.keys()) - {"riddle", "answer"}}参数非法",
|
|
|
|
"error": "{}参数非法".format(set(args_lower.keys()) - {"riddle", "answer"}),
|
|
|
|
"allowed_params": ["riddle=xxx", "answer=xxx"],
|
|
|
|
"allowed_params": ["riddle=xxx", "answer=xxx"],
|
|
|
|
})
|
|
|
|
})
|
|
|
|
query_riddle = args_lower.get("riddle", "").strip()
|
|
|
|
query_riddle = args_lower.get("riddle", "").strip()
|
|
|
@@ -540,7 +562,7 @@ def sci():
|
|
|
|
args_lower = {k.lower(): v for k, v in request.args.items()}
|
|
|
|
args_lower = {k.lower(): v for k, v in request.args.items()}
|
|
|
|
if set(args_lower.keys()) - {"nane", "name"}:
|
|
|
|
if set(args_lower.keys()) - {"nane", "name"}:
|
|
|
|
return jsonify({
|
|
|
|
return jsonify({
|
|
|
|
"error": f"{set(args_lower.keys()) - {"nane", "name"}}参数非法",
|
|
|
|
"error": "{}参数非法".format(set(args_lower.keys()) - {"nane", "name"}),
|
|
|
|
"allowed_params": ["nane=xxx"],
|
|
|
|
"allowed_params": ["nane=xxx"],
|
|
|
|
})
|
|
|
|
})
|
|
|
|
publication_name = args_lower.get("nane", "").strip() or args_lower.get("name", "").strip()
|
|
|
|
publication_name = args_lower.get("nane", "").strip() or args_lower.get("name", "").strip()
|
|
|
@@ -612,7 +634,7 @@ def agent():
|
|
|
|
extra_params = set(args_lower.keys()) - allowed_keys
|
|
|
|
extra_params = set(args_lower.keys()) - allowed_keys
|
|
|
|
if extra_params:
|
|
|
|
if extra_params:
|
|
|
|
return jsonify({
|
|
|
|
return jsonify({
|
|
|
|
"error": f"{extra_params}参数非法",
|
|
|
|
"error": "{}参数非法".format(extra_params),
|
|
|
|
"allowed_params": ["url=xxx", "ref=xxx", "pwd=xxx"],
|
|
|
|
"allowed_params": ["url=xxx", "ref=xxx", "pwd=xxx"],
|
|
|
|
})
|
|
|
|
})
|
|
|
|
target_url = args_lower.get("url", "").strip()
|
|
|
|
target_url = args_lower.get("url", "").strip()
|
|
|
@@ -700,7 +722,7 @@ def pan_file_download():
|
|
|
|
extra_params = set(args_lower.keys()) - allowed_keys
|
|
|
|
extra_params = set(args_lower.keys()) - allowed_keys
|
|
|
|
if extra_params:
|
|
|
|
if extra_params:
|
|
|
|
return jsonify({
|
|
|
|
return jsonify({
|
|
|
|
"error": f"{extra_params}参数非法",
|
|
|
|
"error": "{}参数非法".format(extra_params),
|
|
|
|
"allowed_params": ["name=xxx", "download=true/false"],
|
|
|
|
"allowed_params": ["name=xxx", "download=true/false"],
|
|
|
|
})
|
|
|
|
})
|
|
|
|
file_name = args_lower.get("name", "").strip()
|
|
|
|
file_name = args_lower.get("name", "").strip()
|
|
|
|