mirror of
https://github.com/donlon/cloudflare-error-page.git
synced 2025-12-19 14:59:28 +00:00
python: support type hinting for input params
This commit is contained in:
@@ -1,7 +1,15 @@
|
|||||||
import html
|
import html
|
||||||
import secrets
|
import secrets
|
||||||
|
import sys
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
from typing import Any
|
from typing import Any, TypedDict, Literal
|
||||||
|
|
||||||
|
if sys.version_info >= (3, 11):
|
||||||
|
from typing import NotRequired
|
||||||
|
else:
|
||||||
|
from typing import _SpecialForm
|
||||||
|
NotRequired: _SpecialForm
|
||||||
|
|
||||||
|
|
||||||
from jinja2 import Environment, PackageLoader, Template, select_autoescape
|
from jinja2 import Environment, PackageLoader, Template, select_autoescape
|
||||||
|
|
||||||
@@ -15,7 +23,53 @@ env = Environment(
|
|||||||
default_template: Template = env.get_template("error.html")
|
default_template: Template = env.get_template("error.html")
|
||||||
|
|
||||||
|
|
||||||
def render(params: dict,
|
class ErrorPageParams(TypedDict):
|
||||||
|
class MoreInformation(TypedDict):
|
||||||
|
hidden: NotRequired[bool]
|
||||||
|
text: NotRequired[str]
|
||||||
|
link: NotRequired[str]
|
||||||
|
for_text: NotRequired[str] # renamed to avoid Python keyword conflict
|
||||||
|
|
||||||
|
class StatusItem(TypedDict):
|
||||||
|
status: NotRequired[Literal["ok", "error"]]
|
||||||
|
location: NotRequired[str]
|
||||||
|
name: NotRequired[str]
|
||||||
|
status_text: NotRequired[str]
|
||||||
|
status_text_color: NotRequired[str]
|
||||||
|
|
||||||
|
class PerfSecBy(TypedDict):
|
||||||
|
text: NotRequired[str]
|
||||||
|
link: NotRequired[str]
|
||||||
|
|
||||||
|
class CreatorInfo(TypedDict):
|
||||||
|
hidden: NotRequired[bool]
|
||||||
|
link: NotRequired[str]
|
||||||
|
text: NotRequired[str]
|
||||||
|
|
||||||
|
html_title: NotRequired[str]
|
||||||
|
title: NotRequired[str]
|
||||||
|
error_code: NotRequired[str]
|
||||||
|
time: NotRequired[str]
|
||||||
|
|
||||||
|
more_information: NotRequired[MoreInformation]
|
||||||
|
|
||||||
|
browser_status: NotRequired[StatusItem]
|
||||||
|
cloudflare_status: NotRequired[StatusItem]
|
||||||
|
host_status: NotRequired[StatusItem]
|
||||||
|
|
||||||
|
error_source: NotRequired[Literal["browser", "cloudflare", "host"]]
|
||||||
|
|
||||||
|
what_happened: NotRequired[str]
|
||||||
|
what_can_i_do: NotRequired[str]
|
||||||
|
|
||||||
|
ray_id: NotRequired[str]
|
||||||
|
client_ip: NotRequired[str]
|
||||||
|
|
||||||
|
perf_sec_by: NotRequired[PerfSecBy]
|
||||||
|
creator_info: NotRequired[CreatorInfo]
|
||||||
|
|
||||||
|
|
||||||
|
def render(params: ErrorPageParams,
|
||||||
allow_html: bool = True,
|
allow_html: bool = True,
|
||||||
template: Template | None = None,
|
template: Template | None = None,
|
||||||
*args: Any,
|
*args: Any,
|
||||||
@@ -35,6 +89,12 @@ def render(params: dict,
|
|||||||
|
|
||||||
params = {**params}
|
params = {**params}
|
||||||
|
|
||||||
|
more_information = params.get('more_information')
|
||||||
|
if more_information:
|
||||||
|
for_text = more_information.get('for_text')
|
||||||
|
if for_text is not None:
|
||||||
|
more_information['for'] = for_text
|
||||||
|
|
||||||
if not params.get('time'):
|
if not params.get('time'):
|
||||||
utc_now = datetime.now(timezone.utc)
|
utc_now = datetime.now(timezone.utc)
|
||||||
params['time'] = utc_now.strftime("%Y-%m-%d %H:%M:%S UTC")
|
params['time'] = utc_now.strftime("%Y-%m-%d %H:%M:%S UTC")
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ from flask import (
|
|||||||
redirect,
|
redirect,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from cloudflare_error_page import ErrorPageParams
|
||||||
from cloudflare_error_page import render as render_cf_error_page
|
from cloudflare_error_page import render as render_cf_error_page
|
||||||
from .utils import fill_cf_template_params
|
from .utils import fill_cf_template_params
|
||||||
|
|
||||||
@@ -22,7 +23,7 @@ bp = Blueprint('examples', __name__, url_prefix='/')
|
|||||||
|
|
||||||
param_cache: dict[str, dict] = {}
|
param_cache: dict[str, dict] = {}
|
||||||
|
|
||||||
def get_page_params(name: str) -> dict:
|
def get_page_params(name: str) -> ErrorPageParams:
|
||||||
name = re.sub(r'[^\w]', '', name)
|
name = re.sub(r'[^\w]', '', name)
|
||||||
params = param_cache.get(name)
|
params = param_cache.get(name)
|
||||||
if params is not None:
|
if params is not None:
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
from cloudflare_error_page import ErrorPageParams
|
||||||
from flask import request
|
from flask import request
|
||||||
|
|
||||||
from . import root_dir
|
from . import root_dir
|
||||||
|
|
||||||
|
|
||||||
@@ -31,13 +33,13 @@ def get_cf_location(loc: str):
|
|||||||
return data.get('city')
|
return data.get('city')
|
||||||
|
|
||||||
|
|
||||||
def fill_cf_template_params(params: dict):
|
def fill_cf_template_params(params: ErrorPageParams):
|
||||||
# Get the real Ray ID / data center location from Cloudflare header
|
# Get the real Ray ID / data center location from Cloudflare header
|
||||||
ray_id_loc = request.headers.get('Cf-Ray')
|
ray_id_loc = request.headers.get('Cf-Ray')
|
||||||
if ray_id_loc:
|
if ray_id_loc:
|
||||||
params['ray_id'] = ray_id_loc[:16]
|
params['ray_id'] = ray_id_loc[:16]
|
||||||
|
|
||||||
cf_status: dict = params.get('cloudflare_status')
|
cf_status = params.get('cloudflare_status')
|
||||||
if cf_status is None:
|
if cf_status is None:
|
||||||
cf_status = params['cloudflare_status'] = {}
|
cf_status = params['cloudflare_status'] = {}
|
||||||
if not cf_status.get('location'):
|
if not cf_status.get('location'):
|
||||||
@@ -61,7 +63,7 @@ def sanitize_user_link(link: str):
|
|||||||
return '#' + link
|
return '#' + link
|
||||||
|
|
||||||
|
|
||||||
def sanitize_page_param_links(param: dict):
|
def sanitize_page_param_links(param: ErrorPageParams):
|
||||||
more_info = param.get('more_information')
|
more_info = param.get('more_information')
|
||||||
if more_info:
|
if more_info:
|
||||||
link = more_info.get('link')
|
link = more_info.get('link')
|
||||||
|
|||||||
@@ -1,19 +1,18 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import re
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from flask import (
|
from flask import (
|
||||||
Flask,
|
Flask,
|
||||||
request,
|
request,
|
||||||
send_from_directory
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Append this directory to sys.path is not required if the package is already installed
|
# Append this directory to sys.path is not required if the package is already installed
|
||||||
examples_dir = os.path.dirname(os.path.abspath(__file__))
|
examples_dir = os.path.dirname(os.path.abspath(__file__))
|
||||||
sys.path.append(os.path.dirname(examples_dir))
|
sys.path.append(os.path.dirname(examples_dir))
|
||||||
|
|
||||||
|
from cloudflare_error_page import ErrorPageParams
|
||||||
from cloudflare_error_page import render as render_cf_error_page
|
from cloudflare_error_page import render as render_cf_error_page
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
@@ -21,7 +20,7 @@ app = Flask(__name__)
|
|||||||
|
|
||||||
@app.route('/')
|
@app.route('/')
|
||||||
def index():
|
def index():
|
||||||
params = {
|
params: ErrorPageParams = {
|
||||||
"title": "Internal server error",
|
"title": "Internal server error",
|
||||||
"error_code": 500,
|
"error_code": 500,
|
||||||
"browser_status": {
|
"browser_status": {
|
||||||
|
|||||||
Reference in New Issue
Block a user