UNPKG

@ghini/kit

Version:

js practical tools to assist efficient development

447 lines (446 loc) 13.6 kB
import { req } from "./http/req.js"; export { cf }; async function cf(obj) { const key = obj.key; const domain = obj.domain; const email = obj.email; let auth, headers = {}; if (email) { headers = { "X-Auth-Email": email, "X-Auth-Key": key, }; console.dev("使用Global API Key认证"); } else { auth = "Bearer " + key; console.dev("使用API Token认证"); } const zid = await getZoneId.bind({ domain, auth, headers })(); return { auth, headers, domain, zid, getZoneId, add, madd, set, mset, del, mdel, setSecurity, }; } async function getZoneId() { try { console.dev("获取Zone ID,域名:", this.domain); let res; if (this.headers && Object.keys(this.headers).length > 0) { res = await req( `https://api.cloudflare.com/client/v4/zones?name=${this.domain}`, {}, this.headers ); } else { res = await req( `https://api.cloudflare.com/client/v4/zones?name=${this.domain}`, { auth: this.auth } ); } if (res.data.success && res.data.result.length > 0) { return res.data.result[0].id; } else { throw new Error("记录未找到或权限不足"); } } catch (error) { console.error("获取 Zone ID 失败:", error.message); return null; } } async function mset(arr) { return Promise.all(arr.map((item) => this.set(item))); } /** * 强大的set能力 能够处理如'em962 "test test test" txt' * 默认ttl = 1 * @param {*} str */ async function set(str) { let pre, content, type, priority, ttl; if (Array.isArray(str)) { [pre, content, type, priority, ttl] = str; } else { let processedStr = ""; let inQuotes = false; for (let i = 0; i < str.length; i++) { const char = str.charAt(i); if (char === '"') { inQuotes = !inQuotes; processedStr += char; } else if (char === " ") { processedStr += inQuotes ? "{+}" : char; } else { processedStr += char; } } processedStr = processedStr.replace(/ +/g, " ").trim(); const parts = processedStr.split(" "); pre = parts[0]; if (parts[1] && parts[1].startsWith('"')) { let quoteContent = parts[1]; let contentEndIndex = 1; if (!parts[1].endsWith('"') || parts[1].length <= 1) { for (let i = 2; i < parts.length; i++) { quoteContent += " " + parts[i]; contentEndIndex = i; if (parts[i].endsWith('"')) break; } } content = '"' + quoteContent .substring(1, quoteContent.length - 1) .replace(/\{\+\}/g, " ") + '"'; type = parts[contentEndIndex + 1] || "A"; priority = parts[contentEndIndex + 2] || 10; ttl = parts[contentEndIndex + 3] || 60; } else { content = parts[1] || ""; type = parts[2] || "A"; priority = parts[3] || 10; ttl = parts[4] || 60; } } const host = pre + "." + this.domain; const recordTtl = ttl === "auto" || isNaN(parseInt(ttl)) ? 60 : parseInt(ttl) || 60; try { if (!this.zid) { throw new Error(`无法获取Zone ID,请检查域名: ${this.domain}`); } if (type === "A" && content.includes(",")) { const ipList = [ ...new Set( content .split(",") .map((ip) => ip.trim()) .filter((ip) => ip !== "") ), ]; let res; if (this.headers && Object.keys(this.headers).length > 0) { res = await req( `https://api.cloudflare.com/client/v4/zones/${this.zid}/dns_records?type=${type}&name=${host}`, {}, this.headers ); } else { res = await req( `https://api.cloudflare.com/client/v4/zones/${this.zid}/dns_records?type=${type}&name=${host}`, { auth: this.auth } ); } if (res.data.result && res.data.result.length > 0) { const deletePromises = res.data.result.map((record) => { if (this.headers && Object.keys(this.headers).length > 0) { return req( `https://api.cloudflare.com/client/v4/zones/${this.zid}/dns_records/${record.id} delete`, {}, this.headers ); } else { return req( `https://api.cloudflare.com/client/v4/zones/${this.zid}/dns_records/${record.id} delete`, { auth: this.auth } ); } }); await Promise.all(deletePromises); } console.log(`添加: ${host} ${type} ${content} 数量:${ipList.length}`); const addPromises = ipList.map((ip) => { const recordData = { type: type, name: host, content: ip, proxied: false, priority: parseInt(priority) || 10, ttl: recordTtl, }; return add.bind({ auth: this.auth, headers: this.headers, zid: this.zid, })(recordData); }); await Promise.all(addPromises); return { success: true, message: `已为 ${host} 添加 ${ipList.length} 条A记录`, }; } else { let res; if (this.headers && Object.keys(this.headers).length > 0) { res = await req( `https://api.cloudflare.com/client/v4/zones/${this.zid}/dns_records?type=${type}&name=${host}`, {}, this.headers ); } else { res = await req( `https://api.cloudflare.com/client/v4/zones/${this.zid}/dns_records?type=${type}&name=${host}`, { auth: this.auth } ); } if (res.data.result && res.data.result.length > 0) { const deletePromises = res.data.result.map((record) => { if (this.headers && Object.keys(this.headers).length > 0) { return req( `https://api.cloudflare.com/client/v4/zones/${this.zid}/dns_records/${record.id} delete`, {}, this.headers ); } else { return req( `https://api.cloudflare.com/client/v4/zones/${this.zid}/dns_records/${record.id} delete`, { auth: this.auth } ); } }); await Promise.all(deletePromises); } console.log(`添加: ${host} ${type} ${content}`); const result = await add.bind({ auth: this.auth, headers: this.headers, zid: this.zid, })({ type: type || "A", name: host, content, proxied: false, priority: parseInt(priority) || 10, ttl: recordTtl, }); return { success: true, message: `已更新 ${host} 的记录` }; } } catch (error) { console.error(`操作 ${host} 时出错:`, error.message); return { success: false, error: error.message }; } } async function madd(arr) { return Promise.all(arr.map((item) => this.add(item))); } /** * * @param {*} json * { type: "A", name: "starlink-sfo2", content: "146.190.127.168", "proxied": true, * } */ async function add(json) { try { let res; if (this.headers && Object.keys(this.headers).length > 0) { res = await req( `https://api.cloudflare.com/client/v4/zones/${this.zid}/dns_records post`, { json }, this.headers ); } else { res = await req( `https://api.cloudflare.com/client/v4/zones/${this.zid}/dns_records post`, { auth: this.auth, json } ); } return res.data; } catch (error) { console.error(`添加记录 ${json.name} 失败:`, error.message); throw error; } } async function mdel(arr) { return Promise.all(arr.map((item) => this.del(item))); } async function del(pre) { try { const host = pre + "." + this.domain; let res; if (this.headers && Object.keys(this.headers).length > 0) { res = await req( `https://api.cloudflare.com/client/v4/zones/${this.zid}/dns_records?type=A&name=${host}`, {}, this.headers ); } else { res = await req( `https://api.cloudflare.com/client/v4/zones/${this.zid}/dns_records?type=A&name=${host}`, { auth: this.auth } ); } const recordId = res.data.result[0]?.id; if (!recordId) { console.log(`记录 ${host} 不存在,跳过删除`); return; } if (this.headers && Object.keys(this.headers).length > 0) { res = await req( `https://api.cloudflare.com/client/v4/zones/${this.zid}/dns_records/${recordId} delete`, {}, this.headers ); } else { res = await req( `https://api.cloudflare.com/client/v4/zones/${this.zid}/dns_records/${recordId} delete`, { auth: this.auth } ); } console.log(`删除${host}: ${res.data.success ? "成功" : "失败"}`); return res.data; } catch (error) { console.error(`删除记录失败:`, error.message); throw error; } } /** * 添加安全规则 * @param {Object} options - 规则配置选项 * @param {string} options.description - 规则描述 * @param {string} options.expression - 规则表达式 * @param {string} options.action - 规则触发的动作,如 "managed_challenge", "block", "js_challenge" 等 * @param {number} options.priority - 规则优先级,数字越大优先级越低 * @returns {Promise<Object>} - 返回 API 响应结果 */ async function setSecurity(options = {}) { try { const { description = "安全规则", expression = "", action = "managed_challenge", priority = 999, } = options; let existingRule = null; let listResponse; if (this.headers && Object.keys(this.headers).length > 0) { listResponse = await req( `https://api.cloudflare.com/client/v4/zones/${this.zid}/firewall/rules`, {}, this.headers ); } else { listResponse = await req( `https://api.cloudflare.com/client/v4/zones/${this.zid}/firewall/rules`, { auth: this.auth } ); } if (listResponse.data.success && listResponse.data.result.length > 0) { existingRule = listResponse.data.result.find( (rule) => rule.description === description ); } let response; if (existingRule) { const filterId = existingRule.filter.id; let filterUpdateResponse; if (this.headers && Object.keys(this.headers).length > 0) { filterUpdateResponse = await req( `https://api.cloudflare.com/client/v4/zones/${this.zid}/filters/${filterId} put`, { json: { expression: expression, paused: false } }, this.headers ); } else { filterUpdateResponse = await req( `https://api.cloudflare.com/client/v4/zones/${this.zid}/filters/${filterId} put`, { auth: this.auth, json: { expression: expression, paused: false } } ); } if (!filterUpdateResponse.data.success) { throw new Error( `更新过滤器失败: ${JSON.stringify(filterUpdateResponse.data.errors)}` ); } if (this.headers && Object.keys(this.headers).length > 0) { response = await req( `https://api.cloudflare.com/client/v4/zones/${this.zid}/firewall/rules/${existingRule.id} put`, { json: { action: action, priority: priority, paused: false, description: description, filter: { id: filterId, }, }, }, this.headers ); } else { response = await req( `https://api.cloudflare.com/client/v4/zones/${this.zid}/firewall/rules/${existingRule.id} put`, { auth: this.auth, json: { action: action, priority: priority, paused: false, description: description, filter: { id: filterId, }, }, } ); } if (response.data.success) { console.log(`安全规则 "${description}" 更新成功!`); return response.data.result; } else { console.error("更新安全规则失败:", response.data.errors); throw new Error(JSON.stringify(response.data.errors)); } } else { console.log(`未找到安全规则 "${description}",准备创建...`); const requestBody = [ { filter: { expression: expression, paused: false, }, action: action, priority: priority, paused: false, description: description, }, ]; if (this.headers && Object.keys(this.headers).length > 0) { response = await req( `https://api.cloudflare.com/client/v4/zones/${this.zid}/firewall/rules post`, { json: requestBody }, this.headers ); } else { response = await req( `https://api.cloudflare.com/client/v4/zones/${this.zid}/firewall/rules post`, { auth: this.auth, json: requestBody } ); } if (response.data.success) { console.log(`安全规则 "${description}" 创建成功!`); return response.data.result[0]; } else { console.error("创建安全规则失败:", response.data.errors); throw new Error(JSON.stringify(response.data.errors)); } } } catch (error) { console.error("设置安全规则时出错:", error.message); throw error; } }