mirror of
https://github.com/donlon/cloudflare-error-page.git
synced 2025-12-20 07:19:30 +00:00
124 lines
2.8 KiB
TypeScript
124 lines
2.8 KiB
TypeScript
import * as fs from "fs";
|
|
import * as path from "path";
|
|
import { fileURLToPath } from "url";
|
|
import * as ejs from "ejs";
|
|
import * as crypto from "crypto";
|
|
|
|
const __filename = fileURLToPath(import.meta.url);
|
|
const __dirname = path.dirname(__filename);
|
|
|
|
export interface StatusItem {
|
|
status?: "ok" | "error";
|
|
status_text?: string;
|
|
status_text_color?: string;
|
|
location?: string;
|
|
name?: string;
|
|
}
|
|
|
|
export interface MoreInformation {
|
|
hidden?: boolean;
|
|
link?: string;
|
|
text?: string;
|
|
for?: string;
|
|
}
|
|
|
|
export interface PerfSecBy {
|
|
link?: string;
|
|
text?: string;
|
|
}
|
|
|
|
export interface CreatorInfo {
|
|
hidden?: boolean;
|
|
link?: string;
|
|
text?: string;
|
|
}
|
|
|
|
export interface ErrorPageParams {
|
|
error_code?: number;
|
|
title?: string;
|
|
html_title?: string;
|
|
time?: string;
|
|
ray_id?: string;
|
|
client_ip?: string;
|
|
|
|
browser_status?: StatusItem;
|
|
cloudflare_status?: StatusItem;
|
|
host_status?: StatusItem;
|
|
|
|
error_source?: "browser" | "cloudflare" | "host";
|
|
|
|
what_happened?: string;
|
|
what_can_i_do?: string;
|
|
|
|
more_information?: MoreInformation;
|
|
perf_sec_by?: PerfSecBy;
|
|
creator_info?: CreatorInfo;
|
|
}
|
|
|
|
/**
|
|
* Fill default parameters if not provided
|
|
*/
|
|
function fillParams(params: ErrorPageParams): ErrorPageParams {
|
|
const filledParams = { ...params };
|
|
|
|
if (!filledParams.time) {
|
|
const now = new Date();
|
|
filledParams.time =
|
|
now.toISOString().replace("T", " ").substring(0, 19) + " UTC";
|
|
}
|
|
|
|
if (!filledParams.ray_id) {
|
|
filledParams.ray_id = crypto.randomBytes(8).toString("hex");
|
|
}
|
|
|
|
return filledParams;
|
|
}
|
|
|
|
/**
|
|
* Escape HTML special characters
|
|
*/
|
|
function escapeHtml(text: string): string {
|
|
const htmlEscapeMap: Record<string, string> = {
|
|
"&": "&",
|
|
"<": "<",
|
|
">": ">",
|
|
'"': """,
|
|
"'": "'",
|
|
};
|
|
return text.replace(/[&<>"']/g, (char) => htmlEscapeMap[char] || char);
|
|
}
|
|
|
|
/**
|
|
* Render a customized Cloudflare error page
|
|
* @param params - The parameters for the error page
|
|
* @param allowHtml - Whether to allow HTML in what_happened and what_can_i_do fields (default: true)
|
|
* @returns The rendered HTML string
|
|
*/
|
|
export function render(
|
|
params: ErrorPageParams,
|
|
allowHtml: boolean = true
|
|
): string {
|
|
let processedParams = fillParams(params);
|
|
|
|
if (!allowHtml) {
|
|
processedParams = { ...processedParams };
|
|
if (processedParams.what_happened) {
|
|
processedParams.what_happened = escapeHtml(processedParams.what_happened);
|
|
}
|
|
if (processedParams.what_can_i_do) {
|
|
processedParams.what_can_i_do = escapeHtml(processedParams.what_can_i_do);
|
|
}
|
|
}
|
|
|
|
// Load EJS template
|
|
const templatePath = path.join(__dirname, "..", "templates", "error.ejs");
|
|
|
|
const template = fs.readFileSync(templatePath, "utf-8");
|
|
|
|
const rendered = ejs.render(template, { params: processedParams });
|
|
|
|
return rendered;
|
|
}
|
|
|
|
export default render;
|