fix: show leave-license interstitial instead of blank black page.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -2,11 +2,12 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import html as html_lib
|
||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from fastapi import FastAPI, Request
|
from fastapi import FastAPI, Request
|
||||||
from fastapi.responses import HTMLResponse, JSONResponse, RedirectResponse
|
from fastapi.responses import HTMLResponse, JSONResponse, RedirectResponse, Response
|
||||||
|
|
||||||
from lib.license.license_lib import (
|
from lib.license.license_lib import (
|
||||||
get_device_id,
|
get_device_id,
|
||||||
@@ -17,6 +18,7 @@ from lib.license.license_lib import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
_TEMPLATE_PATH = Path(__file__).resolve().parent / "templates" / "license.html"
|
_TEMPLATE_PATH = Path(__file__).resolve().parent / "templates" / "license.html"
|
||||||
|
_POST_LICENSE_TARGET = "/login"
|
||||||
|
|
||||||
|
|
||||||
def _license_public_path(path: str) -> bool:
|
def _license_public_path(path: str) -> bool:
|
||||||
@@ -47,6 +49,43 @@ def _license_manage_requested(request: Request) -> bool:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _locally_licensed() -> bool:
|
||||||
|
return bool(get_license_status(skip_remote=True).get("valid"))
|
||||||
|
|
||||||
|
|
||||||
|
def _leave_license_response(target: str = _POST_LICENSE_TARGET) -> Response:
|
||||||
|
safe = html_lib.escape(target, quote=True)
|
||||||
|
body = f"""<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta http-equiv="refresh" content="0;url={safe}">
|
||||||
|
<title>已授权</title>
|
||||||
|
<style>
|
||||||
|
body {{
|
||||||
|
margin: 0; min-height: 100vh; display: flex; align-items: center; justify-content: center;
|
||||||
|
background: #0a0a10; color: #e8e8f0; font-family: sans-serif;
|
||||||
|
}}
|
||||||
|
a {{ color: #7ec8ff; }}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<p>已激活,正在进入系统… <a href="{safe}">点击进入</a></p>
|
||||||
|
<script>location.replace({target!r});</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
"""
|
||||||
|
return Response(
|
||||||
|
content=body,
|
||||||
|
status_code=302,
|
||||||
|
headers={
|
||||||
|
"Location": target,
|
||||||
|
"Cache-Control": "no-store, no-cache, must-revalidate",
|
||||||
|
"Content-Type": "text/html; charset=utf-8",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def install_license_middleware(app: FastAPI) -> None:
|
def install_license_middleware(app: FastAPI) -> None:
|
||||||
@app.get("/health")
|
@app.get("/health")
|
||||||
async def _license_health():
|
async def _license_health():
|
||||||
@@ -76,8 +115,8 @@ def install_license_middleware(app: FastAPI) -> None:
|
|||||||
@app.api_route("/license", methods=["GET", "POST"])
|
@app.api_route("/license", methods=["GET", "POST"])
|
||||||
async def _license_page(request: Request):
|
async def _license_page(request: Request):
|
||||||
# 已授权:默认不可再进授权页(续费/换机:/license?renew=1)
|
# 已授权:默认不可再进授权页(续费/换机:/license?renew=1)
|
||||||
if is_license_valid() and request.method == "GET" and not _license_manage_requested(request):
|
if _locally_licensed() and request.method == "GET" and not _license_manage_requested(request):
|
||||||
return RedirectResponse(url="/", status_code=302)
|
return _leave_license_response()
|
||||||
|
|
||||||
msg = ""
|
msg = ""
|
||||||
err = ""
|
err = ""
|
||||||
@@ -87,9 +126,9 @@ def install_license_middleware(app: FastAPI) -> None:
|
|||||||
ckey = str(form.get("client_api_key") or "").strip()
|
ckey = str(form.get("client_api_key") or "").strip()
|
||||||
result = redeem_code(code, client_api_key=ckey or None)
|
result = redeem_code(code, client_api_key=ckey or None)
|
||||||
if result.get("ok"):
|
if result.get("ok"):
|
||||||
return RedirectResponse(url="/", status_code=302)
|
return _leave_license_response()
|
||||||
err = result.get("message") or "激活失败"
|
err = result.get("message") or "激活失败"
|
||||||
status = get_license_status()
|
status = get_license_status(skip_remote=True)
|
||||||
html = _TEMPLATE_PATH.read_text(encoding="utf-8")
|
html = _TEMPLATE_PATH.read_text(encoding="utf-8")
|
||||||
filled = (
|
filled = (
|
||||||
html.replace("{{ device_id }}", get_device_id())
|
html.replace("{{ device_id }}", get_device_id())
|
||||||
|
|||||||
@@ -2,10 +2,11 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import html as html_lib
|
||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from flask import Flask, jsonify, redirect, render_template_string, request
|
from flask import Flask, Response, jsonify, redirect, render_template_string, request
|
||||||
|
|
||||||
from lib.license.license_lib import (
|
from lib.license.license_lib import (
|
||||||
get_device_id,
|
get_device_id,
|
||||||
@@ -17,6 +18,9 @@ from lib.license.license_lib import (
|
|||||||
|
|
||||||
_TEMPLATE_PATH = Path(__file__).resolve().parent / "templates" / "license.html"
|
_TEMPLATE_PATH = Path(__file__).resolve().parent / "templates" / "license.html"
|
||||||
|
|
||||||
|
# 已授权离开授权页时优先去登录页(有完整 UI);已登录会再跳进系统
|
||||||
|
_POST_LICENSE_TARGET = "/login"
|
||||||
|
|
||||||
|
|
||||||
def _license_public_path(path: str) -> bool:
|
def _license_public_path(path: str) -> bool:
|
||||||
"""未授权时仍可访问的路径(授权页 / 接口 / 静态资源)。"""
|
"""未授权时仍可访问的路径(授权页 / 接口 / 静态资源)。"""
|
||||||
@@ -31,7 +35,7 @@ def _license_public_path(path: str) -> bool:
|
|||||||
|
|
||||||
def _license_manage_requested() -> bool:
|
def _license_manage_requested() -> bool:
|
||||||
"""已授权时默认禁止进入 /license;续费/换机用 ?renew=1。"""
|
"""已授权时默认禁止进入 /license;续费/换机用 ?renew=1。"""
|
||||||
return (request.args.get("renew") or request.args.get("manage") or "").strip() in (
|
return (request.args.get("renew") or request.args.get("manage") or "").strip().lower() in (
|
||||||
"1",
|
"1",
|
||||||
"true",
|
"true",
|
||||||
"yes",
|
"yes",
|
||||||
@@ -39,6 +43,45 @@ def _license_manage_requested() -> bool:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _locally_licensed() -> bool:
|
||||||
|
"""仅看本地状态,避免授权站网络拖死页面。"""
|
||||||
|
return bool(get_license_status(skip_remote=True).get("valid"))
|
||||||
|
|
||||||
|
|
||||||
|
def _leave_license_response(target: str = _POST_LICENSE_TARGET) -> Response:
|
||||||
|
"""已授权离开 /license:302 + 可见提示,避免浏览器停在全黑空页。"""
|
||||||
|
safe = html_lib.escape(target, quote=True)
|
||||||
|
body = f"""<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta http-equiv="refresh" content="0;url={safe}">
|
||||||
|
<title>已授权</title>
|
||||||
|
<style>
|
||||||
|
body {{
|
||||||
|
margin: 0; min-height: 100vh; display: flex; align-items: center; justify-content: center;
|
||||||
|
background: #0a0a10; color: #e8e8f0; font-family: sans-serif;
|
||||||
|
}}
|
||||||
|
a {{ color: #7ec8ff; }}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<p>已激活,正在进入系统… <a href="{safe}">点击进入</a></p>
|
||||||
|
<script>location.replace({target!r});</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
"""
|
||||||
|
return Response(
|
||||||
|
body,
|
||||||
|
status=302,
|
||||||
|
headers={
|
||||||
|
"Location": target,
|
||||||
|
"Cache-Control": "no-store, no-cache, must-revalidate",
|
||||||
|
"Content-Type": "text/html; charset=utf-8",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def install_license_gate(app: Flask) -> None:
|
def install_license_gate(app: Flask) -> None:
|
||||||
"""注册 /license 与 before_request 门禁。三所 Flask 共用。"""
|
"""注册 /license 与 before_request 门禁。三所 Flask 共用。"""
|
||||||
|
|
||||||
@@ -65,8 +108,8 @@ def install_license_gate(app: Flask) -> None:
|
|||||||
@app.route("/license", methods=["GET", "POST"])
|
@app.route("/license", methods=["GET", "POST"])
|
||||||
def _license_page():
|
def _license_page():
|
||||||
# 已授权:默认不可再进授权页(续费/换机:/license?renew=1)
|
# 已授权:默认不可再进授权页(续费/换机:/license?renew=1)
|
||||||
if is_license_valid() and request.method == "GET" and not _license_manage_requested():
|
if _locally_licensed() and request.method == "GET" and not _license_manage_requested():
|
||||||
return redirect("/")
|
return _leave_license_response()
|
||||||
|
|
||||||
msg = ""
|
msg = ""
|
||||||
err = ""
|
err = ""
|
||||||
@@ -75,9 +118,9 @@ def install_license_gate(app: Flask) -> None:
|
|||||||
ckey = (request.form.get("client_api_key") or "").strip()
|
ckey = (request.form.get("client_api_key") or "").strip()
|
||||||
result = redeem_code(code, client_api_key=ckey or None)
|
result = redeem_code(code, client_api_key=ckey or None)
|
||||||
if result.get("ok"):
|
if result.get("ok"):
|
||||||
return redirect("/")
|
return _leave_license_response()
|
||||||
err = result.get("message") or "激活失败"
|
err = result.get("message") or "激活失败"
|
||||||
status = get_license_status()
|
status = get_license_status(skip_remote=True)
|
||||||
html = _TEMPLATE_PATH.read_text(encoding="utf-8")
|
html = _TEMPLATE_PATH.read_text(encoding="utf-8")
|
||||||
return render_template_string(
|
return render_template_string(
|
||||||
html,
|
html,
|
||||||
|
|||||||
Reference in New Issue
Block a user