Compare commits

...

3 Commits

Author SHA1 Message Date
copilot-swe-agent[bot] 5800837ed5 Security: Upgrade multer from 1.4.5-lts.1 to 2.1.1 to fix DoS vulnerabilities
Co-authored-by: whyour <22700758+whyour@users.noreply.github.com>
2026-03-07 13:36:45 +00:00
copilot-swe-agent[bot] aecdd7852b Fix: Add custom SMTP host/port/secure settings to fix AliyunQiye email connection error
Co-authored-by: whyour <22700758+whyour@users.noreply.github.com>
2026-03-07 13:31:42 +00:00
copilot-swe-agent[bot] d68c5b85bd Initial plan 2026-03-07 13:24:51 +00:00
6 changed files with 86 additions and 28 deletions
+3
View File
@@ -116,6 +116,9 @@ export class EmailNotification extends NotificationBaseInfo {
public emailUser: string = ''; public emailUser: string = '';
public emailPass: string = ''; public emailPass: string = '';
public emailTo: string = ''; public emailTo: string = '';
public emailHost: string = '';
public emailPort: string = '';
public emailSecure: string = '';
} }
export class PushMeNotification extends NotificationBaseInfo { export class PushMeNotification extends NotificationBaseInfo {
+34 -4
View File
@@ -590,16 +590,46 @@ export default class NotificationService {
} }
private async email() { private async email() {
const { emailPass, emailService, emailUser, emailTo } = this.params; const {
emailPass,
emailService,
emailUser,
emailTo,
emailHost,
emailPort,
emailSecure,
} = this.params;
try { try {
const transporter = nodemailer.createTransport({ const transportConfig: {
service: emailService, service?: string;
host?: string;
port?: number;
secure?: boolean;
auth: { user: string; pass: string };
} = {
auth: { auth: {
user: emailUser, user: emailUser,
pass: emailPass, pass: emailPass,
}, },
}); };
if (emailHost) {
transportConfig.host = emailHost;
const parsedPort = emailPort ? parseInt(emailPort, 10) : NaN;
transportConfig.port =
!isNaN(parsedPort) && parsedPort >= 1 && parsedPort <= 65535
? parsedPort
: 465;
transportConfig.secure =
emailSecure !== undefined && emailSecure !== ''
? emailSecure === 'true'
: transportConfig.port === 465;
} else {
transportConfig.service = emailService;
}
const transporter = nodemailer.createTransport(transportConfig);
const info = await transporter.sendMail({ const info = await transporter.sendMail({
from: `"青龙快讯" <${emailUser}>`, from: `"青龙快讯" <${emailUser}>`,
+22 -22
View File
@@ -55,12 +55,15 @@
} }
}, },
"dependencies": { "dependencies": {
"@bufbuild/protobuf": "^2.10.0",
"@grpc/grpc-js": "^1.14.0", "@grpc/grpc-js": "^1.14.0",
"@grpc/proto-loader": "^0.8.0", "@grpc/proto-loader": "^0.8.0",
"@keyv/sqlite": "^4.0.1",
"@otplib/preset-default": "^12.0.1", "@otplib/preset-default": "^12.0.1",
"body-parser": "^1.20.3", "body-parser": "^1.20.3",
"celebrate": "^15.0.3", "celebrate": "^15.0.3",
"chokidar": "^4.0.1", "chokidar": "^4.0.1",
"compression": "^1.7.4",
"cors": "^2.8.5", "cors": "^2.8.5",
"cron-parser": "^5.4.0", "cron-parser": "^5.4.0",
"cross-spawn": "^7.0.6", "cross-spawn": "^7.0.6",
@@ -70,69 +73,66 @@
"express-jwt": "^8.4.1", "express-jwt": "^8.4.1",
"express-rate-limit": "^7.4.1", "express-rate-limit": "^7.4.1",
"express-urlrewrite": "^2.0.3", "express-urlrewrite": "^2.0.3",
"undici": "^7.9.0", "helmet": "^8.1.0",
"hpagent": "^1.2.0", "hpagent": "^1.2.0",
"http-proxy-middleware": "^3.0.3", "http-proxy-middleware": "^3.0.3",
"iconv-lite": "^0.6.3", "iconv-lite": "^0.6.3",
"ip2region": "2.3.0",
"js-yaml": "^4.1.0", "js-yaml": "^4.1.0",
"jsonwebtoken": "^9.0.2", "jsonwebtoken": "^9.0.2",
"keyv": "^5.2.3",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"multer": "1.4.5-lts.1", "multer": "^2.1.1",
"node-schedule": "^2.1.0", "node-schedule": "^2.1.0",
"nodemailer": "^6.9.16", "nodemailer": "^6.9.16",
"p-queue-cjs": "7.3.4", "p-queue-cjs": "7.3.4",
"@bufbuild/protobuf": "^2.10.0", "proper-lockfile": "^4.1.2",
"ps-tree": "^1.2.0", "ps-tree": "^1.2.0",
"reflect-metadata": "^0.2.2", "reflect-metadata": "^0.2.2",
"request-ip": "3.3.0",
"sequelize": "^6.37.5", "sequelize": "^6.37.5",
"sockjs": "^0.3.24", "sockjs": "^0.3.24",
"sqlite3": "git+https://github.com/whyour/node-sqlite3.git#v1.0.3", "sqlite3": "git+https://github.com/whyour/node-sqlite3.git#v1.0.3",
"toad-scheduler": "^3.0.1", "toad-scheduler": "^3.0.1",
"typedi": "^0.10.0", "typedi": "^0.10.0",
"undici": "^7.9.0",
"uuid": "^11.0.3", "uuid": "^11.0.3",
"winston": "^3.17.0", "winston": "^3.17.0",
"winston-daily-rotate-file": "^5.0.0", "winston-daily-rotate-file": "^5.0.0"
"request-ip": "3.3.0",
"ip2region": "2.3.0",
"keyv": "^5.2.3",
"@keyv/sqlite": "^4.0.1",
"proper-lockfile": "^4.1.2",
"compression": "^1.7.4",
"helmet": "^8.1.0"
}, },
"devDependencies": { "devDependencies": {
"moment": "2.30.1",
"@ant-design/icons": "^5.0.1", "@ant-design/icons": "^5.0.1",
"@ant-design/pro-layout": "6.38.22", "@ant-design/pro-layout": "6.38.22",
"@codemirror/view": "^6.34.1",
"@codemirror/state": "^6.4.1", "@codemirror/state": "^6.4.1",
"@codemirror/view": "^6.34.1",
"@monaco-editor/react": "4.2.1", "@monaco-editor/react": "4.2.1",
"@react-hook/resize-observer": "^2.0.2", "@react-hook/resize-observer": "^2.0.2",
"react-router-dom": "6.26.1",
"@types/body-parser": "^1.19.2", "@types/body-parser": "^1.19.2",
"@types/compression": "^1.7.2",
"@types/cors": "^2.8.12", "@types/cors": "^2.8.12",
"@types/cross-spawn": "^6.0.2", "@types/cross-spawn": "^6.0.2",
"@types/express": "^4.17.13", "@types/express": "^4.17.13",
"@types/express-jwt": "^6.0.4", "@types/express-jwt": "^6.0.4",
"@types/file-saver": "2.0.2", "@types/file-saver": "2.0.2",
"@types/helmet": "^4.0.0",
"@types/js-yaml": "^4.0.5", "@types/js-yaml": "^4.0.5",
"@types/jsonwebtoken": "^8.5.8", "@types/jsonwebtoken": "^8.5.8",
"@types/lodash": "^4.14.185", "@types/lodash": "^4.14.185",
"@types/multer": "^1.4.7", "@types/multer": "^2.1.0",
"@types/node": "^17.0.21", "@types/node": "^17.0.21",
"@types/node-schedule": "^1.3.2", "@types/node-schedule": "^1.3.2",
"@types/nodemailer": "^6.4.4", "@types/nodemailer": "^6.4.4",
"@types/proper-lockfile": "^4.1.4",
"@types/ps-tree": "^1.1.6",
"@types/qrcode.react": "^1.0.2", "@types/qrcode.react": "^1.0.2",
"@types/react": "^18.0.20", "@types/react": "^18.0.20",
"@types/react-copy-to-clipboard": "^5.0.4", "@types/react-copy-to-clipboard": "^5.0.4",
"@types/react-dom": "^18.0.6", "@types/react-dom": "^18.0.6",
"@types/request-ip": "0.0.41",
"@types/serve-handler": "^6.1.1", "@types/serve-handler": "^6.1.1",
"@types/sockjs": "^0.3.33", "@types/sockjs": "^0.3.33",
"@types/sockjs-client": "^1.5.1", "@types/sockjs-client": "^1.5.1",
"@types/uuid": "^8.3.4", "@types/uuid": "^8.3.4",
"@types/request-ip": "0.0.41",
"@types/proper-lockfile": "^4.1.4",
"@types/ps-tree": "^1.1.6",
"@uiw/codemirror-extensions-langs": "^4.21.9", "@uiw/codemirror-extensions-langs": "^4.21.9",
"@uiw/react-codemirror": "^4.21.9", "@uiw/react-codemirror": "^4.21.9",
"@umijs/max": "^4.4.4", "@umijs/max": "^4.4.4",
@@ -144,9 +144,9 @@
"axios": "^1.4.0", "axios": "^1.4.0",
"compression-webpack-plugin": "9.2.0", "compression-webpack-plugin": "9.2.0",
"concurrently": "^7.0.0", "concurrently": "^7.0.0",
"react-hotkeys-hook": "^4.6.1",
"file-saver": "2.0.2", "file-saver": "2.0.2",
"lint-staged": "^13.0.3", "lint-staged": "^13.0.3",
"moment": "2.30.1",
"monaco-editor": "0.33.0", "monaco-editor": "0.33.0",
"nodemon": "^3.0.1", "nodemon": "^3.0.1",
"prettier": "^2.5.1", "prettier": "^2.5.1",
@@ -162,7 +162,9 @@
"react-dnd": "^16.0.1", "react-dnd": "^16.0.1",
"react-dnd-html5-backend": "^16.0.1", "react-dnd-html5-backend": "^16.0.1",
"react-dom": "18.3.1", "react-dom": "18.3.1",
"react-hotkeys-hook": "^4.6.1",
"react-intl-universal": "^2.12.0", "react-intl-universal": "^2.12.0",
"react-router-dom": "6.26.1",
"react-split-pane": "^0.1.92", "react-split-pane": "^0.1.92",
"sockjs-client": "^1.6.0", "sockjs-client": "^1.6.0",
"ts-node": "^10.9.2", "ts-node": "^10.9.2",
@@ -170,8 +172,6 @@
"tslib": "^2.4.0", "tslib": "^2.4.0",
"typescript": "5.2.2", "typescript": "5.2.2",
"vh-check": "^2.0.5", "vh-check": "^2.0.5",
"virtualizedtableforantd4": "1.3.0", "virtualizedtableforantd4": "1.3.0"
"@types/compression": "^1.7.2",
"@types/helmet": "^4.0.0"
} }
} }
+4
View File
@@ -390,7 +390,11 @@
"调用版本;专业版填写pro,个人版填写personal,为空默认使用专业版": "Version, you can specify 'pro' for the Professional version and 'personal' for the Personal version. If left blank, it will default to the Professional version.", "调用版本;专业版填写pro,个人版填写personal,为空默认使用专业版": "Version, you can specify 'pro' for the Professional version and 'personal' for the Personal version. If left blank, it will default to the Professional version.",
"飞书群组机器人:https://www.feishu.cn/hc/zh-CN/articles/360024984973": "Feishu group bot: https://www.feishu.cn/hc/zh-CN/articles/360024984973", "飞书群组机器人:https://www.feishu.cn/hc/zh-CN/articles/360024984973": "Feishu group bot: https://www.feishu.cn/hc/zh-CN/articles/360024984973",
"飞书群组机器人加签密钥,安全设置中开启签名校验后获得": "Feishu group bot signature secret, obtained after enabling signature verification in security settings", "飞书群组机器人加签密钥,安全设置中开启签名校验后获得": "Feishu group bot signature secret, obtained after enabling signature verification in security settings",
"邮箱服务名称,比如126、163、Gmail、QQ等,支持列表https://github.com/nodemailer/nodemailer/blob/master/lib/well-known/services.json,设置emailHost后此项可不填": "Email service name, e.g., 126, 163, Gmail, QQ, etc. Supported list: https://github.com/nodemailer/nodemailer/blob/master/lib/well-known/services.json. Can be left blank if emailHost is set",
"邮箱服务名称,比如126、163、Gmail、QQ等,支持列表https://github.com/nodemailer/nodemailer/blob/master/lib/well-known/services.json": "Email service name, e.g., 126, 163, Gmail, QQ, etc. Supported list: https://github.com/nodemailer/nodemailer/blob/master/lib/well-known/services.json", "邮箱服务名称,比如126、163、Gmail、QQ等,支持列表https://github.com/nodemailer/nodemailer/blob/master/lib/well-known/services.json": "Email service name, e.g., 126, 163, Gmail, QQ, etc. Supported list: https://github.com/nodemailer/nodemailer/blob/master/lib/well-known/services.json",
"自定义SMTP服务器地址,设置后将忽略emailService中的服务器配置,如smtp.qiye.aliyun.com": "Custom SMTP server address. When set, the server configuration in emailService will be ignored. E.g., smtp.qiye.aliyun.com",
"自定义SMTP端口号,默认465": "Custom SMTP port number, default is 465",
"是否使用SSL/TLS,端口为465时默认为true,否则默认为false": "Whether to use SSL/TLS. Defaults to true when port is 465, otherwise false",
"邮箱地址": "Email Address", "邮箱地址": "Email Address",
"SMTP 登录密码,也可能为特殊口令,视具体邮件服务商说明而定": "The SMTP login password may also be a special passphrase, depending on the specific email service provider's instructions", "SMTP 登录密码,也可能为特殊口令,视具体邮件服务商说明而定": "The SMTP login password may also be a special passphrase, depending on the specific email service provider's instructions",
"PushMe的Keyhttps://push.i-i.me/": "PushMe key, https://push.i-i.me/", "PushMe的Keyhttps://push.i-i.me/": "PushMe key, https://push.i-i.me/",
+4
View File
@@ -390,7 +390,11 @@
"调用版本;专业版填写pro,个人版填写personal,为空默认使用专业版": "调用版本;专业版填写pro,个人版填写personal,为空默认使用专业版", "调用版本;专业版填写pro,个人版填写personal,为空默认使用专业版": "调用版本;专业版填写pro,个人版填写personal,为空默认使用专业版",
"飞书群组机器人:https://www.feishu.cn/hc/zh-CN/articles/360024984973": "飞书群组机器人:https://www.feishu.cn/hc/zh-CN/articles/360024984973", "飞书群组机器人:https://www.feishu.cn/hc/zh-CN/articles/360024984973": "飞书群组机器人:https://www.feishu.cn/hc/zh-CN/articles/360024984973",
"飞书群组机器人加签密钥,安全设置中开启签名校验后获得": "飞书群组机器人加签密钥,安全设置中开启签名校验后获得", "飞书群组机器人加签密钥,安全设置中开启签名校验后获得": "飞书群组机器人加签密钥,安全设置中开启签名校验后获得",
"邮箱服务名称,比如126、163、Gmail、QQ等,支持列表https://github.com/nodemailer/nodemailer/blob/master/lib/well-known/services.json,设置emailHost后此项可不填": "邮箱服务名称,比如126、163、Gmail、QQ等,支持列表https://github.com/nodemailer/nodemailer/blob/master/lib/well-known/services.json,设置emailHost后此项可不填",
"邮箱服务名称,比如126、163、Gmail、QQ等,支持列表https://github.com/nodemailer/nodemailer/blob/master/lib/well-known/services.json": "邮箱服务名称,比如126、163、Gmail、QQ等,支持列表https://github.com/nodemailer/nodemailer/blob/master/lib/well-known/services.json", "邮箱服务名称,比如126、163、Gmail、QQ等,支持列表https://github.com/nodemailer/nodemailer/blob/master/lib/well-known/services.json": "邮箱服务名称,比如126、163、Gmail、QQ等,支持列表https://github.com/nodemailer/nodemailer/blob/master/lib/well-known/services.json",
"自定义SMTP服务器地址,设置后将忽略emailService中的服务器配置,如smtp.qiye.aliyun.com": "自定义SMTP服务器地址,设置后将忽略emailService中的服务器配置,如smtp.qiye.aliyun.com",
"自定义SMTP端口号,默认465": "自定义SMTP端口号,默认465",
"是否使用SSL/TLS,端口为465时默认为true,否则默认为false": "是否使用SSL/TLS,端口为465时默认为true,否则默认为false",
"邮箱地址": "邮箱地址", "邮箱地址": "邮箱地址",
"SMTP 登录密码,也可能为特殊口令,视具体邮件服务商说明而定": "SMTP 登录密码,也可能为特殊口令,视具体邮件服务商说明而定", "SMTP 登录密码,也可能为特殊口令,视具体邮件服务商说明而定": "SMTP 登录密码,也可能为特殊口令,视具体邮件服务商说明而定",
"PushMe的Keyhttps://push.i-i.me/": "PushMe的Keyhttps://push.i-i.me/", "PushMe的Keyhttps://push.i-i.me/": "PushMe的Keyhttps://push.i-i.me/",
+19 -2
View File
@@ -406,9 +406,26 @@ export default {
{ {
label: 'emailService', label: 'emailService',
tip: intl.get( tip: intl.get(
'邮箱服务名称,比如126、163、Gmail、QQ等,支持列表https://github.com/nodemailer/nodemailer/blob/master/lib/well-known/services.json', '邮箱服务名称,比如126、163、Gmail、QQ等,支持列表https://github.com/nodemailer/nodemailer/blob/master/lib/well-known/services.json,设置emailHost后此项可不填',
), ),
required: true, },
{
label: 'emailHost',
tip: intl.get(
'自定义SMTP服务器地址,设置后将忽略emailService中的服务器配置,如smtp.qiye.aliyun.com',
),
},
{
label: 'emailPort',
tip: intl.get('自定义SMTP端口号,默认465'),
},
{
label: 'emailSecure',
tip: intl.get('是否使用SSL/TLS,端口为465时默认为true,否则默认为false'),
items: [
{ value: 'true', label: 'true' },
{ value: 'false', label: 'false' },
],
}, },
{ label: 'emailUser', tip: intl.get('邮箱认证地址'), required: true }, { label: 'emailUser', tip: intl.get('邮箱认证地址'), required: true },
{ {