@@ -1,434 +1,728 @@
export default {
async fetch ( request , env , ctx ) {
async fetch ( request , env , ctx ) {
const url = new URL ( request . url ) ;
// 处理 API 请求
if ( url . pathname === '/api/add-ssl' && request . method === 'POST' ) {
return handleApiRequest ( request ) ;
// 处理 API 请求:支持 POST (/api/add-ssl) 和 GET (/?...)
if (
( url . pathname === '/api/add-ssl' && request . method === 'POST' ) ||
( url . pathname === '/' && request . method === 'GET' && url . searchParams . has ( 'zoneId' ) )
) {
return handleApiRequest ( request , url . searchParams ) ;
}
// 返回 HTML 页面
// 返回 HTML 页面 (仅当是根路径的 GET 请求且没有API参数时)
return new Response ( getHTML ( ) , {
headers : {
'Content-Type' : 'text/html; charset=utf-8' ,
} ,
headers : {
'Content-Type' : 'text/html; charset=utf-8' ,
} ,
} ) ;
} ,
} ;
async function handleApiRequest ( request ) {
try {
const { email, zone_id, api_key } = await request . json ( ) ;
// 验证输入
} ,
} ;
// 统一处理 API 请求(支持 POST Body 和 GET Query Params)
async function handleApiRequest ( request , queryParams ) {
let email , zone_id , api_key , enabled , certificate_authority ;
try {
if ( request . method === 'POST' ) {
// POST 请求:从请求体中解析 JSON
const body = await request . json ( ) ;
email = body . email ;
zone_id = body . zoneId ;
api_key = body . apikey ;
enabled = body . enabled !== undefined ? body . enabled : true ;
certificate_authority = body . ca || "ssl_com" ;
} else if ( request . method === 'GET' ) {
// GET 请求:从 URL 查询参数中获取
email = queryParams . get ( 'email' ) ;
zone_id = queryParams . get ( 'zoneId' ) ;
api_key = queryParams . get ( 'apikey' ) ;
enabled = ! ( queryParams . get ( 'enabled' ) === 'false' ) ;
certificate_authority = queryParams . get ( 'ca' ) || "ssl_com" ;
}
// 验证必需的输入
if ( ! email || ! zone_id || ! api_key ) {
return new Response ( JSON . stringify ( {
success : false ,
errors : [ '所有字段都是必需的' ]
} ) , {
status : 400 ,
headers : { 'Content-Type' : 'application/json' }
} ) ;
return new Response ( JSON . stringify ( {
success : false ,
errors : [ '邮箱、区域ID和API密钥都是必需的' ]
} ) , {
status : 400 ,
headers : {
'Content-Type' : 'application/json' ,
'Access-Control-Allow-Origin' : '*' ,
}
} ) ;
}
// 验证并设置 CA 默认值
const validCAs = [ "ssl_com" , "lets_encrypt" , "google" , "sectigo" ] ;
const caToUse = validCAs . includes ( certificate_authority ) ? certificate_authority : "ssl_com" ;
// 调用 Cloudflare API
const response = await fetch ( `https://api.cloudflare.com/client/v4/zones/${ zone_id } /ssl/universal/settings` , {
method : 'PATCH' ,
headers : {
'X-Auth-Email' : email ,
'X-Auth-Key' : api_key ,
'Content-Type' : 'application/json' ,
} ,
body : JSON . stringify ( {
enabled : true ,
certificate_authority : "ssl_com"
} ) ,
method : 'PATCH' ,
headers : {
'X-Auth-Email' : email ,
'X-Auth-Key' : api_key ,
'Content-Type' : 'application/json' ,
} ,
body : JSON . stringify ( {
enabled : enabled ,
certificate_authority : caToUse
} ) ,
} ) ;
const result = await response . json ( ) ;
// 为 API 调用返回 JSON 响应
return new Response ( JSON . stringify ( result ) , {
headers : {
'Content-Type' : 'application/json' ,
'Access-Control-Allow-Origin' : '*' ,
'Access-Control-Allow-Methods' : 'POST' ,
'Access-Control-Allow-Headers' : 'Content-Type' ,
} ,
headers : {
'Content-Type' : 'application/json' ,
'Access-Control-Allow-Origin' : '*' ,
'Access-Control-Allow-Methods' : 'GET, POST' ,
'Access-Control-Allow-Headers' : 'Content-Type' ,
} ,
} ) ;
} catch ( error ) {
} catch ( error ) {
return new Response ( JSON . stringify ( {
success : false ,
errors : [ `请求失败: ${ error . message } ` ]
success : false ,
errors : [ { message : `请求失败: ${ error . message || '未知错误' } ` } ]
} ) , {
status : 500 ,
headers : {
'Content-Type' : 'application/json' ,
'Access-Control-Allow-Origin' : '*' ,
}
status : 500 ,
headers : {
'Content-Type' : 'application/json' ,
'Access-Control-Allow-Origin' : '*' ,
}
} ) ;
}
}
function getHTML ( ) {
return `<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>IP6.ARPA域名自动添加SSL证书</title>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
body {
background: linear-gradient(135deg, #1a2a6c, #b21f1f, #fdbb2d);
color: #333;
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
padding: 10px;
}
.container {
background-color: rgba(255, 255, 255, 0.95);
border-radius: 12px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
width: 100%;
max-width: 500px;
padding: 30px;
}
h1 {
text-align: center;
margin-bottom: 25px;
color: #2c3e50;
font-size: 24px;
position: relative;
padding-bottom: 15px;
}
h1:after {
content: '';
position: absolute;
bottom: 0;
left: 25%;
width: 50%;
height: 3px;
background: linear-gradient(to right, #1a2a6c, #b21f1f, #fdbb2d);
border-radius: 3px;
}
.register-btn {
display: block;
background: linear-gradient(to right, #1a2a6c, #3498db);
color: white;
text-align: center;
text-decoration: none;
border-radius: 8px;
padding: 14px 20px;
font-size: 16px;
font-weight: 600;
margin-bottom: 25px;
transition: all 0.3s;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
.register-btn:hover {
transform: translateY(-2px);
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.15);
}
.form-group {
margin-bottom: 20px;
}
label {
display: block;
margin-bottom: 8px;
font-weight: 600;
color: #2c3e50;
}
input[type="text"], input[type="email"] {
width: 100%;
padding: 12px 15px;
border: 2px solid #e0e0e0;
border-radius: 8px;
font-size: 16px;
transition: all 0.3s;
}
input[type="text"]:focus, input[type="email"]:focus {
border-color: #3498db;
box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.2);
outline: none;
}
.error {
border-color: #e74c3c !important;
box-shadow: 0 0 0 3px rgba(231, 76, 60, 0.2) !important;
}
.error-message {
color: #e74c3c;
font-size: 14px;
margin-top: 5px;
display: none;
}
.btn {
background: linear-gradient(to right, #1a2a6c, #b21f1f);
color: white;
border: none;
border-radius: 8px;
padding: 14px 20px;
font-size: 16px;
font-weight: 600;
cursor: pointer;
width: 100%;
transition: all 0.3s;
display: flex;
justify-content: center;
align-items: center;
}
.btn:hover {
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);
}
.btn:active {
transform: translateY(0);
}
.spinner {
display: none;
width: 20px;
height: 20px;
border: 3px solid rgba(255, 255, 255, 0.3);
border-radius: 50%;
border-top-color: white;
animation: spin 1s ease-in-out infinite;
margin-right: 10px;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
}
// getHTML 函数保持不变,因为前端表单仍然使用 POST 请求
function getHTML ( ) {
return `<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>IP6.ARPA域名自动添加SSL证书</title>
<meta name="description" content="一键为您的 IP6.ARPA 反向解析域名自动申请和配置 Cloudflare 通用 SSL 证书,同时提供 IP6.ARPA 域名生成工具。">
<link rel="icon" href="https://tunnelbroker.net/favicon.ico" type="image/ico">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css" crossorigin="anonymous" referrerpolicy="no-referrer" />
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
body {
background: linear-gradient(135deg, #1a2a6c, #b21f1f, #fdbb2d);
color: #333;
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
padding: 10px;
}
.container {
background: rgba(255, 255, 255, 0.3);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
border-radius: 12px;
box-shadow: 8px 8px 15px rgba(0, 0, 0, 0.15);
width: 100%;
max-width: 840px;
padding: 30px;
margin: 30px;
}
h1 {
text-align: center;
margin-bottom: 25px;
color: #e58d1dd9;
font-size: 36px;
position: relative;
padding-bottom: 15px;
text-shadow: 1px 1px 3px rgba(0, 0, 0, 0.7);
}
/* CSS for two-column layout */
.form-row {
display: flex;
justify-content: space-between;
gap: 20px;
margin-bottom: 20px;
}
.form-group.half-width {
flex: 1;
margin-bottom: 0;
}
.ca-select-style {
width: 100%;
padding: 12px 15px;
border: 2px solid #e0e0e0;
border-radius: 8px;
font-size: 16px;
transition: all 0.3s;
}
.ca-select-style:focus {
border-color: #3498db;
box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.2);
outline: none;
}
.registration-buttons {
display: flex;
justify-content: space-between;
gap: 15px;
margin-bottom: 25px;
}
.register-btn {
flex: 1;
display: block;
background: #1163c2;
color: white;
text-align: center;
text-decoration: none;
border-radius: 8px;
padding: 10px 15px;
font-size: 16px;
font-weight: 600;
transition: all 0.3s;
box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.15);
}
.register-btn:hover {
transform: translateY(-2px);
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.15);
}
.form-group {
margin-bottom: 20px;
}
label {
display: block;
margin-bottom: 8px;
font-weight: 600;
color: #2c3e50;
}
input[type="text"],
input[type="email"],
textarea,
.ca-select-style {
width: 100%;
padding: 12px 15px;
background: rgba(255, 255, 255, 0.35);
backdrop-filter: blur(5px);
-webkit-backdrop-filter: blur(5px);
border: 1px solid rgba(255, 255, 255, 0.4);
border-radius: 8px;
font-size: 16px;
color: #2c3e50;
transition: all 0.3s;
resize: none;
}
.ca-select-style {
height: 48px;
}
input[type="text"]:focus,
input[type="email"]:focus,
textarea:focus,
.ca-select-style:focus {
border-color: #3498db;
box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.2);
outline: none;
background: rgba(255, 255, 255, 0.5);
}
.error {
border-color: #e74c3c !important;
box-shadow: 0 0 0 3px rgba(231, 76, 60, 0.2) !important;
}
.error-message {
color: #e74c3c;
font-size: 14px;
margin-top: 5px;
display: none;
}
.btn {
background: linear-gradient(to right, #1a2a6c, #b21f1f);
color: white;
border: none;
border-radius: 8px;
padding: 14px 20px;
font-size: 16px;
font-weight: 600;
cursor: pointer;
width: 100%;
transition: all 0.3s;
display: flex;
justify-content: center;
align-items: center;
box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.15);
}
.info-box .btn#generate-btn { margin-top: 15px; }
.info-box .btn#generate-btn i { position: relative; top: 1px; }
.btn:hover {
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);
}
.btn:active {
transform: translateY(0);
}
.spinner {
display: none;
width: 20px;
height: 20px;
border: 3px solid rgba(255, 255, 255, 0.3);
border-radius: 50%;
border-top-color: white;
animation: spin 1s ease-in-out infinite;
margin-right: 10px;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
.result {
margin-top: 20px;
padding: 15px;
border-radius: 8px;
display: none;
text-align: center;
font-weight: 600;
}
.success {
background-color: #d4edda;
color: #155724;
border: 1px solid #c3e6cb;
}
.error-result {
background-color: #f8d7da;
color: #721c24;
border: 1px solid #f5c6cb;
}
.info-box {
background: rgba(255, 255, 255, 0.35);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
border-left: 4px solid #db6034;
padding: 15px;
margin-top: 25px;
border-radius: 8px;
}
.info-box h2 {
color: #2c3e50;
margin-bottom: 10px;
font-size: 20px;
}
.info-box p {
font-size: 14px;
line-height: 1.5;
color: #34495e;
}
.footer {
text-align: center;
margin-top: 20px;
font-size: 14px;
color: #444;
}
.footer a {
color: inherit;
text-decoration: none;
transition: color 0.3s;
}
.footer a:hover {
color: #3498db;
}
.separator {
padding: 0 5px;
color: inherit;
display: inline-block;
}
/* 响应式调整:在小屏幕上变回单列布局 */
@media (max-width: 600px) {
.form-row { flex-direction: column; gap: 0; }
.form-group.half-width { margin-bottom: 20px; }
.footer { font-size: 0.8em; }
}
</style>
</head>
<body>
<div class="container">
<h1>IP6.ARPA域名自动添加SSL证书</h1>
<div class="registration-buttons">
<a href="https://tb.netassist.ua" class="register-btn" target="_blank"><i class="fas fa-registered"></i> ip6.arpa 注册地址1(已崩)</a>
<a href="https://dns.he.net" class="register-btn" target="_blank"><i class="fas fa-registered"></i> ip6.arpa 注册地址2</a>
<a href="https://tunnelbroker.net/" class="register-btn" target="_blank"><i class="fas fa-registered"></i> ip6.arpa 注册地址3</a>
</div>
<form id="ssl-form">
<div class="form-row">
<div class="form-group half-width">
<label for="email"><i class="fas fa-envelope"></i> Cloudflare注册邮箱 (Email)</label>
<input type="email" id="email" placeholder="请输入您的Cloudflare邮箱">
<div class="error-message" id="email-error">请输入有效的邮箱地址</div>
</div>
.result {
margin-top: 20px;
padding: 15px;
border-radius: 8px;
display: none;
text-align: center;
font-weight: 600;
}
<div class="form-group half-width">
<label for="zone-id"><i class="fas fa-id-card"></i> 区域ID (Zone ID)</label>
<input type="text" id="zone-id" placeholder="请输入您的区域ID">
<div class="error-message" id="zone-id-error">请输入区域ID</div>
</div>
</div>
<div class="form-row">
<div class="form-group half-width">
<label for="api-key"><i class="fas fa-key"></i> 全局API密钥 (API Key)</label>
<input type="text" id="api-key" placeholder="请输入您的API密钥">
<div class="error-message" id="api-key-error">请输入API密钥</div>
</div>
.success {
background-color: #d4edda;
color: #155724;
border: 1px solid #c3e6cb;
<div class="form-group half-width">
<label for="ca-select"><i class="fas fa-landmark"></i> CA证书颁发机构</label>
<select id="ca-select" class="ca-select-style">
<option value="ssl_com">SSL.com (默认)</option>
<option value="lets_encrypt">Let's Encrypt</option>
<option value="google">Google Trust Services</option>
<option value="sectigo">Sectigo</option>
</select>
</div>
</div>
<button type="submit" class="btn" id="submit-btn">
<div class="spinner" id="spinner"></div>
<span id="btn-text"><i class="fas fa-plus-circle"></i> 添加 SSL 证书</span>
</button>
</form>
<div class="result" id="result-message"></div>
<div class="info-box">
<h2>IP6.ARPA 域名生成工具</h2>
<div class="form-row" style="margin-top: 15px;">
<div class="form-group half-width">
<label for="ipv6-cidr"><i class="fas fa-network-wired"></i> 输入 IPv6 CIDR 地址</label>
<input type="text" id="ipv6-cidr" placeholder="请输入 IPv6 CIDR, 例如: 2001:DB8::/48">
<div class="error-message" id="ipv6-cidr-error">请输入有效的 IPv6 CIDR</div>
<button type="button" class="btn" id="generate-btn"><i class="fas fa-sync-alt"></i> 生成 IP6.ARPA 域名</button>
</div>
<div class="form-group half-width">
<label for="generated-domain"><i class="fas fa-check-circle"></i> IP6.ARPA 域名生成结果</label>
<textarea id="generated-domain" readonly rows="4" placeholder="生成结果将显示在这里"></textarea>
</div>
</div>
</div>
<div class="info-box">
<h2>API GET 调用示例</h2>
<p style="font-size: 14px; margin-bottom: 10px;">证书颁发机构 (ca) 支持:<code>ssl_com</code>、<code>lets_encrypt</code>、<code>google</code>、<code>sectigo</code>。<strong>注意:ip6.arpa 域名通常仅支持 <code>ssl_com</code>。</strong></p>
<pre style="background: rgba(255, 255, 255, 0.7); padding: 10px; border-radius: 6px; font-size: 14px; overflow-x: auto; color: #000;">https://worker地址/?zoneId=...&email=...&apikey=...&enabled=true&ca=ssl_com</pre>
</div>
<div class="footer">
<i class="fas fa-copyright"></i> Copyright 2025 <span class="separator">|</span>
<a href="https://gist.github.com/eooce/d3549e80a67dd39e47a55f81bae6b802" target="_blank"><i class="fab fa-github"></i> GitHub源代码</a> <span class="separator">|</span>
<a href="https://t.me/eooceu" target="_blank"><i class="fas fa-telegram"></i> telegram群组</a>
<p style="margin-top: 10px;">此站点中api key仅用于请求,不记录,如有疑问,可自行在cloudflare workers部署</p>
</div>
</div>
<script>
// ==========================================================
// 域名生成逻辑 (支持随机子域名生成)
// ==========================================================
// 辅助函数:将缩写的 IPv6 地址展开为完整的 32 位十六进制字符串
function expandIpv6(ipv6) {
ipv6 = ipv6.toLowerCase();
// 检查是否有 '::' 缩写
if (!ipv6.includes('::')) {
return ipv6.split(':').map((block) => block.padStart(4, '0')).join('');
}
const parts = ipv6.split('::');
const leftBlocks = parts[0].split(':').filter(Boolean);
const rightBlocks = parts[1].split(':').filter(Boolean);
const existingBlocksCount = leftBlocks.length + rightBlocks.length;
const zeroBlocksCount = 8 - existingBlocksCount;
if (zeroBlocksCount < 0) {
throw new Error('IPv6 地址块过多,格式错误。');
}
const zeroPadding = Array(zeroBlocksCount).fill('0000').join('');
// 填充左侧和右侧的块,然后合并
const fullLeft = leftBlocks.map((block) => block.padStart(4, '0')).join('');
const fullRight = rightBlocks.map((block) => block.padStart(4, '0')).join('');
return fullLeft + zeroPadding + fullRight;
}
// 辅助函数:生成指定长度的随机十六进制字符串
function randomHex(length) {
let result = '';
const characters = '0123456789abcdef';
for (let i = 0; i < length; i++) {
result += characters.charAt(Math.floor(Math.random() * characters.length));
}
return result;
}
// 生成 ipv6 反向根域名
function generateArpaRootDomain(cidr) {
const parts = cidr.split('/');
if (parts.length !== 2) {
throw new Error('CIDR 格式不正确,请使用 IP/前缀长度 格式。');
}
const ipv6 = parts[0].trim();
const prefixLength = parseInt(parts[1], 10);
if (isNaN(prefixLength) || prefixLength < 0 || prefixLength > 128 || prefixLength % 4 !== 0) {
throw new Error('前缀长度无效,必须是 4 的倍数 (例如: /32, /48, /64)。');
}
const fullHex = expandIpv6(ipv6); // 获取完整的 32 字符十六进制地址
const hexCharsInPrefix = prefixLength / 4; // 截取固定的网络前缀部分
const networkPrefix = fullHex.substring(0, hexCharsInPrefix);
const reversed = networkPrefix.split('').reverse().join('.'); // 反转并用 '.' 分隔
return reversed + '.ip6.arpa'; // 拼接后缀
}
// 生成随机前缀域名
function generateRandomPrefixDomains(baseArpaDomain) {
const domains = [baseArpaDomain]; // 根域名
for (let i = 0; i < 3; i++) {
// 生成 1 到 4 位长的随机十六进制字符串
const randomLength = Math.floor(Math.random() * 4) + 1; // 1 to 4
const prefix = randomHex(randomLength).split('').join('.');
domains.push(prefix + '.' + baseArpaDomain);
}
return domains;
}
// ==========================================================
// DOM 交互逻辑
// ==========================================================
// 辅助函数:从本地存储加载 CIDR
function loadSavedCidr() {
const savedCidr = localStorage.getItem('ipv6Cidr');
if (savedCidr) {
document.getElementById('ipv6-cidr').value = savedCidr;
}
}
// 辅助函数:保存 CIDR 到本地存储
function saveCidr(cidr) {
localStorage.setItem('ipv6Cidr', cidr);
}
// 辅助函数:显示字段错误
function showError(fieldId, message) {
const field = document.getElementById(fieldId);
const errorElement = document.getElementById(fieldId + '-error');
field.classList.add('error');
errorElement.textContent = message;
errorElement.style.display = 'block';
if (!document.querySelector('.error:focus')) {
field.focus();
}
}
// 辅助函数:重置所有错误状态
function resetErrors() {
const errorFields = document.querySelectorAll('.error');
const errorMessages = document.querySelectorAll('.error-message');
errorFields.forEach((field) => {
field.classList.remove('error');
});
errorMessages.forEach((message) => {
message.style.display = 'none';
});
}
// 辅助函数:显示操作结果
function showResult(message, type) {
const resultElement = document.getElementById('result-message');
resultElement.textContent = message;
resultElement.className = 'result';
resultElement.classList.add(type === 'success' ? 'success' : 'error-result');
resultElement.style.display = 'block';
resultElement.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
}
// 辅助函数:执行复制操作 (仅使用 Clipboard API)
async function copyTextToClipboard(text) {
if (navigator.clipboard && navigator.clipboard.writeText) {
try {
await navigator.clipboard.writeText(text);
return true;
} catch (err) {
console.warn('Clipboard API 复制失败或权限被拒绝:', err);
return false;
}
.error-result {
background-color: #f8d7da;
color: #721c24;
border: 1px solid #f5c6cb;
} else {
console.warn('浏览器不支持 navigator.clipboard API。');
return false;
}
}
// ==========================================================
// 页面初始化和事件监听
// ==========================================================
document.addEventListener('DOMContentLoaded', function () {
// 1. 加载保存的 CIDR
loadSavedCidr();
// 2. 监听 CIDR 输入,实时保存
document.getElementById('ipv6-cidr').addEventListener('input', function (e) {
saveCidr(e.target.value.trim());
});
// 3. 事件监听: IPv6 域名生成 (调用随机生成函数)
document.getElementById('generate-btn').addEventListener('click', async function () {
resetErrors();
const cidrInput = document.getElementById('ipv6-cidr');
const domainOutput = document.getElementById('generated-domain');
const cidr = cidrInput.value.trim();
domainOutput.value = '';
if (!cidr) {
showError('ipv6-cidr', '请输入 IPv6 CIDR 地址。');
return;
}
.info-box {
background-color: #e8f4fd;
border-left: 4px solid #3498db;
padding: 15px;
margin-top: 25px;
border-radius: 0 8px 8px 0;
try {
const rootDomain = generateArpaRootDomain(cidr); // 生成 ARPA 根域名
const generatedDomains = generateRandomPrefixDomains(rootDomain); // 生成包含根域名和随机前缀的 4 个域名列表
const resultText = generatedDomains.join('\\n'); // 将所有域名格式化成多行文本
domainOutput.value = resultText; // 将所有 4 个域名赋值给 textarea
const copySuccess = await copyTextToClipboard(resultText); // 复制操作 (复制所有 4 个域名)
let resultMessage = 'IP6.ARPA 域名生成成功!共生成 4 个域名。';
if (copySuccess) {
resultMessage += '所有域名已自动复制到剪贴板。';
} else {
resultMessage += '自动复制失败,请手动复制文本框中的内容。';
}
showResult(resultMessage, 'success');
console.log("生成的 4 个域名:\\n" + resultText);
} catch (error) {
showError('ipv6-cidr', error.message || '生成域名失败, 请检查CIDR格式。');
showResult('生成失败: ' + (error.message || '未知错误'), 'error');
}
.info-box h3 {
color: #2c3e50;
margin-bottom: 10px;
font-size: 16px;
});
// 4. 事件监听: Cloudflare SSL 提交
document.getElementById('ssl-form').addEventListener('submit', async function (e) {
e.preventDefault();
// 获取输入值
const email = document.getElementById('email').value.trim();
const zoneId = document.getElementById('zone-id').value.trim();
const apikey = document.getElementById('api-key').value.trim();
const caSelect = document.getElementById('ca-select').value;
// 重置错误状态
resetErrors();
// 验证输入
let isValid = true;
if (!email) {
showError('email', '请输入有效的邮箱地址');
isValid = false;
}
.info-box p {
font-size: 14px;
line-height: 1.5;
color: #34495e;
if (!zoneId) {
showError('zone-id', '请输入区域ID');
isValid = false;
}
.footer {
text-align: center;
margin-top: 20px;
font-size: 12px;
color: #7f8c8d;
if (!apikey) {
showError('api-key', '请输入API密钥');
isValid = false;
}
</style>
</head>
<body>
<div class="container">
<h1>IP6.ARPA域名自动添加SSL证书</h1>
<a href="https://tb.netassist.ua" class="register-btn" target="_blank">注册ip6.arpa域名</a>
<form id="ssl-form">
<div class="form-group">
<label for="email">Cloudflare注册邮箱 (Email)</label>
<input type="email" id="email" placeholder="请输入您的Cloudflare邮箱">
<div class="error-message" id="email-error">请输入有效的邮箱地址</div>
</div>
<div class="form-group">
<label for="zone-id">区域ID (Zone ID)</label>
<input type="text" id="zone-id" placeholder="请输入您的区域ID">
<div class="error-message" id="zone-id-error">请输入区域ID</div>
</div>
<div class="form-group">
<label for="api-key">全局API密钥 (API Key)</label>
<input type="text" id="api-key" placeholder="请输入您的API密钥">
<div class="error-message" id="api-key-error">请输入API密钥</div>
</div>
<button type="submit" class="btn" id="submit-btn">
<div class="spinner" id="spinner"></div>
<span id="btn-text">添加SSL证书</span>
</button>
</form>
<div class="result" id="result-message"></div>
<div class="info-box">
<h3>使用说明</h3>
<p>1. 请确保您输入的Cloudflare账户信息正确</p>
<p>2. 请确保您的ip6.arpa域名已在cloudflare激活状态再添加</p>
<p>3. 添加成功后,请等待10分钟,然后在域名菜单检查SSL/TLS证书</p>
<p>4. 此工具使用Cloudflare API为您的IP6.ARPA域名添加SSL证书</p>
</div>
<div class="footer">
<p>注意:您的API密钥仅用于本次请求,不会被存储</p>
</div>
</div>
<script>
document.getElementById('ssl-form').addEventListener('submit', async function(e) {
e.preventDefault();
// 获取输入值
const email = document.getElementById('email').value.trim();
const zoneId = document.getElementById('zone-id').value.trim();
const apiKey = document.getElementById('api-key').value.trim();
// 重置错误状态
resetErrors();
// 验证输入
let isValid = true;
if (!email) {
showError('email', '请输入有效的邮箱地址');
isValid = false;
}
if (!zoneId) {
showError('zone-id', '请输入区域ID');
isValid = false;
}
if (!apiKey) {
showError('api-key', '请输入API密钥');
isValid = false;
}
if (!isValid) return;
// 显示加载状态
document.getElementById('spinner').style.display = 'block';
document.getElementById('btn-text').textContent = '添加中...';
document.getElementById('submit-btn').disabled = true;
try {
// 发送请求到 Worker API
const response = await fetch('/api/add-ssl', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: email,
zone_id: zoneId,
api_key: apiKey
})
});
const data = await response.json();
// 显示结果
if (data.success) {
showResult('证书添加成功,请10分钟后在Cloudflare该域名里检查SSL/TLS证书', 'success');
} else {
let errorMsg = '添加证书失败';
if (data.errors && data.errors.length > 0) {
errorMsg += ': ' + data.errors[0].message;
}
showResult(errorMsg, 'error');
if (!isValid) return;
// 显示加载状态
document.getElementById('spinner').style.display = 'block';
document.getElementById('btn-text').textContent = '添加中...';
document.getElementById('submit-btn').disabled = true;
try {
// 发送请求到 Worker API
const response = await fetch('/api/add-ssl', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: email,
zoneId: zoneId,
apikey: apikey,
enabled: true,
ca: caSelect,
}),
});
const data = await response.json();
// 显示结果
if (data.success) {
showResult('证书添加成功, 请10分钟后在Cloudflare该域名里检查SSL/TLS证书', 'success');
} else {
let errorMsg = '添加证书失败';
if (data.errors && data.errors.length > 0) {
errorMsg += ': ' + (data.errors[0].message || JSON.stringify(data.errors[0]));
} else if (data.errors) {
errorMsg += ': ' + JSON.stringify(data.errors);
}
} catch (error) {
showResult('请求失败,请检查网络连接', 'error');
console.error('Error:', error);
} finally {
// 隐藏加载状态
document.getElementById('spinner').style.display = 'none';
document.getElementById('btn-text').textContent = '添加SSL证书';
document.getElementById('submit-btn').disabled = false;
showResult(errorMsg, 'error');
}
});
function showError(fieldId, message) {
const field = document.getElementById(fieldId);
const errorElement = document.getElementById(\`\${fieldId}-error\`);
field.classList.add('error');
errorElement.textContent = message;
errorElement.style.display = 'block';
// 聚焦到第一个错误字段
if (!document.querySelector('.error:focus')) {
field.focus();
}
}
function resetErrors() {
const errorFields = document.querySelectorAll('.error');
const errorMessages = document.querySelectorAll('.error-message');
errorFields.forEach(field => {
field.classList.remove('error');
});
errorMessages.forEach(message => {
message.style.display = 'none';
});
}
function showResult(message, type) {
const resultElement = document.getElementById('result-message');
resultElement.textContent = message;
resultElement.className = 'result';
resultElement.classList.add(type === 'success' ? 'success' : 'error-result');
resultElement.style.display = 'block';
// 滚动到结果
resultElement.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
} catch (error) {
showResult('请求失败,请检查网络连接', 'error');
console.error('Error:', error);
} finally {
// 隐藏加载状态
document.getElementById('spinner').style.display = 'none';
document.getElementById('btn-text').textContent = '添加SSL证书';
document.getElementById('submit-btn').disabled = false;
}
</script>
</body>
</html>` ;
}
});
});
</script>
</body>
</html>` ;
}