#!/usr/bin/env node // ═══════════════════════════════════════════════ // 🔺 Sovereign: TCS-0002∞ | Root: SYS-GLW-0001 // 📜 Copyright: 国作登字-2026-A-00037559 // ═══════════════════════════════════════════════ // server/proxy/service/send-subscription.js // 📧 铸渊专线 · 订阅链接邮件发送 // // 通过SMTP发送订阅链接到指定邮箱 // 确保敏感信息不经过公开仓库 // // 用法: // node send-subscription.js send — 发送V2订阅链接 // node send-subscription.js send-v3 — 发送V3订阅链接 // node send-subscription.js alert — 发送告警邮件 // // 环境变量: // ZY_SMTP_USER, ZY_SMTP_PASS — SMTP认证 // ZY_PROXY_SUB_TOKEN — 订阅Token // ZY_SERVER_HOST — 服务器地址 // ═══════════════════════════════════════════════ 'use strict'; const net = require('net'); const tls = require('tls'); const fs = require('fs'); const path = require('path'); const KEYS_FILE = process.env.ZY_PROXY_KEYS_FILE || '/opt/zhuyuan/proxy/.env.keys'; // ── 加载配置 ───────────────────────────────── // 优先级: 环境变量 > .env.keys文件 // 通用读取所有键值对,确保guardian/monitor等服务也能获取完整配置 function loadConfig() { const config = { smtp_user: process.env.ZY_SMTP_USER || '', smtp_pass: process.env.ZY_SMTP_PASS || '', server_host: process.env.ZY_SERVER_HOST || '', sub_token: process.env.ZY_PROXY_SUB_TOKEN || '' }; // 从.env.keys文件读取所有键值对(环境变量未设置时回退) try { const content = fs.readFileSync(KEYS_FILE, 'utf8'); for (const line of content.split('\n')) { if (line.startsWith('#') || !line.includes('=')) continue; const [key, ...vals] = line.split('='); const k = key.trim(); const v = vals.join('=').trim(); if (!v) continue; // 仅在环境变量未设置时使用文件中的值 if (k === 'ZY_PROXY_SUB_TOKEN' && !config.sub_token) config.sub_token = v; if (k === 'ZY_SERVER_HOST' && !config.server_host) config.server_host = v; if (k === 'ZY_SMTP_USER' && !config.smtp_user) config.smtp_user = v; if (k === 'ZY_SMTP_PASS' && !config.smtp_pass) config.smtp_pass = v; } } catch { /* ignore */ } return config; } // ── SMTP发送邮件 ───────────────────────────── async function sendEmail(to, subject, htmlBody) { const config = loadConfig(); if (!config.smtp_user || !config.smtp_pass) { console.error('❌ SMTP未配置 (需要ZY_SMTP_USER和ZY_SMTP_PASS)'); process.exit(1); } // 检测SMTP服务商 const smtpHost = detectSmtpHost(config.smtp_user); const smtpPort = 465; // SSL return new Promise((resolve, reject) => { const socket = tls.connect(smtpPort, smtpHost, {}, () => { let step = 0; const from = config.smtp_user; const commands = [ `EHLO zy-proxy\r\n`, `AUTH LOGIN\r\n`, `${Buffer.from(from).toString('base64')}\r\n`, `${Buffer.from(config.smtp_pass).toString('base64')}\r\n`, `MAIL FROM:<${from}>\r\n`, `RCPT TO:<${to}>\r\n`, `DATA\r\n`, `From: "铸渊专线" <${from}>\r\nTo: <${to}>\r\nSubject: =?UTF-8?B?${Buffer.from(subject).toString('base64')}?=\r\nContent-Type: text/html; charset=utf-8\r\nMIME-Version: 1.0\r\n\r\n${htmlBody}\r\n.\r\n`, `QUIT\r\n` ]; socket.on('data', (data) => { const response = data.toString(); if (step < commands.length) { socket.write(commands[step]); step++; } if (response.startsWith('250 ') && step >= commands.length) { resolve(true); } }); socket.on('error', (err) => { reject(err); }); }); socket.on('error', (err) => { reject(err); }); }); } // ── 检测SMTP主机 ───────────────────────────── function detectSmtpHost(email) { if (email.includes('@qq.com')) return 'smtp.qq.com'; if (email.includes('@163.com')) return 'smtp.163.com'; if (email.includes('@126.com')) return 'smtp.126.com'; if (email.includes('@gmail.com')) return 'smtp.gmail.com'; if (email.includes('@outlook.com') || email.includes('@hotmail.com')) return 'smtp.office365.com'; if (email.includes('@yeah.net')) return 'smtp.yeah.net'; // 默认 return 'smtp.qq.com'; } // ── 生成订阅邮件HTML ───────────────────────── function generateSubscriptionEmail(config, urlOverride) { const subUrl = urlOverride || `http://${config.server_host}/api/proxy-sub/sub/${config.sub_token}`; const now = new Date().toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' }); return `

🏛️ 铸渊专线

ZY-Proxy · 私有订阅链接


📱 订阅链接

${subUrl}

⚠️ 请勿分享此链接 · 所有订阅共享500GB月配额


📋 使用方法

🍎 iPhone (Shadowrocket)

  1. 打开 Shadowrocket
  2. 点击右上角 +
  3. 选择 Subscribe (订阅)
  4. 粘贴上方订阅链接
  5. 点击完成 → 选择节点 → 开启连接

💻 Mac / Windows (Clash Verge)

  1. 打开 Clash Verge
  2. 点击 Profiles (配置)
  3. 粘贴上方订阅链接到输入框
  4. 点击 Import (导入)
  5. 选中新配置 → 开启系统代理

🤖 Android (ClashMi / Clash Meta)

  1. 打开 ClashMi
  2. 点击 ProfileNew Profile
  3. 选择 URL
  4. 粘贴上方订阅链接
  5. 保存 → 选中配置 → 启动

📊 配额信息

月配额500 GB
重置日期每月1日
协议VLESS + Reality (最高安全级别)
节点位置🇸🇬 新加坡

在客户端中刷新订阅可查看剩余配额。
配额达到80%/90%/100%时会自动发送邮件提醒。


铸渊专线 · 冰朔私有网络 · ${now}
国作登字-2026-A-00037559

`; } // ── 生成V3订阅邮件HTML (光湖语言世界) ───────── function generateV3SubscriptionEmail(subUrl, dashboardUrl) { const now = new Date().toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' }); return `

🌐 光湖语言世界

光湖语言世界 V3 · 私有订阅链接

✅ V3 正式版 — 稳定版本,全面优化升级

📱 V3 订阅链接

${subUrl}

⚠️ 请勿分享此链接 · 所有订阅共享 2000GB 月流量池


📊 V3 流量仪表盘

${dashboardUrl}

💡 V3新功能:在浏览器中查看实时流量统计和节点状态


📋 使用方法

🍎 iPhone (Shadowrocket)

  1. 打开 Shadowrocket
  2. 点击右上角 +
  3. 选择 Subscribe (订阅)
  4. 粘贴上方 V3 订阅链接
  5. 点击完成 → 选择节点 → 开启连接

💻 Mac / Windows (Clash Verge)

  1. 打开 Clash Verge
  2. 点击 Profiles (配置)
  3. 粘贴上方 V3 订阅链接到输入框
  4. 点击 Import (导入)
  5. 选中新配置 → 开启系统代理

🤖 Android (ClashMi / Clash Meta)

  1. 打开 ClashMi
  2. 点击 ProfileNew Profile
  3. 选择 URL
  4. 粘贴上方 V3 订阅链接
  5. 保存 → 选中配置 → 启动

🆕 V3 升级亮点

品牌光湖语言世界
流量池2000 GB / 月 (硬切 · 到量即停)
重置日期每月1日
协议VLESS + Reality (最高安全级别)
节点位置🇸🇬 新加坡 (多节点)
新增📊 流量仪表盘 · 增强分流 · 反向加速

光湖语言世界 · V3 正式版 · ${now}
国作登字-2026-A-00037559

`; } // ── 生成告警邮件HTML ───────────────────────── function generateAlertEmail(message) { const now = new Date().toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' }); return `

🛡️ 铸渊专线 · 系统告警

${message}

${now}

`; } // ── 主入口 ─────────────────────────────────── async function main() { const [,, action, target, urlOverride, dashboardUrl] = process.argv; if (!action) { console.log('用法:'); console.log(' node send-subscription.js send — 发送V2订阅链接'); console.log(' node send-subscription.js send-v3 — 发送V3订阅链接'); console.log(' node send-subscription.js alert — 发送告警邮件'); process.exit(0); } const config = loadConfig(); if (action === 'send') { const email = target || config.smtp_user; if (!email) { console.error('❌ 请指定目标邮箱'); process.exit(1); } console.log(`📧 发送订阅链接到: ${email}`); const html = generateSubscriptionEmail(config, urlOverride); try { await sendEmail(email, '🏛️ 铸渊专线 · 订阅链接', html); console.log('✅ 订阅链接已发送'); } catch (err) { console.error('❌ 发送失败:', err.message); process.exit(1); } } else if (action === 'send-v3') { const email = target; if (!email) { console.error('❌ 请指定目标邮箱'); process.exit(1); } if (!urlOverride) { console.error('❌ 请提供V3订阅URL'); process.exit(1); } let dashboard = dashboardUrl; if (!dashboard) { if (urlOverride.includes('/sub/')) { dashboard = urlOverride.replace('/sub/', '/dashboard/'); } else { console.error('❌ 订阅URL中未包含/sub/路径,请手动提供仪表盘URL'); process.exit(1); } } console.log(`📧 发送V3订阅链接到: ${email}`); const html = generateV3SubscriptionEmail(urlOverride, dashboard); try { await sendEmail(email, '🌐 光湖语言世界 · V3订阅链接', html); console.log('✅ V3订阅链接已发送'); } catch (err) { console.error('❌ 发送失败:', err.message); process.exit(1); } } else if (action === 'alert') { const message = target || '未知告警'; const email = config.smtp_user; // 告警发到管理员邮箱 if (!email) { console.error('❌ SMTP用户未配置,无法发送告警'); process.exit(1); } console.log(`📧 发送告警到: ${email}`); const html = generateAlertEmail(message); try { await sendEmail(email, '🛡️ 铸渊专线告警', html); console.log('✅ 告警已发送'); } catch (err) { console.error('❌ 发送失败:', err.message); process.exit(1); } } else { console.error(`❌ 未知操作: ${action}`); process.exit(1); } } main().catch(console.error);