码桶
发现社区成员的开源项目
origin-rules.js5.9 KB
import { logAudit } from '../../_audit.js';
const PHASE = 'http_request_origin';
const ENTRYPOINT = (zoneId) => `https://api.cloudflare.com/client/v4/zones/${zoneId}/rulesets/phases/${PHASE}/entrypoint`;
async function fetchRuleset(cfHeaders, zoneId) {
try {
const res = await fetch(ENTRYPOINT(zoneId), {
headers: { ...cfHeaders, 'Content-Type': 'application/json' }
});
const data = await res.json();
if (data.success) return data.result;
return null;
} catch {
return null;
}
}
async function putRules(cfHeaders, zoneId, ruleset, rules) {
const url = ruleset?.id
? `https://api.cloudflare.com/client/v4/zones/${zoneId}/rulesets/${ruleset.id}`
: ENTRYPOINT(zoneId);
const res = await fetch(url, {
method: 'PUT',
headers: { ...cfHeaders, 'Content-Type': 'application/json' },
body: JSON.stringify({ rules })
});
return res.json();
}
export async function onRequestGet(context) {
const { cfHeaders } = context.data;
const { zoneId } = context.params;
try {
const res = await fetch(ENTRYPOINT(zoneId), {
headers: { ...cfHeaders, 'Content-Type': 'application/json' }
});
const data = await res.json();
if (data.success) {
return new Response(JSON.stringify({
success: true,
rules: data.result?.rules || [],
rulesetId: data.result?.id || null,
errors: []
}), { headers: { 'Content-Type': 'application/json' } });
}
if (!data.success && data.errors?.some(e => e.code === 10000 || e.message?.includes('not found'))) {
return new Response(JSON.stringify({ success: true, rules: [], rulesetId: null, errors: [] }), { headers: { 'Content-Type': 'application/json' } });
}
return new Response(JSON.stringify({ success: false, errors: data.errors || [] }), { status: 400, headers: { 'Content-Type': 'application/json' } });
} catch (e) {
return new Response(JSON.stringify({ success: false, errors: [{ message: e.message || 'Failed to fetch origin rules' }] }), { status: 500, headers: { 'Content-Type': 'application/json' } });
}
}
export async function onRequestPost(context) {
const { cfHeaders } = context.data;
const { zoneId } = context.params;
const body = await context.request.json();
const username = context.data.user?.username || 'client';
const kv = context.env.CF_DNS_KV;
const { action } = body;
try {
if (action === 'toggle_rule') {
const { ruleIndex, enabled } = body;
const ruleset = await fetchRuleset(cfHeaders, zoneId);
if (!ruleset) return jsonErr('Could not fetch ruleset');
const rules = ruleset.rules || [];
if (ruleIndex < 0 || ruleIndex >= rules.length) return jsonErr('Invalid rule index');
rules[ruleIndex] = { ...rules[ruleIndex], enabled };
const putData = await putRules(cfHeaders, zoneId, ruleset, rules);
if (putData.success) {
await logAudit(kv, username, 'origin.toggle', `${enabled ? 'Enabled' : 'Disabled'} origin rule #${ruleIndex + 1} (zone: ${zoneId})`);
}
return jsonRes(putData);
}
if (action === 'create_rule') {
const { rule } = body;
const ruleset = await fetchRuleset(cfHeaders, zoneId);
const rules = ruleset?.rules || [];
rules.push({ ...rule, action: rule.action || 'route' });
const putData = await putRules(cfHeaders, zoneId, ruleset, rules);
if (putData.success) {
await logAudit(kv, username, 'origin.create', `Created origin rule "${rule.description || ''}" (zone: ${zoneId})`);
}
return jsonRes(putData);
}
if (action === 'update_rule') {
const { ruleIndex, rule } = body;
const ruleset = await fetchRuleset(cfHeaders, zoneId);
if (!ruleset) return jsonErr('Could not fetch ruleset');
const rules = ruleset.rules || [];
if (ruleIndex < 0 || ruleIndex >= rules.length) return jsonErr('Invalid rule index');
rules[ruleIndex] = { ...rules[ruleIndex], ...rule, action: rule.action || 'route' };
const putData = await putRules(cfHeaders, zoneId, ruleset, rules);
if (putData.success) {
await logAudit(kv, username, 'origin.update', `Updated origin rule #${ruleIndex + 1} (zone: ${zoneId})`);
}
return jsonRes(putData);
}
if (action === 'delete_rule') {
const { ruleIndex } = body;
const ruleset = await fetchRuleset(cfHeaders, zoneId);
if (!ruleset) return jsonErr('Could not fetch ruleset');
const rules = ruleset.rules || [];
if (ruleIndex < 0 || ruleIndex >= rules.length) return jsonErr('Invalid rule index');
const deleted = rules.splice(ruleIndex, 1)[0];
const putData = await putRules(cfHeaders, zoneId, ruleset, rules);
if (putData.success) {
await logAudit(kv, username, 'origin.delete', `Deleted origin rule "${deleted.description || '#' + (ruleIndex + 1)}" (zone: ${zoneId})`);
}
return jsonRes(putData);
}
return jsonErr(`Unknown action: "${action}"`);
} catch (e) {
return new Response(JSON.stringify({ success: false, errors: [{ message: e.message }] }), { status: 500, headers: { 'Content-Type': 'application/json' } });
}
}
function jsonRes(data) {
return new Response(JSON.stringify({ success: data.success, errors: data.errors || [] }), {
status: data.success ? 200 : 400, headers: { 'Content-Type': 'application/json' }
});
}
function jsonErr(msg) {
return new Response(JSON.stringify({ success: false, errors: [{ message: msg }] }), {
status: 400, headers: { 'Content-Type': 'application/json' }
});
}