refactor: 邮件模板语言专业化 + 新增V3订阅邮件 + 带宽授权域名切换guanghulab.online

Agent-Logs-Url: https://github.com/qinfendebingshuo/guanghulab/sessions/5deef078-5765-44a5-b9bf-03476c0fddce

Co-authored-by: qinfendebingshuo <207279273+qinfendebingshuo@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot] 2026-04-06 10:18:51 +00:00 committed by GitHub
parent d159ae2a42
commit eab7e2057e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 230 additions and 31 deletions

View File

@ -17,6 +17,7 @@
// 6. 带宽共享验证码 — 发送6位验证码 (∞+1·含VPN系统介绍)
// 7. 风险提示通知 — 全体用户风险提醒 (∞+1)
// 8. 安全恢复通知 — 危机解除后全体通知 (∞+1)
// 9. V3订阅链接 — 含系统介绍 + 带宽共享邀请 (∞+1)
//
// 所有邮件底部附「意见反馈」链接
//
@ -31,6 +32,7 @@
// node email-hub.js bandwidth-auth-all — 一键发送带宽验证码 (全部用户·∞+1)
// node email-hub.js threat-alert <msg> — 全体用户风险提示 (∞+1)
// node email-hub.js threat-cleared — 全体用户安全恢复通知 (∞+1)
// node email-hub.js send-subscription-v3 <email> — 发送V3订阅链接 (含系统介绍+带宽共享邀请)
// node email-hub.js list-emails — 列出所有启用用户的邮箱
//
// 运行方式: CLI调用 (由auto-evolution.js调度)
@ -50,6 +52,11 @@ const POOL_STATUS_FILE = path.join(DATA_DIR, 'pool-quota-status.json');
const EMAIL_LOG_FILE = path.join(DATA_DIR, 'email-hub-log.json');
const RELEASE_NOTES_FILE = path.join(__dirname, '../config/release-notes.json');
// ── 带宽授权页面域名 ─────────────────────────
// QQ邮箱拦截guanghulab.com域名链接使用guanghulab.online桥接
// guanghulab.online通过Nginx反向代理桥接到大脑服务器V3订阅服务
const BW_AUTH_HOST = process.env.ZY_BW_AUTH_HOST || 'guanghulab.online';
// ── 加载版本更新说明 ────────────────────────────
function loadReleaseNotes() {
try {
@ -607,9 +614,9 @@ function generateBandwidthAuthEmail(code, authPageUrl, config) {
<h3 class="section-heading" style="color: #1a1a2e; font-size: 16px; margin: 0 0 12px; font-weight: 600;">🔑 带宽共享加速 · 验证码授权</h3>
<p style="color: #444; line-height: 1.9; font-size: 14px; margin: 0 0 24px;">
您正在参与<strong>光湖语言世界</strong><br>
这是一项<strong>完全自愿</strong>VPN<br>
果您<strong>同意授权</strong>
本邮件为<strong>光湖语言世界</strong><br>
带宽共享为<strong>自愿参与</strong><br>
您确认授权请复制以下验证码并在授权页面提
</p>
<!-- 验证码展示区 -->
@ -628,31 +635,31 @@ function generateBandwidthAuthEmail(code, authPageUrl, config) {
<!-- 同意说明 -->
<div class="info-card" style="background: #f0faf3; border-radius: 10px; padding: 18px 20px; margin: 0 0 12px; border-left: 4px solid #28a745;">
<h4 style="color: #155724; margin: 0 0 8px; font-size: 14px; font-weight: 600;"> 同意授权 = 输入验证码</h4>
<h4 style="color: #155724; margin: 0 0 8px; font-size: 14px; font-weight: 600;"> 授权确认 · 提交验证码</h4>
<p style="color: #555; font-size: 13px; margin: 0; line-height: 1.9;">
您的多余带宽将用于加速VPN网络<br>
用的人越多系统越快您自己也会享受到加速效果
您的闲置带宽将纳入光湖语言世界加速网络<br>
参与带宽共享的用户越多全网加速效能越高您的连接速度将同步提升
</p>
</div>
<!-- 不同意说明 -->
<div class="info-card" style="background: #f8f9fa; border-radius: 10px; padding: 18px 20px; margin: 0 0 12px; border-left: 4px solid #6c757d;">
<h4 style="color: #495057; margin: 0 0 8px; font-size: 14px; font-weight: 600;"> 不同意 = 忽略此邮件即可</h4>
<h4 style="color: #495057; margin: 0 0 8px; font-size: 14px; font-weight: 600;"> 暂不参与 · 无需操作</h4>
<p style="color: #555; font-size: 13px; margin: 0; line-height: 1.9;">
完全没问题这是您的自由选择您可以继续正常使用VPN<br>
只是走系统自身带宽速度可能慢一些但也比普通VPN好太多了<br>
果以后改变主意随时可以联系我们重新发送验证码
本功能为自愿参与机制不影响您的正常服务使用<br>
未参与带宽共享的用户将通过系统默认带宽通道连接服务质量不受影响<br>
后续需要参与可通过仪表盘页面重新发起授权申请
</p>
</div>
<!-- 安全说明 -->
<div class="info-card" style="background: #fffbeb; border: 1px solid #ffc107; border-radius: 10px; padding: 16px 20px; margin: 16px 0 0;">
<p style="color: #856404; font-size: 13px; margin: 0; line-height: 1.8;">
🔒 <strong>安全说明</strong>VPN
您的IP仅用于带宽加速系统内部加密存储SHA256 + 盐值外部无法看到
若检测到任何风险系统会<strong>自动切断您的共享通道</strong>
并格式化所有共享记录就像这条路从未出现过一样
危机解除后我们会重新为您推送新的订阅链接您的隐私安全铸渊守护
🔒 <strong>安全机制说明</strong>
您的IP地址仅用于带宽加速调度系统采用 <strong>SHA256 + 盐值</strong> 访
当系统检测到安全风险时将自动执行以下保护措施
即时切断所有共享通道格式化全部共享记录确保无痕清除
风险解除后系统将自动重新分配订阅链接您的隐私安全由铸渊守护体系全程保障
</p>
</div>`;
@ -722,6 +729,108 @@ function generateThreatClearedEmail(config) {
return wrapEmailTemplate('安全恢复通知', content, config);
}
// ═══════════════════════════════════════════════
// 📧 邮件类型 9: V3订阅链接 (含系统介绍 + 带宽共享邀请)
// ═══════════════════════════════════════════════
function generateSubscriptionV3Email(subUrl, dashboardUrl, bwAuthUrl, config) {
const releaseNotes = loadReleaseNotesObj();
const vpnIntro = getVpnSystemIntroHtml(releaseNotes);
const content = `
<div class="alert-box" style="background: #d4edda; border: 1px solid #c3e6cb; border-radius: 10px; padding: 16px 20px; margin: 0 0 24px;">
<strong style="color: #155724; font-size: 15px;"> 光湖语言世界 V3 正式版 · 专属订阅</strong>
</div>
<h3 class="section-heading" style="color: #1a1a2e; font-size: 16px; margin: 0 0 12px; font-weight: 600;">📱 订阅链接</h3>
<div class="info-card" style="background: #f0f4ff; border: 1px solid #d0d8ff; border-radius: 10px; padding: 16px 20px; word-break: break-all; font-family: Consolas, Monaco, 'Courier New', monospace; font-size: 13px; margin: 0 0 8px; color: #333;">
${escapeHtml(subUrl)}
</div>
<p style="color: #999; font-size: 12px; margin: 0 0 24px;">
此链接为个人专属请勿对外分享全部用户共享 2000GB 月流量池
</p>
<h3 class="section-heading" style="color: #1a1a2e; font-size: 16px; margin: 0 0 12px; font-weight: 600;">📊 流量仪表盘</h3>
<div class="info-card" style="background: #fff8e1; border: 1px solid #ffe082; border-radius: 10px; padding: 16px 20px; word-break: break-all; font-family: Consolas, Monaco, 'Courier New', monospace; font-size: 13px; margin: 0 0 8px; color: #333;">
${escapeHtml(dashboardUrl)}
</div>
<p style="color: #999; font-size: 12px; margin: 0 0 24px;">
💡 在浏览器中打开可查看实时流量统计与节点状态
</p>
<h3 class="section-heading" style="color: #1a1a2e; font-size: 16px; margin: 0 0 16px; font-weight: 600;">📋 客户端配置指引</h3>
<div class="info-card" style="background: #fafbfc; border-radius: 10px; padding: 20px; border: 1px solid #e8eaed; margin: 0 0 24px;">
<h4 style="color: #555; margin: 0 0 8px; font-size: 14px; font-weight: 600;">🍎 iOS (Shadowrocket)</h4>
<ol style="color: #666; line-height: 2; font-size: 13px; padding-left: 20px; margin: 0 0 16px;">
<li>打开 Shadowrocket 点击右上角 <strong>+</strong></li>
<li>选择 <strong>Subscribe</strong> () </li>
<li>点击完成 选择节点 开启连接</li>
</ol>
<h4 style="color: #555; margin: 0 0 8px; font-size: 14px; font-weight: 600;">💻 Mac / Windows (Clash Verge)</h4>
<ol style="color: #666; line-height: 2; font-size: 13px; padding-left: 20px; margin: 0 0 16px;">
<li>打开 Clash Verge 点击 <strong>Profiles</strong></li>
<li>粘贴订阅链接到输入框 点击 <strong>Import</strong></li>
<li>选中新配置 开启系统代理</li>
</ol>
<h4 style="color: #555; margin: 0 0 8px; font-size: 14px; font-weight: 600;">🤖 Android (ClashMi / Clash Meta)</h4>
<ol style="color: #666; line-height: 2; font-size: 13px; padding-left: 20px; margin: 0;">
<li>打开 ClashMi <strong>Profile</strong> <strong>New Profile</strong></li>
<li>选择 <strong>URL</strong> </li>
<li>保存 选中配置 启动</li>
</ol>
</div>
${vpnIntro}
<h3 class="section-heading" style="color: #1a1a2e; font-size: 16px; margin: 0 0 12px; font-weight: 600;">📊 服务配额</h3>
<table class="data-table" role="presentation" cellpadding="0" cellspacing="0" border="0" width="100%" style="border-collapse: collapse; margin: 0 0 24px;">
<tr style="border-bottom: 1px solid #f0f2f5;">
<td style="padding: 12px 16px; color: #666; font-size: 14px; width: 40%;">月流量池</td>
<td style="padding: 12px 16px; font-weight: 600; color: #1a1a2e; font-size: 14px;">2000 GB (共享配额)</td>
</tr>
<tr style="border-bottom: 1px solid #f0f2f5; background: #fafbfc;">
<td style="padding: 12px 16px; color: #666; font-size: 14px;">重置日期</td>
<td style="padding: 12px 16px; color: #1a1a2e; font-size: 14px;">每月1日</td>
</tr>
<tr style="border-bottom: 1px solid #f0f2f5;">
<td style="padding: 12px 16px; color: #666; font-size: 14px;">传输协议</td>
<td style="padding: 12px 16px; color: #1a1a2e; font-size: 14px;">VLESS + Reality</td>
</tr>
<tr>
<td style="padding: 12px 16px; color: #666; font-size: 14px;">节点位置</td>
<td style="padding: 12px 16px; color: #1a1a2e; font-size: 14px;">🇸🇬 新加坡 (多节点)</td>
</tr>
</table>
<!-- 带宽共享邀请 -->
<div style="background: linear-gradient(135deg, #e8f4fd 0%, #f0f7ff 100%); border: 1px solid #b8daff; border-radius: 12px; padding: 20px; margin: 0 0 16px;">
<h3 style="color: #004085; font-size: 15px; margin: 0 0 12px; font-weight: 700;">🌊 带宽共享加速计划 · 自愿参与</h3>
<p style="color: #444; font-size: 13px; margin: 0 0 16px; line-height: 1.9;">
光湖语言世界支持带宽共享加速机制参与用户的闲置带宽将纳入全网加速池
提升所有用户的连接速度与稳定性此功能为<strong>自愿参与</strong>
不参与不影响正常服务使用
</p>
${bwAuthUrl ? `
<div style="text-align: center; margin: 0 0 16px;">
<a href="${bwAuthUrl}" class="action-btn" style="display: inline-block; background: linear-gradient(135deg, #667eea, #764ba2); color: white; padding: 14px 36px; border-radius: 10px; text-decoration: none; font-size: 15px; font-weight: 600; letter-spacing: 0.5px;">
🌊 前往参与带宽共享
</a>
</div>` : ''}
<p style="color: #888; font-size: 12px; margin: 0; line-height: 1.8;">
点击上方按钮进入授权页面在页面中申请验证码完成授权<br>
如暂不参与无需任何操作此邮件仅为系统通知不参与不产生任何影响
</p>
</div>
<div class="info-card" style="background: #f8f9fa; border-radius: 10px; padding: 16px 20px; margin: 0; border-left: 4px solid #667eea;">
<p style="color: #555; font-size: 13px; margin: 0; line-height: 1.8;">
🔒 <strong>安全机制说明</strong>IP SHA256 +
系统检测到风险时将自动切断共享通道并清除所有记录您的隐私安全由铸渊守护体系全程保障
</p>
</div>`;
return wrapEmailTemplate('V3 专属订阅 · 光湖语言世界', content, config);
}
// ── HTML转义 ─────────────────────────────────
function escapeHtml(str) {
return String(str)
@ -936,6 +1045,40 @@ async function sendThreatClearedEmail() {
return result;
}
/**
* 发送V3订阅链接给单个用户 (含系统介绍 + 带宽共享邀请)
* 自动从users.json查找用户token构建订阅/仪表盘/授权URL
* @param {string} email 目标邮箱
*/
async function sendSubscriptionV3Email(email) {
const config = loadConfig();
const users = getEnabledUsers();
const user = users.find(u => u.email === email);
if (!user || !user.token) {
console.error(`[邮件中枢] ❌ 用户不存在或token无效: ${email}`);
return { sent: 0, failed: 1 };
}
const host = config.server_host || 'guanghulab.com';
const subUrl = `https://${host}/api/proxy-v3/sub/${user.token}`;
const dashboardUrl = `https://${host}/api/proxy-v3/dashboard/${user.token}`;
const bwAuthUrl = `https://${BW_AUTH_HOST}/api/proxy-v3/bandwidth-auth/${user.token}`;
const html = generateSubscriptionV3Email(subUrl, dashboardUrl, bwAuthUrl, config);
try {
await sendEmail(email, '🌐 光湖语言世界 · V3专属订阅链接', html);
console.log(`[邮件中枢] ✅ V3订阅已发送: ${email}`);
logEmail('subscription-v3', email, true, null);
return { sent: 1, failed: 0 };
} catch (err) {
console.error(`[邮件中枢] ❌ V3订阅发送失败: ${err.message}`);
logEmail('subscription-v3', email, false, err.message);
return { sent: 0, failed: 1 };
}
}
/**
* 一键发送带宽共享验证码给所有用户 (+1)
* 自动提取所有启用用户邮箱为每位用户生成独立验证码并加密发送
@ -968,11 +1111,10 @@ async function sendBandwidthAuthAllEmail() {
// 为每位用户生成独立验证码
const authCode = bwPool.createAuthCode(user.email);
// 构建用户专属授权页面URL
// 构建用户专属授权页面URL (使用guanghulab.online桥接域名)
let authPageUrl;
if (user.token) {
const host = config.server_host || 'guanghulab.com';
authPageUrl = `https://${host}/api/proxy-v3/bandwidth-auth/${user.token}`;
authPageUrl = `https://${BW_AUTH_HOST}/api/proxy-v3/bandwidth-auth/${user.token}`;
}
const html = generateBandwidthAuthEmail(authCode, authPageUrl, config);
@ -1013,6 +1155,7 @@ async function main() {
console.log(' node email-hub.js bandwidth-auth-all — 一键发送带宽验证码 (全部用户·∞+1)');
console.log(' node email-hub.js threat-alert <消息> — 全体用户风险提示 (∞+1)');
console.log(' node email-hub.js threat-cleared — 全体用户安全恢复通知 (∞+1)');
console.log(' node email-hub.js send-subscription-v3 <邮箱> — V3订阅链接 (含系统介绍+带宽共享邀请)');
console.log(' node email-hub.js list-emails — 列出所有用户邮箱');
console.log('');
console.log('💡 描述支持分号分隔多条内容,自动渲染为功能清单:');
@ -1108,14 +1251,12 @@ async function main() {
const bwPool = require('./bandwidth-pool-agent');
const authCode = bwPool.createAuthCode(arg1);
// 查找用户token以构建授权页面URL
// 查找用户token以构建授权页面URL (使用guanghulab.online桥接域名)
let bwAuthPageUrl;
const bwConfig = loadConfig();
const bwUsers = getEnabledUsers();
const bwUser = bwUsers.find(u => u.email === arg1);
if (bwUser && bwUser.token) {
const bwHost = bwConfig.server_host || 'guanghulab.com';
bwAuthPageUrl = `https://${bwHost}/api/proxy-v3/bandwidth-auth/${bwUser.token}`;
bwAuthPageUrl = `https://${BW_AUTH_HOST}/api/proxy-v3/bandwidth-auth/${bwUser.token}`;
}
const result = await sendBandwidthAuthEmail(arg1, authCode, bwAuthPageUrl);
@ -1146,6 +1287,17 @@ async function main() {
break;
}
case 'send-subscription-v3': {
if (!arg1) {
console.error('❌ 请提供邮箱');
console.error('用法: node email-hub.js send-subscription-v3 <邮箱>');
process.exit(1);
}
const result = await sendSubscriptionV3Email(arg1);
console.log(`📧 V3订阅链接: ${result.sent}成功 / ${result.failed}失败`);
break;
}
default:
console.error(`❌ 未知操作: ${action}`);
process.exit(1);
@ -1164,6 +1316,7 @@ module.exports = {
sendBandwidthAuthAllEmail,
sendThreatAlertEmail,
sendThreatClearedEmail,
sendSubscriptionV3Email,
getEnabledUsers,
listUserEmails,
loadReleaseNotes,

View File

@ -1046,7 +1046,7 @@ mode: direct
<div class="card">
<h3>🔑 输入验证码</h3>
<p style="font-size: 0.88em; color: #888; margin-bottom: 12px; line-height: 1.7;">请查看您的QQ邮箱将收到的6位验证码输入以下框中</p>
<p style="font-size: 0.88em; color: #888; margin-bottom: 12px; line-height: 1.7;">请查看您的邮箱将收到的6位验证码输入以下框中如尚未收到验证码请点击下方按钮申请</p>
<form id="authForm" onsubmit="submitCode(event)">
<div class="input-group">
@ -1055,22 +1055,30 @@ mode: direct
<button type="submit" class="submit-btn" id="submitBtn">🔓 提交授权</button>
</form>
<div style="text-align: center; margin-top: 14px;">
<button onclick="requestCode()" id="requestCodeBtn" style="background: transparent; border: 1px solid #667eea; color: #667eea; padding: 10px 24px; border-radius: 8px; font-size: 0.9em; cursor: pointer; transition: all 0.3s;">
📧 申请发送验证码
</button>
</div>
<div id="codeResult" class="result"></div>
<div id="result" class="result"></div>
</div>
<div class="info-box green">
<strong> 同意授权 = 输入验证码</strong>
您的多余带宽将用于加速VPN网络用的人越多系统越快您自己也会享受到加速效果
<strong> 授权确认 · 提交验证码</strong>
您的闲置带宽将纳入光湖语言世界加速网络参与带宽共享的用户越多全网加速效能越高您的连接速度将同步提升
</div>
<div class="info-box gray">
<strong> 不同意 = 关闭此页面</strong>
完全没问题您可以继续正常使用VPN只是走我们系统的带宽速度可能慢一些但也比普通VPN好太多了无论您选择什么都不影响正常使用
<strong> 暂不参与 · 关闭此页面</strong>
本功能为自愿参与机制不影响您的正常服务使用未参与带宽共享的用户将通过系统默认带宽通道连接服务质量不受影响
</div>
<div class="info-box yellow">
<strong>🔒 安全保障</strong>
VPN是内部专用的用户都是团队自己人已经相对安全您的IP仅用于带宽加速系统内部加密存储若检测到任何风险系统会自动切断您的共享通道并格式化所有共享记录就像这条路从未出现过危机解除后会重新推送新的订阅链接您的隐私安全铸渊守护
<strong>🔒 安全机制说明</strong>
系统为内部授权用户专用所有参与者均为受邀成员您的IP地址仅用于带宽加速调度系统采用 SHA256 + 盐值 加密存储外部无法访问当系统检测到安全风险时将自动切断所有共享通道并格式化全部共享记录确保无痕清除风险解除后系统将自动重新分配订阅链接您的隐私安全由铸渊守护体系全程保障
</div>
<div class="footer">
@ -1080,6 +1088,43 @@ mode: direct
</div>
<script>
async function requestCode() {
const btn = document.getElementById('requestCodeBtn');
const codeResult = document.getElementById('codeResult');
btn.disabled = true;
btn.textContent = '⏳ 发送中...';
try {
const sendCodeUrl = window.location.pathname.replace('/bandwidth-auth/', '/bandwidth-send-code/');
const resp = await fetch(sendCodeUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({})
});
const data = await resp.json();
codeResult.style.display = 'block';
if (data.success) {
codeResult.className = 'result success';
codeResult.textContent = '✅ ' + data.message;
btn.textContent = '✅ 验证码已发送';
setTimeout(() => { btn.disabled = false; btn.textContent = '📧 重新发送验证码'; }, 60000);
} else {
codeResult.className = 'result error';
codeResult.textContent = '❌ ' + data.message;
btn.disabled = false;
btn.textContent = '📧 申请发送验证码';
}
} catch (err) {
codeResult.style.display = 'block';
codeResult.className = 'result error';
codeResult.textContent = '❌ 网络异常,请稍后重试';
btn.disabled = false;
btn.textContent = '📧 申请发送验证码';
}
}
async function submitCode(e) {
e.preventDefault();
const code = document.getElementById('codeInput').value.trim();
@ -1150,8 +1195,9 @@ async function submitCode(e) {
const emailHub = require('./email-hub');
const code = bwPool.createAuthCode(user.email);
const serverHost = getServerHost();
const authPageUrl = `https://${serverHost}/api/proxy-v3/bandwidth-auth/${token}`;
// 使用guanghulab.online桥接域名 (QQ邮箱反拦截)
const bwAuthHost = process.env.ZY_BW_AUTH_HOST || 'guanghulab.online';
const authPageUrl = `https://${bwAuthHost}/api/proxy-v3/bandwidth-auth/${token}`;
emailHub.sendBandwidthAuthEmail(user.email, code, authPageUrl).then(() => {
res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });