mirror of
https://github.com/donlon/cloudflare-error-page.git
synced 2026-01-06 15:41:45 +00:00
format Python files with ruff
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -9,5 +9,6 @@ build/
|
|||||||
dist/
|
dist/
|
||||||
*.egg-info/
|
*.egg-info/
|
||||||
__pycache__/
|
__pycache__/
|
||||||
|
.ruff_cache/
|
||||||
|
|
||||||
instance/
|
instance/
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ if sys.version_info >= (3, 11):
|
|||||||
from typing import NotRequired
|
from typing import NotRequired
|
||||||
else:
|
else:
|
||||||
from typing import _SpecialForm
|
from typing import _SpecialForm
|
||||||
|
|
||||||
NotRequired: _SpecialForm
|
NotRequired: _SpecialForm
|
||||||
|
|
||||||
|
|
||||||
@@ -69,12 +70,14 @@ class ErrorPageParams(TypedDict):
|
|||||||
creator_info: NotRequired[CreatorInfo]
|
creator_info: NotRequired[CreatorInfo]
|
||||||
|
|
||||||
|
|
||||||
def render(params: ErrorPageParams,
|
def render(
|
||||||
allow_html: bool = True,
|
params: ErrorPageParams,
|
||||||
template: Template | None = None,
|
allow_html: bool = True,
|
||||||
*args: Any,
|
template: Template | None = None,
|
||||||
**kwargs: Any) -> str:
|
*args: Any,
|
||||||
'''Render a customized Cloudflare error page.
|
**kwargs: Any,
|
||||||
|
) -> str:
|
||||||
|
"""Render a customized Cloudflare error page.
|
||||||
|
|
||||||
:param params: Parameters passed to the template. Refer to the project homepage for more information.
|
:param params: Parameters passed to the template. Refer to the project homepage for more information.
|
||||||
:param allow_html: Allow output raw HTML content from parameters. Set to False if you don't trust the source of the params.
|
:param allow_html: Allow output raw HTML content from parameters. Set to False if you don't trust the source of the params.
|
||||||
@@ -83,7 +86,7 @@ def render(params: ErrorPageParams,
|
|||||||
:param args: Additional positional arguments passed to ``Template.render`` function.
|
:param args: Additional positional arguments passed to ``Template.render`` function.
|
||||||
:param kwargs: Additional keyword arguments passed to ``Template.render`` function.
|
:param kwargs: Additional keyword arguments passed to ``Template.render`` function.
|
||||||
:return: The rendered error page as a string.
|
:return: The rendered error page as a string.
|
||||||
'''
|
"""
|
||||||
if not template:
|
if not template:
|
||||||
template = base_template
|
template = base_template
|
||||||
|
|
||||||
@@ -106,5 +109,6 @@ def render(params: ErrorPageParams,
|
|||||||
|
|
||||||
return template.render(params=params, *args, **kwargs)
|
return template.render(params=params, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
__version__ = '0.2.0'
|
__version__ = '0.2.0'
|
||||||
__all__ = ['jinja_env', 'base_template', 'render']
|
__all__ = ['jinja_env', 'base_template', 'render']
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
# SPDX-License-Identifier: MIT
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
from pathlib import Path
|
||||||
import secrets
|
import secrets
|
||||||
import string
|
import string
|
||||||
import sys
|
|
||||||
import tomllib
|
import tomllib
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
from flask import Flask, redirect, url_for
|
from flask import Flask, redirect, url_for
|
||||||
from flask_limiter import Limiter
|
from flask_limiter import Limiter
|
||||||
@@ -16,17 +15,24 @@ from werkzeug.middleware.proxy_fix import ProxyFix
|
|||||||
|
|
||||||
root_dir = Path(__file__).parent.parent.parent.parent
|
root_dir = Path(__file__).parent.parent.parent.parent
|
||||||
|
|
||||||
|
|
||||||
class Base(DeclarativeBase):
|
class Base(DeclarativeBase):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
db: SQLAlchemy = SQLAlchemy(model_class=Base, session_options={
|
|
||||||
# 'autobegin': False,
|
db: SQLAlchemy = SQLAlchemy(
|
||||||
# 'expire_on_commit': False,
|
model_class=Base,
|
||||||
})
|
session_options={
|
||||||
|
# 'autobegin': False,
|
||||||
|
# 'expire_on_commit': False,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
limiter: Limiter = Limiter(
|
limiter: Limiter = Limiter(
|
||||||
key_func=get_remote_address, # Uses client's IP address by default
|
key_func=get_remote_address, # Uses client's IP address by default
|
||||||
)
|
)
|
||||||
|
static_dir: str | None = None
|
||||||
|
|
||||||
|
|
||||||
def _generate_secret(length=32) -> str:
|
def _generate_secret(length=32) -> str:
|
||||||
characters = string.ascii_letters + string.digits # A-Z, a-z, 0-9
|
characters = string.ascii_letters + string.digits # A-Z, a-z, 0-9
|
||||||
@@ -34,10 +40,9 @@ def _generate_secret(length=32) -> str:
|
|||||||
|
|
||||||
|
|
||||||
def _initialize_app_config(app: Flask):
|
def _initialize_app_config(app: Flask):
|
||||||
|
global static_dir
|
||||||
if app.config.get('BEHIND_PROXY', True):
|
if app.config.get('BEHIND_PROXY', True):
|
||||||
app.wsgi_app = ProxyFix(
|
app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1)
|
||||||
app.wsgi_app, x_for=1, x_proto=1
|
|
||||||
)
|
|
||||||
secret_key = app.config.get('SECRET_KEY', '')
|
secret_key = app.config.get('SECRET_KEY', '')
|
||||||
if secret_key:
|
if secret_key:
|
||||||
app.secret_key = secret_key
|
app.secret_key = secret_key
|
||||||
@@ -45,12 +50,14 @@ def _initialize_app_config(app: Flask):
|
|||||||
app.logger.info('Using generated secret')
|
app.logger.info('Using generated secret')
|
||||||
app.secret_key = _generate_secret()
|
app.secret_key = _generate_secret()
|
||||||
|
|
||||||
app.config["SQLALCHEMY_DATABASE_URI"] = app.config.get('SQLALCHEMY_DATABASE_URI', 'sqlite:///example.db')
|
app.config['SQLALCHEMY_DATABASE_URI'] = app.config.get('SQLALCHEMY_DATABASE_URI', 'sqlite:///example.db')
|
||||||
if app.config["SQLALCHEMY_DATABASE_URI"].startswith('sqlite'):
|
if app.config['SQLALCHEMY_DATABASE_URI'].startswith('sqlite'):
|
||||||
app.config["SQLALCHEMY_ENGINE_OPTIONS"] = {
|
app.config['SQLALCHEMY_ENGINE_OPTIONS'] = {
|
||||||
'isolation_level': 'SERIALIZABLE',
|
'isolation_level': 'SERIALIZABLE',
|
||||||
# "execution_options": {"autobegin": False}
|
# "execution_options": {"autobegin": False}
|
||||||
}
|
}
|
||||||
|
static_dir = os.path.join(app.instance_path, app.config.get('STATIC_DIR', '../../web/dist'))
|
||||||
|
app.logger.info(f'Static directory: {static_dir}')
|
||||||
|
|
||||||
|
|
||||||
def create_app(test_config=None) -> Flask:
|
def create_app(test_config=None) -> Flask:
|
||||||
@@ -60,16 +67,12 @@ def create_app(test_config=None) -> Flask:
|
|||||||
os.makedirs(instance_path, exist_ok=True)
|
os.makedirs(instance_path, exist_ok=True)
|
||||||
print(f'App instance path: {instance_path}')
|
print(f'App instance path: {instance_path}')
|
||||||
|
|
||||||
app = Flask(__name__,
|
app = Flask(__name__, instance_path=instance_path, instance_relative_config=True)
|
||||||
instance_path=instance_path,
|
app.config.from_file('config.toml', load=tomllib.load, text=False)
|
||||||
instance_relative_config=True
|
|
||||||
)
|
|
||||||
app.config.from_file("config.toml", load=tomllib.load, text=False)
|
|
||||||
_initialize_app_config(app)
|
_initialize_app_config(app)
|
||||||
|
|
||||||
|
from . import utils # noqa: F401
|
||||||
from . import utils
|
from . import models # noqa: F401
|
||||||
from . import models
|
|
||||||
from . import examples
|
from . import examples
|
||||||
from . import editor
|
from . import editor
|
||||||
from . import share
|
from . import share
|
||||||
|
|||||||
@@ -30,13 +30,14 @@ bp_short = Blueprint('share_short', __name__, url_prefix='/')
|
|||||||
|
|
||||||
rand_charset = string.ascii_lowercase + string.digits
|
rand_charset = string.ascii_lowercase + string.digits
|
||||||
|
|
||||||
|
|
||||||
def get_rand_name(digits=8):
|
def get_rand_name(digits=8):
|
||||||
return ''.join(random.choice(rand_charset) for _ in range(digits))
|
return ''.join(random.choice(rand_charset) for _ in range(digits))
|
||||||
|
|
||||||
|
|
||||||
@bp.post('/create')
|
@bp.post('/create')
|
||||||
@limiter.limit("20 per minute")
|
@limiter.limit('20 per minute')
|
||||||
@limiter.limit("500 per hour")
|
@limiter.limit('500 per hour')
|
||||||
def create():
|
def create():
|
||||||
if len(request.data) > 4096:
|
if len(request.data) > 4096:
|
||||||
abort(413)
|
abort(413)
|
||||||
@@ -82,9 +83,7 @@ def get(name: str):
|
|||||||
item = db.session.query(models.Item).filter_by(name=name).first()
|
item = db.session.query(models.Item).filter_by(name=name).first()
|
||||||
if not item:
|
if not item:
|
||||||
if is_json:
|
if is_json:
|
||||||
return {
|
return {'status': 'notfound'}
|
||||||
'status': 'notfound'
|
|
||||||
}
|
|
||||||
else:
|
else:
|
||||||
return abort(404)
|
return abort(404)
|
||||||
params = cast(ErrorPageParams, item.params)
|
params = cast(ErrorPageParams, item.params)
|
||||||
@@ -104,8 +103,7 @@ def get(name: str):
|
|||||||
'link': request.host_url[:-1] + url_for('editor.index') + f'#from={name}',
|
'link': request.host_url[:-1] + url_for('editor.index') + f'#from={name}',
|
||||||
}
|
}
|
||||||
sanitize_page_param_links(params)
|
sanitize_page_param_links(params)
|
||||||
return render_extended_template(params=params,
|
return render_extended_template(params=params, allow_html=False)
|
||||||
allow_html=False)
|
|
||||||
|
|
||||||
|
|
||||||
@bp.get('/<name>')
|
@bp.get('/<name>')
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ env = Environment(
|
|||||||
trim_blocks=True,
|
trim_blocks=True,
|
||||||
lstrip_blocks=True,
|
lstrip_blocks=True,
|
||||||
)
|
)
|
||||||
template = env.from_string('''{% extends base %}
|
template = env.from_string("""{% extends base %}
|
||||||
|
|
||||||
{% block html_head %}
|
{% block html_head %}
|
||||||
{% if page_icon_url %}
|
{% if page_icon_url %}
|
||||||
@@ -45,11 +45,12 @@ template = env.from_string('''{% extends base %}
|
|||||||
<meta property="twitter:image" content="{{ page_image_url }}" />
|
<meta property="twitter:image" content="{{ page_image_url }}" />
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
''')
|
""")
|
||||||
|
|
||||||
|
|
||||||
loc_data: dict = None
|
loc_data: dict = None
|
||||||
|
|
||||||
|
|
||||||
def read_loc_file(path: str):
|
def read_loc_file(path: str):
|
||||||
try:
|
try:
|
||||||
with open(os.path.join(Path(__file__).parent / path)) as f:
|
with open(os.path.join(Path(__file__).parent / path)) as f:
|
||||||
@@ -117,11 +118,9 @@ def sanitize_page_param_links(param: ErrorPageParams):
|
|||||||
perf_sec_by['link'] = sanitize_user_link(link)
|
perf_sec_by['link'] = sanitize_user_link(link)
|
||||||
|
|
||||||
|
|
||||||
def render_extended_template(params: ErrorPageParams,
|
def render_extended_template(params: ErrorPageParams, *args: Any, **kwargs: Any) -> str:
|
||||||
*args: Any,
|
|
||||||
**kwargs: Any) -> str:
|
|
||||||
fill_cf_template_params(params)
|
fill_cf_template_params(params)
|
||||||
description = params.get('what_happened') or 'There is an internal server error on Cloudflare\'s network.'
|
description = params.get('what_happened') or "There is an internal server error on Cloudflare's network."
|
||||||
description = re.sub(r'<\/?.*?>', '', description).strip()
|
description = re.sub(r'<\/?.*?>', '', description).strip()
|
||||||
|
|
||||||
status = 'ok'
|
status = 'ok'
|
||||||
@@ -133,13 +132,15 @@ def render_extended_template(params: ErrorPageParams,
|
|||||||
page_icon_url = current_app.config.get('PAGE_ICON_URL', '').replace('{status}', status)
|
page_icon_url = current_app.config.get('PAGE_ICON_URL', '').replace('{status}', status)
|
||||||
page_icon_type = current_app.config.get('PAGE_ICON_TYPE')
|
page_icon_type = current_app.config.get('PAGE_ICON_TYPE')
|
||||||
page_image_url = current_app.config.get('PAGE_IMAGE_URL', '').replace('{status}', status)
|
page_image_url = current_app.config.get('PAGE_IMAGE_URL', '').replace('{status}', status)
|
||||||
return render_cf_error_page(params=params,
|
return render_cf_error_page(
|
||||||
template=template,
|
params=params,
|
||||||
base=base_template,
|
template=template,
|
||||||
page_icon_url=page_icon_url,
|
base=base_template,
|
||||||
page_icon_type=page_icon_type,
|
page_icon_url=page_icon_url,
|
||||||
page_url=request.url,
|
page_icon_type=page_icon_type,
|
||||||
page_description=description,
|
page_url=request.url,
|
||||||
page_image_url=page_image_url,
|
page_description=description,
|
||||||
*args,
|
page_image_url=page_image_url,
|
||||||
**kwargs)
|
*args,
|
||||||
|
**kwargs,
|
||||||
|
)
|
||||||
|
|||||||
@@ -24,3 +24,15 @@ include = ["app/**/*"]
|
|||||||
|
|
||||||
[tool.hatch.build.targets.wheel.hooks.custom]
|
[tool.hatch.build.targets.wheel.hooks.custom]
|
||||||
path = "hatch_build.py"
|
path = "hatch_build.py"
|
||||||
|
|
||||||
|
[tool.ruff]
|
||||||
|
line-length = 120
|
||||||
|
target-version = "py313"
|
||||||
|
|
||||||
|
[tool.ruff.lint]
|
||||||
|
ignore = [
|
||||||
|
'E722', # Bare-except
|
||||||
|
]
|
||||||
|
|
||||||
|
[tool.ruff.format]
|
||||||
|
quote-style = "single"
|
||||||
|
|||||||
@@ -46,3 +46,19 @@ path = "scripts/hatch_build.py"
|
|||||||
|
|
||||||
[tool.hatch.version]
|
[tool.hatch.version]
|
||||||
path = "cloudflare_error_page/__init__.py"
|
path = "cloudflare_error_page/__init__.py"
|
||||||
|
|
||||||
|
[tool.ruff]
|
||||||
|
line-length = 120
|
||||||
|
target-version = "py310"
|
||||||
|
include = [
|
||||||
|
"cloudflare_error_page/**/*.py",
|
||||||
|
"scripts/**/*.py",
|
||||||
|
]
|
||||||
|
|
||||||
|
[tool.ruff.lint]
|
||||||
|
ignore = [
|
||||||
|
'E722', # Bare-except
|
||||||
|
]
|
||||||
|
|
||||||
|
[tool.ruff.format]
|
||||||
|
quote-style = "single"
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ from hatchling.builders.hooks.plugin.interface import BuildHookInterface
|
|||||||
sys.path.append(os.path.dirname(__file__))
|
sys.path.append(os.path.dirname(__file__))
|
||||||
from inline_resources import generate_inlined_css
|
from inline_resources import generate_inlined_css
|
||||||
|
|
||||||
|
|
||||||
class CustomBuildHook(BuildHookInterface):
|
class CustomBuildHook(BuildHookInterface):
|
||||||
def initialize(self, version: str, build_data: dict[str, Any]):
|
def initialize(self, version: str, build_data: dict[str, Any]):
|
||||||
generate_inlined_css()
|
generate_inlined_css()
|
||||||
|
|||||||
@@ -38,8 +38,7 @@ def inline_svg_resources(css_file: str, svg_files: list[str], output_file: str):
|
|||||||
def inline_css_resource(original_file: str, css_file: str, output_file: str):
|
def inline_css_resource(original_file: str, css_file: str, output_file: str):
|
||||||
css_data = read_file(css_file)
|
css_data = read_file(css_file)
|
||||||
original_data = read_file(original_file)
|
original_data = read_file(original_file)
|
||||||
original_data = original_data.replace('<!-- @INLINE_CSS_HERE@ -->',
|
original_data = original_data.replace('<!-- @INLINE_CSS_HERE@ -->', f'<style>{css_data}</style>')
|
||||||
f'<style>{css_data}</style>')
|
|
||||||
note = 'Note: This file is generated with scripts/inline_resources.py. Please do not edit manually.'
|
note = 'Note: This file is generated with scripts/inline_resources.py. Please do not edit manually.'
|
||||||
if original_file.endswith('.ejs'):
|
if original_file.endswith('.ejs'):
|
||||||
original_data = f'<%# {note} %>\n' + original_data
|
original_data = f'<%# {note} %>\n' + original_data
|
||||||
@@ -60,7 +59,7 @@ def generate_inlined_css():
|
|||||||
'../images/cf-icon-error.svg',
|
'../images/cf-icon-error.svg',
|
||||||
],
|
],
|
||||||
os.path.join(resources_folder, 'styles/main.css'),
|
os.path.join(resources_folder, 'styles/main.css'),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
Reference in New Issue
Block a user