mirror of
https://github.com/whyour/qinglong.git
synced 2026-08-11 10:40:52 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5800837ed5 | ||
|
|
aecdd7852b | ||
|
|
d68c5b85bd | ||
|
|
275d8af4e2 | ||
|
|
544c432f49 | ||
|
|
6bec52dca1 | ||
|
|
ce599d306f |
@@ -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
-5
@@ -13,9 +13,29 @@ import { isValidToken } from '../shared/auth';
|
|||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
|
||||||
export default ({ app }: { app: Application }) => {
|
export default ({ app }: { app: Application }) => {
|
||||||
|
// Security: Enable strict routing to prevent case-insensitive path bypass
|
||||||
|
app.set('case sensitive routing', true);
|
||||||
|
app.set('strict routing', true);
|
||||||
app.set('trust proxy', 'loopback');
|
app.set('trust proxy', 'loopback');
|
||||||
app.use(cors());
|
app.use(cors());
|
||||||
|
|
||||||
|
// Security: Path normalization middleware to prevent case variation attacks
|
||||||
|
app.use((req, res, next) => {
|
||||||
|
const originalPath = req.path;
|
||||||
|
const normalizedPath = originalPath.toLowerCase();
|
||||||
|
|
||||||
|
// Block requests with case variations on protected paths
|
||||||
|
if (originalPath !== normalizedPath &&
|
||||||
|
(normalizedPath.startsWith('/api/') || normalizedPath.startsWith('/open/'))) {
|
||||||
|
return res.status(400).json({
|
||||||
|
code: 400,
|
||||||
|
message: 'Invalid path format'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
|
||||||
// Rewrite URLs to strip baseUrl prefix if configured
|
// Rewrite URLs to strip baseUrl prefix if configured
|
||||||
// This allows the rest of the app to work without baseUrl awareness
|
// This allows the rest of the app to work without baseUrl awareness
|
||||||
if (config.baseUrl) {
|
if (config.baseUrl) {
|
||||||
@@ -36,7 +56,7 @@ export default ({ app }: { app: Application }) => {
|
|||||||
secret: config.jwt.secret,
|
secret: config.jwt.secret,
|
||||||
algorithms: ['HS384'],
|
algorithms: ['HS384'],
|
||||||
}).unless({
|
}).unless({
|
||||||
path: [...config.apiWhiteList, /^\/(?!api\/).*/],
|
path: [...config.apiWhiteList, /^(\/(?!api\/).*)$/i],
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -51,19 +71,20 @@ export default ({ app }: { app: Application }) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
app.use(async (req: Request, res, next) => {
|
app.use(async (req: Request, res, next) => {
|
||||||
if (!['/open/', '/api/'].some((x) => req.path.startsWith(x))) {
|
const pathLower = req.path.toLowerCase();
|
||||||
|
if (!['/open/', '/api/'].some((x) => pathLower.startsWith(x))) {
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
|
|
||||||
const headerToken = getToken(req);
|
const headerToken = getToken(req);
|
||||||
if (req.path.startsWith('/open/')) {
|
if (pathLower.startsWith('/open/')) {
|
||||||
const apps = await shareStore.getApps();
|
const apps = await shareStore.getApps();
|
||||||
const doc = apps?.filter((x) =>
|
const doc = apps?.filter((x) =>
|
||||||
x.tokens?.find((y) => y.value === headerToken),
|
x.tokens?.find((y) => y.value === headerToken),
|
||||||
)?.[0];
|
)?.[0];
|
||||||
if (doc && doc.tokens && doc.tokens.length > 0) {
|
if (doc && doc.tokens && doc.tokens.length > 0) {
|
||||||
const currentToken = doc.tokens.find((x) => x.value === headerToken);
|
const currentToken = doc.tokens.find((x) => x.value === headerToken);
|
||||||
const keyMatch = req.path.match(/\/open\/([a-z]+)\/*/);
|
const keyMatch = pathLower.match(/\/open\/([a-z]+)\/*/);
|
||||||
const key = keyMatch && keyMatch[1];
|
const key = keyMatch && keyMatch[1];
|
||||||
if (
|
if (
|
||||||
doc.scopes.includes(key as any) &&
|
doc.scopes.includes(key as any) &&
|
||||||
@@ -98,7 +119,15 @@ export default ({ app }: { app: Application }) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
app.use(async (req, res, next) => {
|
app.use(async (req, res, next) => {
|
||||||
if (!['/api/user/init', '/api/user/notification/init'].includes(req.path)) {
|
const pathLower = req.path.toLowerCase();
|
||||||
|
if (
|
||||||
|
![
|
||||||
|
'/api/user/init',
|
||||||
|
'/api/user/notification/init',
|
||||||
|
'/open/user/init',
|
||||||
|
'/open/user/notification/init',
|
||||||
|
].includes(req.path)
|
||||||
|
) {
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
const authInfo =
|
const authInfo =
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import { AuthDataType, SystemModel } from '../data/system';
|
|||||||
import SystemService from '../services/system';
|
import SystemService from '../services/system';
|
||||||
import UserService from '../services/user';
|
import UserService from '../services/user';
|
||||||
import { writeFile, readFile } from 'fs/promises';
|
import { writeFile, readFile } from 'fs/promises';
|
||||||
import { createRandomString, fileExist, safeJSONParse } from '../config/util';
|
import { createRandomString, fileExist, isDemoEnv, safeJSONParse } from '../config/util';
|
||||||
import OpenService from '../services/open';
|
import OpenService from '../services/open';
|
||||||
import { shareStore } from '../shared/store';
|
import { shareStore } from '../shared/store';
|
||||||
import Logger from './logger';
|
import Logger from './logger';
|
||||||
@@ -50,7 +50,7 @@ export default async () => {
|
|||||||
const [authConfig] = await SystemModel.findOrCreate({
|
const [authConfig] = await SystemModel.findOrCreate({
|
||||||
where: { type: AuthDataType.authConfig },
|
where: { type: AuthDataType.authConfig },
|
||||||
});
|
});
|
||||||
if (!authConfig?.info) {
|
if (!authConfig?.info || isDemoEnv()) {
|
||||||
let authInfo = {
|
let authInfo = {
|
||||||
username: 'admin',
|
username: 'admin',
|
||||||
password: 'admin',
|
password: 'admin',
|
||||||
|
|||||||
+34
-4
@@ -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}>`,
|
||||||
|
|||||||
@@ -69,9 +69,10 @@ RUN git clone --depth=1 -b ${QL_BRANCH} ${QL_URL} ${QL_DIR} \
|
|||||||
|
|
||||||
ENV PNPM_HOME=${QL_DIR}/data/dep_cache/node \
|
ENV PNPM_HOME=${QL_DIR}/data/dep_cache/node \
|
||||||
PYTHON_HOME=${QL_DIR}/data/dep_cache/python3 \
|
PYTHON_HOME=${QL_DIR}/data/dep_cache/python3 \
|
||||||
PYTHONUSERBASE=${QL_DIR}/data/dep_cache/python3
|
PYTHONUSERBASE=${QL_DIR}/data/dep_cache/python3 \
|
||||||
|
HOME=/root
|
||||||
|
|
||||||
ENV PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:${PNPM_HOME}:${PYTHON_HOME}/bin \
|
ENV PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:${PNPM_HOME}:${PYTHON_HOME}/bin:${HOME}/bin \
|
||||||
NODE_PATH=/usr/local/bin:/usr/local/lib/node_modules:${PNPM_HOME}/global/5/node_modules \
|
NODE_PATH=/usr/local/bin:/usr/local/lib/node_modules:${PNPM_HOME}/global/5/node_modules \
|
||||||
PIP_CACHE_DIR=${PYTHON_HOME}/pip \
|
PIP_CACHE_DIR=${PYTHON_HOME}/pip \
|
||||||
PYTHONPATH=${PYTHON_HOME}:${PYTHON_HOME}/lib/python${PYTHON_SHORT_VERSION}:${PYTHON_HOME}/lib/python${PYTHON_SHORT_VERSION}/site-packages
|
PYTHONPATH=${PYTHON_HOME}:${PYTHON_HOME}/lib/python${PYTHON_SHORT_VERSION}:${PYTHON_HOME}/lib/python${PYTHON_SHORT_VERSION}/site-packages
|
||||||
|
|||||||
+3
-2
@@ -69,9 +69,10 @@ RUN git clone --depth=1 -b ${QL_BRANCH} ${QL_URL} ${QL_DIR} \
|
|||||||
|
|
||||||
ENV PNPM_HOME=${QL_DIR}/data/dep_cache/node \
|
ENV PNPM_HOME=${QL_DIR}/data/dep_cache/node \
|
||||||
PYTHON_HOME=${QL_DIR}/data/dep_cache/python3 \
|
PYTHON_HOME=${QL_DIR}/data/dep_cache/python3 \
|
||||||
PYTHONUSERBASE=${QL_DIR}/data/dep_cache/python3
|
PYTHONUSERBASE=${QL_DIR}/data/dep_cache/python3 \
|
||||||
|
HOME=/root
|
||||||
|
|
||||||
ENV PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:${PNPM_HOME}:${PYTHON_HOME}/bin \
|
ENV PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:${PNPM_HOME}:${PYTHON_HOME}/bin:${HOME}/bin \
|
||||||
NODE_PATH=/usr/local/bin:/usr/local/lib/node_modules:${PNPM_HOME}/global/5/node_modules \
|
NODE_PATH=/usr/local/bin:/usr/local/lib/node_modules:${PNPM_HOME}/global/5/node_modules \
|
||||||
PIP_CACHE_DIR=${PYTHON_HOME}/pip \
|
PIP_CACHE_DIR=${PYTHON_HOME}/pip \
|
||||||
PYTHONPATH=${PYTHON_HOME}:${PYTHON_HOME}/lib/python${PYTHON_SHORT_VERSION}:${PYTHON_HOME}/lib/python${PYTHON_SHORT_VERSION}/site-packages
|
PYTHONPATH=${PYTHON_HOME}:${PYTHON_HOME}/lib/python${PYTHON_SHORT_VERSION}:${PYTHON_HOME}/lib/python${PYTHON_SHORT_VERSION}/site-packages
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
export PATH="$HOME/bin:$PATH"
|
|
||||||
|
|
||||||
dir_shell=/ql/shell
|
dir_shell=/ql/shell
|
||||||
. $dir_shell/share.sh
|
. $dir_shell/share.sh
|
||||||
|
|
||||||
|
|||||||
+22
-22
@@ -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"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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的Key,https://push.i-i.me/": "PushMe key, https://push.i-i.me/",
|
"PushMe的Key,https://push.i-i.me/": "PushMe key, https://push.i-i.me/",
|
||||||
|
|||||||
@@ -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的Key,https://push.i-i.me/": "PushMe的Key,https://push.i-i.me/",
|
"PushMe的Key,https://push.i-i.me/": "PushMe的Key,https://push.i-i.me/",
|
||||||
|
|||||||
+19
-2
@@ -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 },
|
||||||
{
|
{
|
||||||
|
|||||||
+5
-10
@@ -1,11 +1,6 @@
|
|||||||
version: 2.20.1
|
version: 2.20.2
|
||||||
changeLogLink: https://t.me/jiao_long/433
|
changeLogLink: https://t.me/jiao_long/434
|
||||||
publishTime: 2025-12-26 22:00
|
publishTime: 2026-03-01 1800
|
||||||
changeLog: |
|
changeLog: |
|
||||||
1. 修复获取依赖管理列表
|
1. 修复 path 安全漏洞(重要)
|
||||||
2. notify.js 修复 TG_PROXY_AUTH 参数拼接
|
|
||||||
3. QLAPI.notify larkSecret 参数
|
|
||||||
4. 修复 cron parser 定时规则校验
|
|
||||||
5. 修复设置 baseUrl 后无法访问
|
|
||||||
6. 修复环境变量排序
|
|
||||||
7. 修复定时任务无法停止
|
|
||||||
Reference in New Issue
Block a user