feat: 转为esm规范&升级koa2 latest

This commit is contained in:
chaoszhu
2026-07-28 22:43:14 +08:00
parent b3c38c42fe
commit 92fe31737f
66 changed files with 606 additions and 400 deletions
+38 -4
View File
@@ -1,6 +1,6 @@
const path = require('path')
import path from 'node:path'
module.exports = {
const config = {
httpPort: process.env.HTTP_PORT ? parseInt(process.env.HTTP_PORT) : 8082,
httpsPort: process.env.HTTPS_PORT ? parseInt(process.env.HTTPS_PORT) : 8092,
enableHttps: process.env.ENABLE_HTTPS ? parseInt(process.env.ENABLE_HTTPS) : 0, // 0:关闭 1:自签证书 2:传入证书路径
@@ -32,5 +32,39 @@ module.exports = {
logConfig: {
outDir: path.join(process.cwd(),'./app/db/logs'),
DEBUG: process.env.DEBUG !== 'false'
}
}
}
}
export const {
httpPort,
httpsPort,
enableHttps,
sslCertPath,
sslKeyPath,
uploadDir,
staticDir,
sftpCacheDir,
credentialsDBPath,
keyDBPath,
hostListDBPath,
groupConfDBPath,
scriptsDBPath,
scriptGroupDBPath,
notifyDBPath,
notifyConfigDBPath,
onekeyDBPath,
plusDBPath,
aiConfigDBPath,
chatHistoryDBPath,
favoriteSftpDBPath,
proxyDBPath,
fileTransferDBPath,
terminalConfigDBPath,
serverListDBPath,
sessionDBPath,
terminalSessionDBPath,
apiPrefix,
logConfig
} = config
export default config
+8 -6
View File
@@ -1,9 +1,11 @@
const path = require('path')
const decryptAndExecuteAsync = require('../utils/decrypt-file')
const { AIConfigDB, ChatHistoryDB } = require('../utils/db-class')
import path, { dirname } from 'node:path'
import { fileURLToPath } from 'node:url'
import decryptAndExecuteAsync from '../utils/decrypt-file.js'
import { AIConfigDB, ChatHistoryDB } from '../utils/db-class.js'
const aiConfigDB = new AIConfigDB().getInstance()
const chatHistoryDB = new ChatHistoryDB().getInstance()
const currentDir = dirname(fileURLToPath(import.meta.url))
async function getAIConfig({ res }) {
try {
@@ -18,7 +20,7 @@ async function getAIConfig({ res }) {
}
async function getAIModels({ res, request }) {
let { getAIModels } = (await decryptAndExecuteAsync(path.join(__dirname, 'plus.js'))) || {}
let { getAIModels } = (await decryptAndExecuteAsync(path.join(currentDir, 'plus.js'))) || {}
if (getAIModels) {
await getAIModels({ res, request })
} else {
@@ -27,7 +29,7 @@ async function getAIModels({ res, request }) {
}
async function saveAIConfig({ res, request }) {
let { saveAIConfig } = (await decryptAndExecuteAsync(path.join(__dirname, 'plus.js'))) || {}
let { saveAIConfig } = (await decryptAndExecuteAsync(path.join(currentDir, 'plus.js'))) || {}
if (saveAIConfig) {
await saveAIConfig({ res, request })
} else {
@@ -71,7 +73,7 @@ async function removeChatHistory({ res, request }) {
res.success({ data: true })
}
module.exports = {
export {
getAIConfig,
saveAIConfig,
getAIModels,
+2 -2
View File
@@ -1,4 +1,4 @@
const { HostListDB, GroupDB } = require('../utils/db-class')
import { HostListDB, GroupDB } from '../utils/db-class.js'
const hostListDB = new HostListDB().getInstance()
const groupDB = new GroupDB().getInstance()
@@ -45,7 +45,7 @@ const removeGroup = async ({ res, request }) => {
res.success({ data: '移除成功' })
}
module.exports = {
export {
addGroupList,
getGroupList,
updateGroupList,
+9 -7
View File
@@ -1,8 +1,10 @@
const path = require('path')
const decryptAndExecuteAsync = require('../utils/decrypt-file')
const { RSADecryptAsync, AESEncryptAsync, AESDecryptAsync } = require('../utils/encrypt')
const { HostListDB } = require('../utils/db-class')
const hostListDB = new HostListDB().getInstance()
import path, { dirname } from 'node:path'
import { fileURLToPath } from 'node:url'
import decryptAndExecuteAsync from '../utils/decrypt-file.js'
import { RSADecryptAsync, AESEncryptAsync, AESDecryptAsync } from '../utils/encrypt.js'
import { HostListDB } from '../utils/db-class.js'
const hostListDB = new HostListDB().getInstance()
const currentDir = dirname(fileURLToPath(import.meta.url))
async function getHostList({ res }) {
let data = await hostListDB.findAsync({})
@@ -58,7 +60,7 @@ async function updateHost({ res, request }) {
}
async function batchUpdateHost({ res, request }) {
let { updateHosts } = (await decryptAndExecuteAsync(path.join(__dirname, 'plus.js'))) || {}
let { updateHosts } = (await decryptAndExecuteAsync(path.join(currentDir, 'plus.js'))) || {}
if (updateHosts) {
await updateHosts({ res, request })
} else {
@@ -121,7 +123,7 @@ async function updateLastConnectTime({ res, request }) {
}
}
module.exports = {
export {
getHostList,
addHost,
updateHost,
+11 -9
View File
@@ -1,7 +1,10 @@
const crypto = require('crypto')
const path = require('path')
const { RSADecryptAsync } = require('../utils/encrypt')
const decryptAndExecuteAsync = require('../utils/decrypt-file')
import crypto from 'node:crypto'
import path, { dirname } from 'node:path'
import { fileURLToPath } from 'node:url'
import { RSADecryptAsync } from '../utils/encrypt.js'
import decryptAndExecuteAsync from '../utils/decrypt-file.js'
const currentDir = dirname(fileURLToPath(import.meta.url))
function encryptJsonForNative(payload, key) {
if (!Buffer.isBuffer(key) || key.length !== 32) {
@@ -46,13 +49,12 @@ async function buildNativeTopology(hostInfo = {}) {
return { proxyType: '', proxy: null, jumpHosts: [] }
}
let { getConnectionHelper } = (await decryptAndExecuteAsync(path.join(__dirname, 'plus.js'))) || {}
let { getConnectionHelper } = (await decryptAndExecuteAsync(path.join(currentDir, 'plus.js'))) || {}
if (getConnectionHelper) {
const config = await getConnectionHelper(proxyType, hostInfo, normalizeNativeAuthPayload)
return config
} else {
throw new Error('跳板机&代理服务为Plus功能')
}
throw new Error('跳板机&代理服务为Plus功能')
}
async function getNativeSshConnection({ request, res }) {
@@ -64,7 +66,7 @@ async function getNativeSshConnection({ request, res }) {
const tempKeyText = await RSADecryptAsync(encryptedKey)
const tempKey = Buffer.from(tempKeyText, 'base64')
const { getConnectionOptions } = require('../socket/terminal')
const { getConnectionOptions } = await import('../socket/terminal.js')
const { authInfo, name, hostInfo } = await getConnectionOptions(hostId)
const payload = {
...normalizeNativeAuthPayload(hostId, name, authInfo),
@@ -79,6 +81,6 @@ async function getNativeSshConnection({ request, res }) {
}
}
module.exports = {
export {
getNativeSshConnection
}
+3 -3
View File
@@ -1,5 +1,5 @@
const { sendServerChan, sendEmail, sendTg, sendWebhook } = require('../utils/notify')
const { NotifyConfigDB, NotifyDB } = require('../utils/db-class')
import { sendServerChan, sendEmail, sendTg, sendWebhook } from '../utils/notify.js'
import { NotifyConfigDB, NotifyDB } from '../utils/db-class.js'
const notifyDB = new NotifyDB().getInstance()
const notifyConfigDB = new NotifyConfigDB().getInstance()
@@ -46,7 +46,7 @@ async function updateNotifyList({ res, request }) {
res.success()
}
module.exports = {
export {
getNotifyConfig,
updateNotifyConfig,
getNotifyList,
+2 -2
View File
@@ -1,4 +1,4 @@
const { OnekeyDB } = require('../utils/db-class')
import { OnekeyDB } from '../utils/db-class.js'
const onekeyDB = new OnekeyDB().getInstance()
async function getOnekeyRecord({ res }) {
@@ -21,7 +21,7 @@ const removeOnekeyRecord = async ({ res, request }) => {
}
}
module.exports = {
export {
getOnekeyRecord,
removeOnekeyRecord
}
File diff suppressed because one or more lines are too long
+2 -2
View File
@@ -1,4 +1,4 @@
const { ProxyDB, HostListDB } = require('../utils/db-class')
import { ProxyDB, HostListDB } from '../utils/db-class.js'
const proxyDB = new ProxyDB().getInstance()
const hostListDB = new HostListDB().getInstance()
@@ -109,7 +109,7 @@ const removeProxy = async ({ res, request }) => {
}
}
module.exports = {
export {
getProxyList,
addProxy,
updateProxy,
+11 -8
View File
@@ -1,6 +1,9 @@
const path = require('path')
const { ScriptGroupDB } = require('../utils/db-class')
const decryptAndExecuteAsync = require('../utils/decrypt-file')
import path, { dirname } from 'node:path'
import { fileURLToPath } from 'node:url'
import { ScriptGroupDB } from '../utils/db-class.js'
import decryptAndExecuteAsync from '../utils/decrypt-file.js'
const currentDir = dirname(fileURLToPath(import.meta.url))
const scriptGroupDB = new ScriptGroupDB().getInstance()
async function getScriptGroupList({ res }) {
@@ -11,7 +14,7 @@ async function getScriptGroupList({ res }) {
}
const addScriptGroup = async ({ res, request }) => {
let { addScriptGroup } = (await decryptAndExecuteAsync(path.join(__dirname, 'plus.js'))) || {}
let { addScriptGroup } = (await decryptAndExecuteAsync(path.join(currentDir, 'plus.js'))) || {}
if (addScriptGroup) {
await addScriptGroup({ res, request })
} else {
@@ -20,7 +23,7 @@ const addScriptGroup = async ({ res, request }) => {
}
const updateScriptGroup = async ({ res, request }) => {
let { updateScriptGroup } = (await decryptAndExecuteAsync(path.join(__dirname, 'plus.js'))) || {}
let { updateScriptGroup } = (await decryptAndExecuteAsync(path.join(currentDir, 'plus.js'))) || {}
if (updateScriptGroup) {
await updateScriptGroup({ res, request })
} else {
@@ -29,7 +32,7 @@ const updateScriptGroup = async ({ res, request }) => {
}
const removeScriptGroup = async ({ res, request }) => {
let { removeScriptGroup } = (await decryptAndExecuteAsync(path.join(__dirname, 'plus.js'))) || {}
let { removeScriptGroup } = (await decryptAndExecuteAsync(path.join(currentDir, 'plus.js'))) || {}
if (removeScriptGroup) {
await removeScriptGroup({ res, request })
} else {
@@ -37,9 +40,9 @@ const removeScriptGroup = async ({ res, request }) => {
}
}
module.exports = {
export {
addScriptGroup,
getScriptGroupList,
updateScriptGroup,
removeScriptGroup
}
}
+9 -7
View File
@@ -1,9 +1,11 @@
const path = require('path')
const decryptAndExecuteAsync = require('../utils/decrypt-file')
const { randomStr } = require('../utils/tools')
const { ScriptsDB } = require('../utils/db-class')
const localShellJson = require('../config/shell.json')
import path, { dirname } from 'node:path'
import { fileURLToPath } from 'node:url'
import decryptAndExecuteAsync from '../utils/decrypt-file.js'
import { randomStr } from '../utils/tools.js'
import { ScriptsDB } from '../utils/db-class.js'
import localShellJson from '../config/shell.json' with { type: 'json' }
const scriptsDB = new ScriptsDB().getInstance()
const currentDir = dirname(fileURLToPath(import.meta.url))
let localShell = JSON.parse(JSON.stringify(localShellJson)).map((item) => {
return { ...item, id: randomStr(10), index: '--', description: item.description, group: 'builtin' }
@@ -56,7 +58,7 @@ const batchRemoveScript = async ({ res, request }) => {
}
const importScript = async ({ res, request }) => {
let { impScript } = (await decryptAndExecuteAsync(path.join(__dirname, 'plus.js'))) || {}
let { impScript } = (await decryptAndExecuteAsync(path.join(currentDir, 'plus.js'))) || {}
if (impScript) {
await impScript({ res, request })
} else {
@@ -64,7 +66,7 @@ const importScript = async ({ res, request }) => {
}
}
module.exports = {
export {
addScript,
getScriptList,
getLocalScriptList,
+2 -2
View File
@@ -1,4 +1,4 @@
const { ServerListDB } = require('../utils/db-class')
import { ServerListDB } from '../utils/db-class.js'
const serverListDB = new ServerListDB().getInstance()
// 获取服务器列表配置
@@ -63,7 +63,7 @@ async function saveServerListConfig({ res, request }) {
}
}
module.exports = {
export {
getServerListConfig,
saveServerListConfig
}
+2 -2
View File
@@ -1,4 +1,4 @@
const { KeyDB, SessionDB } = require('../utils/db-class')
import { KeyDB, SessionDB } from '../utils/db-class.js'
const keyDB = new KeyDB().getInstance()
const sessionDB = new SessionDB().getInstance()
@@ -50,7 +50,7 @@ const revokeLoginSid = async (ctx) => {
res.success({ msg: '注销凭证成功' })
}
module.exports = {
export {
getLog,
saveIpWhiteList,
removeSomeLoginRecords,
+2 -2
View File
@@ -1,4 +1,4 @@
const { HostListDB, CredentialsDB, FavoriteSftpDB } = require('../utils/db-class')
import { HostListDB, CredentialsDB, FavoriteSftpDB } from '../utils/db-class.js'
const favoriteSftpDB = new FavoriteSftpDB().getInstance()
@@ -19,6 +19,6 @@ async function getSftpFavorites({ params, request, res }) {
}
}
module.exports = {
export {
getSftpFavorites
}
+10 -8
View File
@@ -1,10 +1,12 @@
const path = require('path')
const crypto = require('crypto')
const { RSADecryptAsync, AESEncryptAsync, AESDecryptAsync } = require('../utils/encrypt')
const { HostListDB, CredentialsDB } = require('../utils/db-class')
const decryptAndExecuteAsync = require('../utils/decrypt-file')
import path, { dirname } from 'node:path'
import { fileURLToPath } from 'node:url'
import crypto from 'node:crypto'
import { RSADecryptAsync, AESEncryptAsync, AESDecryptAsync } from '../utils/encrypt.js'
import { HostListDB, CredentialsDB } from '../utils/db-class.js'
import decryptAndExecuteAsync from '../utils/decrypt-file.js'
const hostListDB = new HostListDB().getInstance()
const credentialsDB = new CredentialsDB().getInstance()
const credentialsDB = new CredentialsDB().getInstance()
const currentDir = dirname(fileURLToPath(import.meta.url))
async function getSSHList({ res }) {
let data = await credentialsDB.findAsync({})
@@ -118,7 +120,7 @@ const decryptPrivateKey = async ({ res, request }) => {
}
const getRdpToken = async ({ res, request }) => {
let { genRdpToken } = (await decryptAndExecuteAsync(path.join(__dirname, 'plus.js'))) || {}
let { genRdpToken } = (await decryptAndExecuteAsync(path.join(currentDir, 'plus.js'))) || {}
if (genRdpToken) {
await genRdpToken({ res, request })
} else {
@@ -126,7 +128,7 @@ const getRdpToken = async ({ res, request }) => {
}
}
module.exports = {
export {
getSSHList,
addSSH,
updateSSH,
+2 -2
View File
@@ -1,4 +1,4 @@
const { TerminalConfigDB } = require('../utils/db-class')
import { TerminalConfigDB } from '../utils/db-class.js'
// 终端默认配置
const DEFAULT_TERMINAL_CONFIG = {
@@ -74,7 +74,7 @@ async function saveTerminalConfig({ res, request }) {
}
}
module.exports = {
export {
getTerminalConfig,
saveTerminalConfig
}
+3 -3
View File
@@ -1,5 +1,5 @@
const { sessionManager, getDefaultSessionConfig } = require('../utils/terminal-session')
const { KeyDB, HostListDB, TerminalSessionDB } = require('../utils/db-class')
import { sessionManager, getDefaultSessionConfig } from '../utils/terminal-session.js'
import { KeyDB, HostListDB, TerminalSessionDB } from '../utils/db-class.js'
const keyDB = new KeyDB().getInstance()
const hostListDB = new HostListDB().getInstance()
@@ -101,7 +101,7 @@ async function updateTerminalSessionConfig({ request, res }) {
}
}
module.exports = {
export {
getSuspendedSessions,
getTerminalSessionConfig,
updateTerminalSessionConfig
+15 -14
View File
@@ -1,16 +1,17 @@
const jwt = require('jsonwebtoken')
const axios = require('axios')
const speakeasy = require('speakeasy')
const QRCode = require('qrcode')
const uap = require('ua-parser-js')
const { v4: uuidv4 } = require('uuid')
const version = require('../../package.json').version
const getLicenseInfo = require('../utils/get-plus')
const { sendNoticeAsync } = require('../utils/notify')
const { RSADecryptAsync, AESEncryptAsync, SHA1Encrypt, SHA256Encrypt } = require('../utils/encrypt')
const { getNetIPInfo, requestWithFailover, timingSafeEqual } = require('../utils/tools')
const { KeyDB, PlusDB, SessionDB } = require('../utils/db-class')
const { RuntimeState } = require('../utils/runtime-state')
import jwt from 'jsonwebtoken'
import axios from 'axios'
import speakeasy from 'speakeasy'
import QRCode from 'qrcode'
import { UAParser as uap } from 'ua-parser-js'
import { v4 as uuidv4 } from 'uuid'
import PackageJsonModule from '../../package.json' with { type: 'json' }
const version = PackageJsonModule.version
import getLicenseInfo from '../utils/get-plus.js'
import { sendNoticeAsync } from '../utils/notify.js'
import { RSADecryptAsync, AESEncryptAsync, SHA1Encrypt, SHA256Encrypt } from '../utils/encrypt.js'
import { getNetIPInfo, requestWithFailover, timingSafeEqual } from '../utils/tools.js'
import { KeyDB, PlusDB, SessionDB } from '../utils/db-class.js'
import { RuntimeState } from '../utils/runtime-state.js'
const keyDB = new KeyDB().getInstance()
const sessionDB = new SessionDB().getInstance()
@@ -320,7 +321,7 @@ const releasePlusDevice = async ({ res, request }) => {
}
}
module.exports = {
export {
login,
getpublicKey,
updatePwd,
+5 -5
View File
@@ -1,7 +1,7 @@
const NodeRSA = require('node-rsa')
const { randomStr } = require('./utils/tools')
const { AESEncryptAsync, SHA1Encrypt } = require('./utils/encrypt')
const { KeyDB, GroupDB, NotifyDB, NotifyConfigDB, ScriptGroupDB } = require('./utils/db-class')
import NodeRSA from 'node-rsa'
import { randomStr } from './utils/tools.js'
import { AESEncryptAsync, SHA1Encrypt } from './utils/encrypt.js'
import { KeyDB, GroupDB, NotifyDB, NotifyConfigDB, ScriptGroupDB } from './utils/db-class.js'
async function initKeyDB() {
const keyDB = new KeyDB().getInstance()
@@ -153,7 +153,7 @@ async function initScriptGroupDB() {
return Promise.resolve()
}
module.exports = async () => {
export default async () => {
await initKeyDB()
await initNotifyDB()
await initGroupDB()
+5 -3
View File
@@ -1,5 +1,7 @@
const log4js = require('log4js')
const { outDir } = require('./config').logConfig
import log4js from 'log4js'
import { logConfig } from './config/index.js'
const { outDir } = logConfig
log4js.configure({
appenders: {
console: {
@@ -26,4 +28,4 @@ log4js.configure({
}
})
const logger = log4js.getLogger()
global.logger = logger
global.logger = logger
+5 -5
View File
@@ -1,8 +1,8 @@
require('./logs')
const { createServer } = require('./server')
const initDB = require('./db')
const scheduleJob = require('./schedule')
const { startActivation } = require('./utils/get-plus')
import './logs.js'
import { createServer } from './server.js'
import initDB from './db.js'
import scheduleJob from './schedule/index.js'
import { startActivation } from './utils/get-plus.js'
async function main() {
await initDB()
+3 -3
View File
@@ -1,5 +1,5 @@
const { apiPrefix } = require('../config')
const { verifyAuthSync, enumLoginCode } = require('../utils/verify-auth')
import { apiPrefix } from '../config/index.js'
import { verifyAuthSync, enumLoginCode } from '../utils/verify-auth.js'
let whitePath = [
'/login',
@@ -48,4 +48,4 @@ const useAuth = async (ctx, next) => {
return res.fail({ msg: failMsg || '身份验证失败(未知错误!)', status: 403 })
}
module.exports = useAuth
export default useAuth
+4 -2
View File
@@ -1,5 +1,7 @@
const { koaBody } = require('koa-body')
import koaBodyModule from 'koa-body'
module.exports = koaBody({
const { koaBody } = koaBodyModule
export default koaBody({
multipart: false
})
+2 -2
View File
@@ -1,6 +1,6 @@
// 响应压缩模块,自适应头部压缩方式
const compress = require('koa-compress')
import compress from 'koa-compress'
const options = { threshold: 2048 }
module.exports = compress(options)
export default compress(options)
+2 -2
View File
@@ -1,4 +1,4 @@
const cors = require('@koa/cors')
import cors from '@koa/cors'
// 跨域处理
const useCors = cors({
@@ -9,4 +9,4 @@ const useCors = cors({
allowMethods: [ 'GET', 'HEAD', 'PUT', 'POST', 'DELETE', 'PATCH' ]
})
module.exports = useCors
export default useCors
+3 -2
View File
@@ -1,3 +1,4 @@
const { historyApiFallback } = require('koa2-connect-history-api-fallback')
import koa2ConnectHistoryApiFallbackModule from 'koa2-connect-history-api-fallback'
const { historyApiFallback } = koa2ConnectHistoryApiFallbackModule
module.exports = historyApiFallback({ whiteList: ['/api'] })
export default historyApiFallback({ whiteList: ['/api'] })
+12 -12
View File
@@ -1,16 +1,16 @@
const ipFilter = require('./ipFilter') // IP过滤
const responseHandler = require('./response') // 统一返回格式, 错误捕获
const useAuth = require('./auth') // 鉴权
// const useCors = require('./cors') // 处理跨域[暂时禁止]
const useLog = require('./useLog') // 记录日志,需要等待路由处理完成,所以得放路由前
const useKoaBody = require('./body') // 处理body参数 【请求需先走该中间件】
const { useRoutes, useAllowedMethods } = require('./router') // 路由管理
const useStatic = require('./static') // 静态目录
const useSftpCacheStatic = require('./sftp-cache') // SFTP缓存文件服务
const compress = require('./compress') // br/gzip压缩
const history = require('./history') // vue-router的history模式
import ipFilter from './ipFilter.js' // IP过滤
import responseHandler from './response.js' // 统一返回格式, 错误捕获
import useAuth from './auth.js' // 鉴权
// import useCors from './cors.js' // 处理跨域[暂时禁止]
import useLog from './useLog.js' // 记录日志,需要等待路由处理完成,所以得放路由前
import useKoaBody from './body.js' // 处理body参数 【请求需先走该中间件】
import { useRoutes, useAllowedMethods } from './router.js' // 路由管理
import useStatic from './static.js' // 静态目录
import useSftpCacheStatic from './sftp-cache.js' // SFTP缓存文件服务
import compress from './compress.js' // br/gzip压缩
import history from './history.js' // vue-router的history模式
module.exports = [
export default [
ipFilter,
useSftpCacheStatic, // SFTP缓存文件服务
compress,
+7 -5
View File
@@ -1,9 +1,11 @@
// 白名单IP
const fs = require('fs')
const path = require('path')
const { isAllowedIp, getClientIP } = require('../utils/tools')
import fs from 'node:fs'
import path, { dirname } from 'node:path'
import { fileURLToPath } from 'node:url'
import { isAllowedIp, getClientIP } from '../utils/tools.js'
const htmlPath = path.join(__dirname, '../template/ipForbidden.html')
const currentDir = dirname(fileURLToPath(import.meta.url))
const htmlPath = path.join(currentDir, '../template/ipForbidden.html')
const ipForbiddenHtml = fs.readFileSync(htmlPath, 'utf8')
const ipFilter = async (ctx, next) => {
@@ -13,4 +15,4 @@ const ipFilter = async (ctx, next) => {
ctx.body = ipForbiddenHtml
}
module.exports = ipFilter
export default ipFilter
+3 -2
View File
@@ -1,4 +1,5 @@
const { createProxyMiddleware } = require('http-proxy-middleware')
import httpProxyMiddlewareModule from 'http-proxy-middleware'
const { createProxyMiddleware } = httpProxyMiddlewareModule
/**
* RDP代理中间件
@@ -25,4 +26,4 @@ const createRdpProxyMiddleware = () => {
return wsProxy
}
module.exports = createRdpProxyMiddleware
export default createRdpProxyMiddleware
+1 -1
View File
@@ -31,4 +31,4 @@ const responseHandler = async (ctx, next) => {
}
}
module.exports = responseHandler
export default responseHandler
+2 -2
View File
@@ -1,4 +1,4 @@
const router = require('../router')
import router from '../router/index.js'
// 路由中间件
const useRoutes = router.routes()
@@ -7,7 +7,7 @@ const useRoutes = router.routes()
// 使用该中间件后请求方法错误会提示405 Method Not Allowed【get list ✔200 post /list ❌405】
const useAllowedMethods = router.allowedMethods()
module.exports = {
export {
useRoutes,
useAllowedMethods
}
+4 -4
View File
@@ -1,6 +1,6 @@
const koaStatic = require('koa-static')
const path = require('path')
const { sftpCacheDir } = require('../config')
import koaStatic from 'koa-static'
import path from 'node:path'
import { sftpCacheDir } from '../config/index.js'
const useSftpCacheStatic = async (ctx, next) => {
// 只处理 /sftp-cache 路径
@@ -29,4 +29,4 @@ const useSftpCacheStatic = async (ctx, next) => {
}
}
module.exports = useSftpCacheStatic
export default useSftpCacheStatic
+3 -3
View File
@@ -1,5 +1,5 @@
const koaStatic = require('koa-static')
const { staticDir } = require('../config')
import koaStatic from 'koa-static'
import { staticDir } from '../config/index.js'
const useStatic = koaStatic(staticDir, {
maxage: 1000 * 60 * 60 * 24 * 30,
@@ -11,4 +11,4 @@ const useStatic = koaStatic(staticDir, {
}
})
module.exports = useStatic
export default useStatic
+6 -4
View File
@@ -1,5 +1,7 @@
const { DEBUG } = require('../config').logConfig
const { getClientIP } = require('../utils/tools')
import { logConfig } from '../config/index.js'
import { getClientIP } from '../utils/tools.js'
const { DEBUG } = logConfig
// ------------------ 脱敏 ------------------
// 可能包含敏感信息的 header key(小写比较)
@@ -109,7 +111,7 @@ const useLog = () => {
origin,
query,
body,
headers,
headers
} = ctx.request
const ip = getClientIP(ctx.socket.remoteAddress, ctx.get('x-forwarded-for'))
@@ -169,4 +171,4 @@ const useLog = () => {
}
}
module.exports = useLog()
export default useLog()
+3 -3
View File
@@ -1,5 +1,5 @@
const http = require('http')
const GuacamoleLite = require('guacamole-lite')
import http from 'node:http'
import GuacamoleLite from 'guacamole-lite'
const RDP_PORT = process.env.RDP_PORT || 8083 // 使用独立端口
const GUACD_HOST = process.env.GUACD_HOST || 'guacd'
@@ -45,4 +45,4 @@ const startRdpServer = () => {
}
}
module.exports = { startRdpServer }
export { startRdpServer }
+4 -4
View File
@@ -1,8 +1,8 @@
const { apiPrefix } = require('../config')
const koaRouter = require('koa-router')
import { apiPrefix } from '../config/index.js'
import koaRouter from 'koa-router'
const router = new koaRouter({ prefix: apiPrefix })
const routeList = require('./routes')
import routeList from './routes.js'
// 统一注册路由
routeList.forEach(item => {
@@ -10,4 +10,4 @@ routeList.forEach(item => {
router[method](path, controller)
})
module.exports = router
export default router
+17 -17
View File
@@ -1,19 +1,19 @@
const { getSSHList, addSSH, updateSSH, removeSSH, getCommand, decryptPrivateKey, getRdpToken } = require('../controller/ssh')
const { getSftpFavorites } = require('../controller/sftp')
const { getHostList, addHost, updateHost, batchUpdateHost, removeHost, importHost, updateLastConnectTime } = require('../controller/host')
const { login, getpublicKey, updatePwd, getEasynodeVersion, getMFA2Status, getMFA2Code, enableMFA2, disableMFA2, getPlusInfo, getPlusDiscount, getPlusConf, updatePlusKey, getPlusDevices, releasePlusDevice } = require('../controller/user')
const { getNotifyConfig, updateNotifyConfig, getNotifyList, updateNotifyList } = require('../controller/notify')
const { getGroupList, addGroupList, updateGroupList, removeGroup } = require('../controller/group')
const { getScriptList, getLocalScriptList, addScript, updateScriptList, removeScript, batchRemoveScript, importScript } = require('../controller/scripts')
const { getScriptGroupList, addScriptGroup, removeScriptGroup, updateScriptGroup } = require('../controller/script-group')
const { getOnekeyRecord, removeOnekeyRecord } = require('../controller/onekey')
const { getLog, saveIpWhiteList, removeSomeLoginRecords, revokeLoginSid } = require('../controller/sessionLog')
const { getAIConfig, saveAIConfig, getAIModels, getChatHistory, saveChatHistory, removeChatHistory } = require('../controller/chat')
const { getProxyList, addProxy, updateProxy, removeProxy } = require('../controller/proxy')
const { getTerminalConfig, saveTerminalConfig } = require('../controller/terminal-config')
const { getServerListConfig, saveServerListConfig } = require('../controller/server-list-config')
const { getSuspendedSessions, getTerminalSessionConfig, updateTerminalSessionConfig } = require('../controller/terminal')
const { getNativeSshConnection } = require('../controller/native')
import { getSSHList, addSSH, updateSSH, removeSSH, getCommand, decryptPrivateKey, getRdpToken } from '../controller/ssh.js'
import { getSftpFavorites } from '../controller/sftp.js'
import { getHostList, addHost, updateHost, batchUpdateHost, removeHost, importHost, updateLastConnectTime } from '../controller/host.js'
import { login, getpublicKey, updatePwd, getEasynodeVersion, getMFA2Status, getMFA2Code, enableMFA2, disableMFA2, getPlusInfo, getPlusDiscount, getPlusConf, updatePlusKey, getPlusDevices, releasePlusDevice } from '../controller/user.js'
import { getNotifyConfig, updateNotifyConfig, getNotifyList, updateNotifyList } from '../controller/notify.js'
import { getGroupList, addGroupList, updateGroupList, removeGroup } from '../controller/group.js'
import { getScriptList, getLocalScriptList, addScript, updateScriptList, removeScript, batchRemoveScript, importScript } from '../controller/scripts.js'
import { getScriptGroupList, addScriptGroup, removeScriptGroup, updateScriptGroup } from '../controller/script-group.js'
import { getOnekeyRecord, removeOnekeyRecord } from '../controller/onekey.js'
import { getLog, saveIpWhiteList, removeSomeLoginRecords, revokeLoginSid } from '../controller/sessionLog.js'
import { getAIConfig, saveAIConfig, getAIModels, getChatHistory, saveChatHistory, removeChatHistory } from '../controller/chat.js'
import { getProxyList, addProxy, updateProxy, removeProxy } from '../controller/proxy.js'
import { getTerminalConfig, saveTerminalConfig } from '../controller/terminal-config.js'
import { getServerListConfig, saveServerListConfig } from '../controller/server-list-config.js'
import { getSuspendedSessions, getTerminalSessionConfig, updateTerminalSessionConfig } from '../controller/terminal.js'
import { getNativeSshConnection } from '../controller/native.js'
const ssh = [
{
@@ -420,7 +420,7 @@ const sftp = [
}
]
module.exports = [].concat(
export default [].concat(
ssh,
host,
user,
+5 -5
View File
@@ -1,7 +1,7 @@
const schedule = require('node-schedule')
const { sendNoticeAsync } = require('../utils/notify')
const { formatTimestamp } = require('../utils/tools')
const { HostListDB } = require('../utils/db-class')
import schedule from 'node-schedule'
import { sendNoticeAsync } from '../utils/notify.js'
import { formatTimestamp } from '../utils/tools.js'
import { HostListDB } from '../utils/db-class.js'
const hostListDB = new HostListDB().getInstance()
const expiredNotifyJob = async () => {
@@ -27,6 +27,6 @@ const expiredNotifyJob = async () => {
}
}
module.exports = () => {
export default () => {
schedule.scheduleJob('0 0 12 1/1 * ?', expiredNotifyJob)
}
+20 -20
View File
@@ -1,22 +1,22 @@
const Koa = require('koa')
const compose = require('koa-compose') // 组合中间件,简化写法
const http = require('http')
const https = require('https')
const fs = require('fs')
const { httpPort, httpsPort, enableHttps, sslCertPath, sslKeyPath } = require('./config')
const middlewares = require('./middlewares')
const { startRdpServer } = require('./rdp-server')
const wsTerminal = require('./socket/terminal')
const wsSftpV2 = require('./socket/sftp-v2')
const wsDocker = require('./socket/docker')
const wsOnekey = require('./socket/onekey')
const wsServerStatus = require('./socket/server-status')
const wsFileTransfer = require('./socket/file-transfer')
const { throwError, isAllowedIp, getClientIP } = require('./utils/tools')
const { SessionDB } = require('./utils/db-class')
const { parseCookies } = require('./utils/verify-auth')
const { generateSelfSignedCert } = require('./utils/ssl-cert')
const createRdpProxyMiddleware = require('./middlewares/rdp-proxy')
import Koa from 'koa'
import compose from 'koa-compose' // 组合中间件,简化写法
import http from 'node:http'
import https from 'node:https'
import fs from 'node:fs'
import { httpPort, httpsPort, enableHttps, sslCertPath, sslKeyPath } from './config/index.js'
import middlewares from './middlewares/index.js'
import { startRdpServer } from './rdp-server.js'
import wsTerminal from './socket/terminal.js'
import wsSftpV2 from './socket/sftp-v2.js'
import wsDocker from './socket/docker.js'
import wsOnekey from './socket/onekey.js'
import wsServerStatus from './socket/server-status.js'
import wsFileTransfer from './socket/file-transfer.js'
import { throwError, isAllowedIp, getClientIP } from './utils/tools.js'
import { SessionDB } from './utils/db-class.js'
import { parseCookies } from './utils/verify-auth.js'
import { generateSelfSignedCert } from './utils/ssl-cert.js'
import createRdpProxyMiddleware from './middlewares/rdp-proxy.js'
const sessionDB = new SessionDB().getInstance()
@@ -177,6 +177,6 @@ function serverHandler(app, server, httpsServer) {
})
}
module.exports = {
export {
createServer
}
+11 -7
View File
@@ -1,8 +1,12 @@
const path = require('path')
const { Client: SSHClient } = require('ssh2')
const { createTerminal } = require('./terminal')
const decryptAndExecuteAsync = require('../utils/decrypt-file')
const { createSecureWs } = require('../utils/ws-tool')
import path, { dirname } from 'node:path'
import { fileURLToPath } from 'node:url'
import ssh2Module from 'ssh2'
const { Client: SSHClient } = ssh2Module
import { createTerminal } from './terminal.js'
import decryptAndExecuteAsync from '../utils/decrypt-file.js'
import { createSecureWs } from '../utils/ws-tool.js'
const currentDir = dirname(fileURLToPath(import.meta.url))
let executeCommand = () => {
return new Promise((resolve) => {
@@ -129,7 +133,7 @@ async function deleteDockerContainer(targetSSHClient, containerId) {
}
}
module.exports = (httpServer) => {
export default (httpServer) => {
const serverIo = createSecureWs(httpServer, '/docker')
let connectionCount = 0
@@ -144,7 +148,7 @@ module.exports = (httpServer) => {
targetSSHClient = new SSHClient()
let { jumpSshClients: dockerJumpSshClients } = await createTerminal(hostId, socket, targetSSHClient, false)
jumpSshClients.push(...dockerJumpSshClients)
let { getDockerContainers = null, executeCommand: dockerExecuteCommand } = (await decryptAndExecuteAsync(path.join(__dirname, 'plus.js'))) || {}
let { getDockerContainers = null, executeCommand: dockerExecuteCommand } = (await decryptAndExecuteAsync(path.join(currentDir, 'plus.js'))) || {}
executeCommand = dockerExecuteCommand
if (!getDockerContainers) {
socket.emit('docker_not_plus')
+12 -10
View File
@@ -1,13 +1,16 @@
const path = require('path')
const { Client: SSHClient } = require('ssh2')
const { fileTransferThrottle } = require('../utils/tools')
const { createSecureWs } = require('../utils/ws-tool')
const { getConnectionOptions } = require('./terminal')
const { FileTransferDB, HostListDB } = require('../utils/db-class')
const decryptAndExecuteAsync = require('../utils/decrypt-file')
import path, { dirname } from 'node:path'
import { fileURLToPath } from 'node:url'
import ssh2Module from 'ssh2'
const { Client: SSHClient } = ssh2Module
import { fileTransferThrottle } from '../utils/tools.js'
import { createSecureWs } from '../utils/ws-tool.js'
import { getConnectionOptions } from './terminal.js'
import { FileTransferDB, HostListDB } from '../utils/db-class.js'
import decryptAndExecuteAsync from '../utils/decrypt-file.js'
const fileTransferDB = new FileTransferDB().getInstance()
const hostListDB = new HostListDB().getInstance()
const currentDir = dirname(fileURLToPath(import.meta.url))
// 全局传输任务管理
const activeTasks = new Map() // taskId -> { process, sshClient, status, ... }
@@ -53,7 +56,7 @@ async function getSortedTasksList() {
return sortTasks(tasksWithStatus)
}
module.exports = (httpServer) => {
export default (httpServer) => {
const serverIo = createSecureWs(httpServer, '/file-transfer')
let connectionCount = 0
@@ -83,7 +86,7 @@ module.exports = (httpServer) => {
// 启动传输任务
socket.on('start_transfer', async (transferConfig) => {
try {
const { createTransferTask = null } = (await decryptAndExecuteAsync(path.join(__dirname, 'plus.js'))) || {}
const { createTransferTask = null } = (await decryptAndExecuteAsync(path.join(currentDir, 'plus.js'))) || {}
if (!createTransferTask) throw new Error('Plus功能解锁失败: createTransferTask')
const task = await createTransferTask(transferConfig, socket, hostListDB, fileTransferDB, executeTransfer)
socket.emit('task_started', { taskId: task.taskId, message: '传输任务已启动' })
@@ -926,4 +929,3 @@ function stopProgressBroadcast(socket) {
logger.info('已停止进度广播定时器')
}
}
+9 -8
View File
@@ -1,10 +1,11 @@
const { Server } = require('socket.io')
const { Client: SSHClient } = require('ssh2')
const { sendNoticeAsync } = require('../utils/notify')
const { shellThrottle } = require('../utils/tools')
const { createSecureWs } = require('../utils/ws-tool')
const { HostListDB, OnekeyDB } = require('../utils/db-class')
const { getConnectionOptions, handleProxyAndJumpHostConnection } = require('./terminal')
import { Server } from 'socket.io'
import ssh2Module from 'ssh2'
const { Client: SSHClient } = ssh2Module
import { sendNoticeAsync } from '../utils/notify.js'
import { shellThrottle } from '../utils/tools.js'
import { createSecureWs } from '../utils/ws-tool.js'
import { HostListDB, OnekeyDB } from '../utils/db-class.js'
import { getConnectionOptions, handleProxyAndJumpHostConnection } from './terminal.js'
const hostListDB = new HostListDB().getInstance()
const onekeyDB = new OnekeyDB().getInstance()
@@ -88,7 +89,7 @@ function execShell(socket, sshClient, curRes, resolve) {
})
}
module.exports = (httpServer) => {
export default (httpServer) => {
const serverIo = createSecureWs(httpServer, '/onekey')
serverIo.on('connection', async (socket) => {
File diff suppressed because one or more lines are too long
+8 -8
View File
@@ -1,12 +1,12 @@
const { Client: SSHClient } = require('ssh2')
const { createTerminal } = require('./terminal')
const { createSecureWs } = require('../utils/ws-tool')
import ssh2Module from 'ssh2'
const { Client: SSHClient } = ssh2Module
import { createTerminal } from './terminal.js'
import { createSecureWs } from '../utils/ws-tool.js'
const monitorMap = new Map() // key -> { sockets: Set, statusData, stop }
const pendingConnections = new Map() // key -> Promise,跟踪正在创建的连接
const { HostListDB } = require('../utils/db-class')
import { HostListDB } from '../utils/db-class.js'
const hostListDB = new HostListDB().getInstance()
/* eslint-disable no-control-regex */
function stripAnsi(s = '') {
return s
.replace(/\x1B\[[0-?]*[ -/]*[@-~]/g, '') // CSI
@@ -16,7 +16,7 @@ function stripAnsi(s = '') {
const safeDelta = (curr, prev) => (curr >= prev ? curr - prev : 0)
module.exports = (httpServer) => {
export default (httpServer) => {
const serverIo = createSecureWs(httpServer, '/server-status')
let connectionCount = 0
@@ -593,7 +593,7 @@ module.exports = (httpServer) => {
try {
const cgroupMem = await getCgroupMemoryInfo()
if (cgroupMem) {
if (cgroupMem.memTotalBytes != null) {
if (cgroupMem.memTotalBytes !== null) {
const cgroupTotalMb = Math.round(cgroupMem.memTotalBytes / 1024 / 1024)
if (cgroupTotalMb > 0 && cgroupTotalMb < memInfo.totalMemMb) {
const cgroupUsedMb = Math.max(0, Math.min(Math.round(cgroupMem.memUsedBytes / 1024 / 1024), cgroupTotalMb))
@@ -607,7 +607,7 @@ module.exports = (httpServer) => {
}
}
}
if (cgroupMem.swapTotalBytes != null) {
if (cgroupMem.swapTotalBytes !== null) {
const cgroupSwapTotalMb = Math.round(cgroupMem.swapTotalBytes / 1024 / 1024)
if (cgroupSwapTotalMb > 0 && (swapInfo.swapTotal === 0 || cgroupSwapTotalMb < swapInfo.swapTotal)) {
const cgroupSwapUsedMb = Math.max(0, Math.min(Math.round(cgroupMem.swapUsedBytes / 1024 / 1024), cgroupSwapTotalMb))
+13 -12
View File
@@ -1,16 +1,17 @@
const rawPath = require('path')
const fs = require('fs-extra')
const SFTPClient = require('ssh2-sftp-client')
const iconv = require('iconv-lite')
const chardet = require('chardet')
const { v4: uuidv4 } = require('uuid')
const { sftpCacheDir } = require('../config')
const { createSecureWs } = require('../utils/ws-tool')
const { HostListDB, FavoriteSftpDB } = require('../utils/db-class')
const { getConnectionOptions, handleProxyAndJumpHostConnection } = require('./terminal')
import rawPath from 'node:path'
import fs from 'fs-extra'
import SFTPClient from 'ssh2-sftp-client'
import iconv from 'iconv-lite'
import chardet from 'chardet'
import { v4 as uuidv4 } from 'uuid'
import { sftpCacheDir } from '../config/index.js'
import { createSecureWs } from '../utils/ws-tool.js'
import { HostListDB, FavoriteSftpDB } from '../utils/db-class.js'
import { getConnectionOptions, handleProxyAndJumpHostConnection } from './terminal.js'
const hostListDB = new HostListDB().getInstance()
const favoriteSftpDB = new FavoriteSftpDB().getInstance()
const { Client: SSHClient } = require('ssh2')
import ssh2Module from 'ssh2'
const { Client: SSHClient } = ssh2Module
function shellEscape(s) {
// eslint-disable-next-line quotes
@@ -1559,7 +1560,7 @@ const listenAction = (sftpClient, socket) => {
}
}
module.exports = (httpServer) => {
export default (httpServer) => {
const serverIo = createSecureWs(httpServer, '/sftp-v2', {
// 增加消息大小限制,支持大文件上传(默认1MB)
maxHttpBufferSize: 10 * 1024 * 1024, // 10MB
+23 -18
View File
@@ -1,17 +1,20 @@
const path = require('path')
const { Client: SSHClient } = require('ssh2')
const { sendNoticeAsync } = require('../utils/notify')
const { ping } = require('../utils/tools')
const { AESDecryptAsync } = require('../utils/encrypt')
const { KeyDB, HostListDB, CredentialsDB, ProxyDB } = require('../utils/db-class')
const decryptAndExecuteAsync = require('../utils/decrypt-file')
const { sessionManager, SessionStatus } = require('../utils/terminal-session')
const { createSecureWs } = require('../utils/ws-tool')
import path, { dirname } from 'node:path'
import { fileURLToPath } from 'node:url'
import ssh2Module from 'ssh2'
const { Client: SSHClient } = ssh2Module
import { sendNoticeAsync } from '../utils/notify.js'
import { ping } from '../utils/tools.js'
import { AESDecryptAsync } from '../utils/encrypt.js'
import { KeyDB, HostListDB, CredentialsDB, ProxyDB } from '../utils/db-class.js'
import decryptAndExecuteAsync from '../utils/decrypt-file.js'
import { sessionManager, SessionStatus } from '../utils/terminal-session.js'
import { createSecureWs } from '../utils/ws-tool.js'
const hostListDB = new HostListDB().getInstance()
const credentialsDB = new CredentialsDB().getInstance()
const proxyDB = new ProxyDB().getInstance()
const keyDB = new KeyDB().getInstance()
const currentDir = dirname(fileURLToPath(import.meta.url))
async function getConnectionOptions(hostId) {
const hostInfo = await hostListDB.findOneAsync({ _id: hostId })
@@ -137,11 +140,11 @@ async function handleProxyAndJumpHostConnection(options) {
let proxySocket
if (proxyConfig.type === 'socks5') {
const { createSocks5Connection = null } = (await decryptAndExecuteAsync(path.join(__dirname, 'plus.js'))) || {}
const { createSocks5Connection = null } = (await decryptAndExecuteAsync(path.join(currentDir, 'plus.js'))) || {}
if (!createSocks5Connection) throw new Error('Plus功能解锁失败: createSocks5Connection')
proxySocket = await createSocks5Connection(proxyConfig, targetConnectionOptions.host, targetConnectionOptions.port)
} else if (proxyConfig.type === 'http') {
const { createHttpConnection = null } = (await decryptAndExecuteAsync(path.join(__dirname, 'plus.js'))) || {}
const { createHttpConnection = null } = (await decryptAndExecuteAsync(path.join(currentDir, 'plus.js'))) || {}
if (!createHttpConnection) throw new Error('Plus功能解锁失败: createHttpConnection')
proxySocket = await createHttpConnection(proxyConfig, targetConnectionOptions.host, targetConnectionOptions.port)
} else {
@@ -163,7 +166,7 @@ async function handleProxyAndJumpHostConnection(options) {
}
// 跳板机连接
else if (proxyType === 'jumpHosts' && Array.isArray(jumpHosts) && jumpHosts.length > 0) {
const { connectByJumpHosts = null } = (await decryptAndExecuteAsync(path.join(__dirname, 'plus.js'))) || {}
const { connectByJumpHosts = null } = (await decryptAndExecuteAsync(path.join(currentDir, 'plus.js'))) || {}
if (!connectByJumpHosts) throw new Error('Plus功能解锁失败: connectByJumpHosts')
const jumpHostResult = await connectByJumpHosts(jumpHosts, targetConnectionOptions.host, targetConnectionOptions.port, socket)
if (jumpHostResult) {
@@ -538,13 +541,15 @@ function createServerIo(serverIo) {
})
}
module.exports = (httpServer) => {
export default (httpServer) => {
const serverIo = createSecureWs(httpServer, '/terminal')
createServerIo(serverIo)
}
module.exports.getConnectionOptions = getConnectionOptions
module.exports.createTerminal = createTerminal
module.exports.createServerIo = createServerIo
module.exports.getProxyConfig = getProxyConfig
module.exports.handleProxyAndJumpHostConnection = handleProxyAndJumpHostConnection
export {
getConnectionOptions,
createTerminal,
createServerIo,
getProxyConfig,
handleProxyAndJumpHostConnection
}
+1 -1
View File
@@ -1,4 +1,4 @@
module.exports = (content) => {
export default (content) => {
return `<!DOCTYPE html>
<html>
<head>
+22 -22
View File
@@ -1,5 +1,5 @@
const Datastore = require('@seald-io/nedb')
const {
import Datastore from '@seald-io/nedb'
import {
credentialsDBPath,
hostListDBPath,
keyDBPath,
@@ -19,9 +19,9 @@ const {
serverListDBPath,
sessionDBPath,
terminalSessionDBPath
} = require('../config')
} from '../config/index.js'
module.exports.KeyDB = class KeyDB {
export class KeyDB {
constructor() {
if (!KeyDB.instance) {
KeyDB.instance = new Datastore({ filename: keyDBPath, autoload: true })
@@ -33,7 +33,7 @@ module.exports.KeyDB = class KeyDB {
}
}
module.exports.HostListDB = class HostListDB {
export class HostListDB {
constructor() {
if (!HostListDB.instance) {
HostListDB.instance = new Datastore({ filename: hostListDBPath, autoload: true })
@@ -45,7 +45,7 @@ module.exports.HostListDB = class HostListDB {
}
}
module.exports.CredentialsDB = class CredentialsDB {
export class CredentialsDB {
constructor() {
if (!CredentialsDB.instance) {
CredentialsDB.instance = new Datastore({ filename: credentialsDBPath, autoload: true })
@@ -57,7 +57,7 @@ module.exports.CredentialsDB = class CredentialsDB {
}
}
module.exports.NotifyDB = class NotifyDB {
export class NotifyDB {
constructor() {
if (!NotifyDB.instance) {
NotifyDB.instance = new Datastore({ filename: notifyDBPath, autoload: true })
@@ -69,7 +69,7 @@ module.exports.NotifyDB = class NotifyDB {
}
}
module.exports.NotifyConfigDB = class NotifyConfigDB {
export class NotifyConfigDB {
constructor() {
if (!NotifyConfigDB.instance) {
NotifyConfigDB.instance = new Datastore({ filename: notifyConfigDBPath, autoload: true })
@@ -81,7 +81,7 @@ module.exports.NotifyConfigDB = class NotifyConfigDB {
}
}
module.exports.GroupDB = class GroupDB {
export class GroupDB {
constructor() {
if (!GroupDB.instance) {
GroupDB.instance = new Datastore({ filename: groupConfDBPath, autoload: true })
@@ -93,7 +93,7 @@ module.exports.GroupDB = class GroupDB {
}
}
module.exports.ScriptsDB = class ScriptsDB {
export class ScriptsDB {
constructor() {
if (!ScriptsDB.instance) {
ScriptsDB.instance = new Datastore({ filename: scriptsDBPath, autoload: true })
@@ -105,7 +105,7 @@ module.exports.ScriptsDB = class ScriptsDB {
}
}
module.exports.ScriptGroupDB = class ScriptGroupDB {
export class ScriptGroupDB {
constructor() {
if (!ScriptGroupDB.instance) {
ScriptGroupDB.instance = new Datastore({ filename: scriptGroupDBPath, autoload: true })
@@ -116,7 +116,7 @@ module.exports.ScriptGroupDB = class ScriptGroupDB {
}
}
module.exports.OnekeyDB = class OnekeyDB {
export class OnekeyDB {
constructor() {
if (!OnekeyDB.instance) {
OnekeyDB.instance = new Datastore({ filename: onekeyDBPath, autoload: true })
@@ -128,7 +128,7 @@ module.exports.OnekeyDB = class OnekeyDB {
}
}
module.exports.PlusDB = class PlusDB {
export class PlusDB {
constructor() {
if (!PlusDB.instance) {
PlusDB.instance = new Datastore({ filename: plusDBPath, autoload: true })
@@ -139,7 +139,7 @@ module.exports.PlusDB = class PlusDB {
}
}
module.exports.AIConfigDB = class AIConfigDB {
export class AIConfigDB {
constructor() {
if (!AIConfigDB.instance) {
AIConfigDB.instance = new Datastore({ filename: aiConfigDBPath, autoload: true })
@@ -150,7 +150,7 @@ module.exports.AIConfigDB = class AIConfigDB {
}
}
module.exports.ChatHistoryDB = class ChatHistoryDB {
export class ChatHistoryDB {
constructor() {
if (!ChatHistoryDB.instance) {
ChatHistoryDB.instance = new Datastore({ filename: chatHistoryDBPath, autoload: true })
@@ -161,7 +161,7 @@ module.exports.ChatHistoryDB = class ChatHistoryDB {
}
}
module.exports.FavoriteSftpDB = class FavoriteSftpDB {
export class FavoriteSftpDB {
constructor() {
if (!FavoriteSftpDB.instance) {
FavoriteSftpDB.instance = new Datastore({ filename: favoriteSftpDBPath, autoload: true })
@@ -172,7 +172,7 @@ module.exports.FavoriteSftpDB = class FavoriteSftpDB {
}
}
module.exports.ProxyDB = class ProxyDB {
export class ProxyDB {
constructor() {
if (!ProxyDB.instance) {
ProxyDB.instance = new Datastore({ filename: proxyDBPath, autoload: true })
@@ -183,7 +183,7 @@ module.exports.ProxyDB = class ProxyDB {
}
}
module.exports.FileTransferDB = class FileTransferDB {
export class FileTransferDB {
constructor() {
if (!FileTransferDB.instance) {
FileTransferDB.instance = new Datastore({ filename: fileTransferDBPath, autoload: true })
@@ -194,7 +194,7 @@ module.exports.FileTransferDB = class FileTransferDB {
}
}
module.exports.TerminalConfigDB = class TerminalConfigDB {
export class TerminalConfigDB {
constructor() {
if (!TerminalConfigDB.instance) {
TerminalConfigDB.instance = new Datastore({ filename: terminalConfigDBPath, autoload: true })
@@ -205,7 +205,7 @@ module.exports.TerminalConfigDB = class TerminalConfigDB {
}
}
module.exports.ServerListDB = class ServerListDB {
export class ServerListDB {
constructor() {
if (!ServerListDB.instance) {
ServerListDB.instance = new Datastore({ filename: serverListDBPath, autoload: true })
@@ -216,7 +216,7 @@ module.exports.ServerListDB = class ServerListDB {
}
}
module.exports.SessionDB = class SessionDB {
export class SessionDB {
constructor() {
if (!SessionDB.instance) {
SessionDB.instance = new Datastore({ filename: sessionDBPath, autoload: true })
@@ -227,7 +227,7 @@ module.exports.SessionDB = class SessionDB {
}
}
module.exports.TerminalSessionDB = class TerminalSessionDB {
export class TerminalSessionDB {
constructor() {
if (!TerminalSessionDB.instance) {
TerminalSessionDB.instance = new Datastore({ filename: terminalSessionDBPath, autoload: true })
+139 -52
View File
@@ -1,56 +1,143 @@
const fs = require('fs-extra')
const path = require('path')
const CryptoJS = require('crypto-js')
const { AESDecryptAsync } = require('./encrypt')
const { RuntimeState } = require('./runtime-state')
import fs from 'fs-extra'
import { createRequire } from 'node:module'
import path from 'node:path'
import { pathToFileURL } from 'node:url'
import CryptoJS from 'crypto-js'
import { init, parse } from 'es-module-lexer'
import { AESDecryptAsync, SHA256Encrypt } from './encrypt.js'
import { RuntimeState } from './runtime-state.js'
const runtimeState = new RuntimeState().getInstance()
const plusModuleCache = new Map()
const dataModuleUrlPattern = /data:text\/javascript;base64,[A-Za-z0-9+/]+={0,2}(?:#[A-Za-z0-9._-]+)?/g
const moduleLexerReady = init
function decryptAndExecuteAsync(plusPath) {
return new Promise(async (resolve) => {
try {
const decryptKeyCipher = runtimeState.getDecryptKey()
if (!decryptKeyCipher) {
throw new Error('缺少解密密钥')
}
const decryptKey = await AESDecryptAsync(decryptKeyCipher)
if (!decryptKey) {
throw new Error('解密密钥解析失败')
}
const encryptedContent = fs.readFileSync(plusPath, 'utf-8')
const bytes = CryptoJS.AES.decrypt(encryptedContent, decryptKey)
const decryptedContent = bytes.toString(CryptoJS.enc.Utf8)
if (!decryptedContent) {
throw new Error('解密失败,请检查密钥是否正确')
}
const customRequire = (modulePath) => {
if (modulePath.startsWith('.')) {
const absolutePath = path.resolve(path.dirname(plusPath), modulePath)
return require(absolutePath)
}
return require(modulePath)
}
const module = {
exports: {},
require: customRequire,
__filename: plusPath,
__dirname: path.dirname(plusPath)
}
const wrapper = Function('module', 'exports', 'require', '__filename', '__dirname',
decryptedContent + '\n return module.exports;'
)
const exports = wrapper(
module,
module.exports,
customRequire,
module.__filename,
module.__dirname
)
resolve(exports)
} catch (error) {
logger.info('解锁plus功能失败: ', error.message)
resolve(null)
}
})
function isPlusAvailable() {
return Boolean(runtimeState.getDecryptKey()) && !runtimeState.getPlusKicked()
}
module.exports = decryptAndExecuteAsync
function sanitizeLoaderError(error) {
const message = error?.message || String(error)
return message.replace(dataModuleUrlPattern, '[Plus ESM module]')
}
async function resolveImportSpecifiers(source, plusPath) {
await moduleLexerReady
const moduleUrl = pathToFileURL(path.resolve(plusPath))
const resolver = createRequire(moduleUrl)
const resolveSpecifier = (specifier) => {
if (specifier.startsWith('node:')) return specifier
if (specifier.startsWith('.') || specifier.startsWith('/')) {
return new URL(specifier, moduleUrl).href
}
const resolvedPath = resolver.resolve(specifier)
return resolvedPath.startsWith('node:') ? resolvedPath : pathToFileURL(resolvedPath).href
}
const [imports] = parse(source)
let resolvedSource = source
// 从后向前替换,保证 lexer 返回的源码下标不会因前面的替换而偏移。
for (let index = imports.length - 1; index >= 0; index -= 1) {
const importRecord = imports[index]
// 非字面量动态导入(如 import(moduleName))在运行时才能确定,保持原样。
if (typeof importRecord.n !== 'string') continue
const resolvedSpecifier = resolveSpecifier(importRecord.n)
const quote = importRecord.d >= 0 ? source[importRecord.s] : ''
const replacement = quote === '\'' || quote === '"' || quote === '`'
? `${ quote }${ resolvedSpecifier }${ quote }`
: resolvedSpecifier
resolvedSource = `${ resolvedSource.slice(0, importRecord.s) }${ replacement }${ resolvedSource.slice(importRecord.e) }`
}
return resolvedSource
}
async function resolveDecryptKey(decryptKeyCipher) {
const decryptKey = await AESDecryptAsync(decryptKeyCipher)
if (!decryptKey) {
throw new Error('解密密钥解析失败')
}
return {
decryptKey,
fingerprint: SHA256Encrypt(decryptKey)
}
}
async function decryptAndImportOnce(plusPath, decryptKey) {
const encryptedContent = await fs.readFile(plusPath, 'utf-8')
const bytes = CryptoJS.AES.decrypt(encryptedContent, decryptKey)
const decryptedContent = bytes.toString(CryptoJS.enc.Utf8)
if (!decryptedContent) {
throw new Error('解密失败,请检查密钥是否正确')
}
const esmContent = await resolveImportSpecifiers(decryptedContent, plusPath)
const moduleId = path.basename(path.dirname(plusPath))
const sourceLabel = `easynode-plus-${ moduleId }.mjs`
const encodedContent = Buffer.from(`${ esmContent }\n//# sourceURL=${ sourceLabel }\n`).toString('base64')
return import(`data:text/javascript;base64,${ encodedContent }#plus-${ moduleId }`)
}
function createCacheEntry(absolutePath, decryptKeyCipher) {
const entry = {
keyFingerprint: null,
validatedCipher: decryptKeyCipher,
modulePromise: null
}
entry.modulePromise = resolveDecryptKey(decryptKeyCipher)
.then(({ decryptKey, fingerprint }) => {
entry.keyFingerprint = fingerprint
return decryptAndImportOnce(absolutePath, decryptKey)
})
.catch((error) => {
if (plusModuleCache.get(absolutePath) === entry) {
plusModuleCache.delete(absolutePath)
}
throw error
})
plusModuleCache.set(absolutePath, entry)
return entry
}
async function validateCachedAuthorization(entry, decryptKeyCipher) {
if (entry.validatedCipher === decryptKeyCipher) return
const [, currentAuth] = await Promise.all([
entry.modulePromise,
resolveDecryptKey(decryptKeyCipher)
])
if (entry.keyFingerprint !== currentAuth.fingerprint) {
throw new Error('Plus解密密钥已变化')
}
// 同一明文密钥重新激活时密文会变化,仅在状态仍有效时记录本次校验结果。
if (isPlusAvailable() && runtimeState.getDecryptKey() === decryptKeyCipher) {
entry.validatedCipher = decryptKeyCipher
}
}
async function decryptAndExecuteAsync(plusPath) {
try {
if (!isPlusAvailable()) {
throw new Error(runtimeState.getPlusKicked() ? 'Plus授权已失效' : '缺少解密密钥')
}
const absolutePath = path.resolve(plusPath)
const decryptKeyCipher = runtimeState.getDecryptKey()
const entry = plusModuleCache.get(absolutePath)
|| createCacheEntry(absolutePath, decryptKeyCipher)
await validateCachedAuthorization(entry, decryptKeyCipher)
const plusModule = await entry.modulePromise
// 加载过程中授权可能被清除,返回模块前再次校验。
if (!isPlusAvailable() || runtimeState.getDecryptKey() !== decryptKeyCipher) {
throw new Error('Plus授权状态已变化')
}
return plusModule
} catch (error) {
logger.info('解锁plus功能失败: ', sanitizeLoaderError(error))
return null
}
}
export default decryptAndExecuteAsync
+5 -5
View File
@@ -1,7 +1,7 @@
const CryptoJS = require('crypto-js')
const rawCrypto = require('crypto')
const NodeRSA = require('node-rsa')
const { KeyDB } = require('./db-class')
import CryptoJS from 'crypto-js'
import rawCrypto from 'node:crypto'
import NodeRSA from 'node-rsa'
import { KeyDB } from './db-class.js'
const keyDB = new KeyDB().getInstance()
// rsa非对称 私钥解密
@@ -41,7 +41,7 @@ const SHA256Encrypt = (clearText) => {
return rawCrypto.createHash('sha256').update(clearText).digest('hex')
}
module.exports = {
export {
RSADecryptAsync,
AESEncryptAsync,
AESDecryptAsync,
+14 -11
View File
@@ -1,20 +1,23 @@
const crypto = require('crypto')
const path = require('path')
const { requestWithFailover } = require('./tools')
const { AESEncryptAsync } = require('./encrypt')
const decryptAndExecuteAsync = require('./decrypt-file')
const version = require('../../package.json').version
const { PlusDB } = require('./db-class')
const { RuntimeState } = require('./runtime-state')
import crypto from 'node:crypto'
import path, { dirname } from 'node:path'
import { fileURLToPath } from 'node:url'
import { requestWithFailover } from './tools.js'
import { AESEncryptAsync } from './encrypt.js'
import decryptAndExecuteAsync from './decrypt-file.js'
import PackageJsonModule from '../../package.json' with { type: 'json' }
const version = PackageJsonModule.version
import { PlusDB } from './db-class.js'
import { RuntimeState } from './runtime-state.js'
const plusDB = new PlusDB().getInstance()
const runtimeState = new RuntimeState().getInstance()
const currentDir = dirname(fileURLToPath(import.meta.url))
const RETRY_INTERVAL_MS = 30 * 1000
let maxRetryCount = 3
let retryTimer = null
async function startHeartbeatIfAvailable() {
const plusModule = await decryptAndExecuteAsync(path.join(__dirname, '../controller/plus.js'))
const plusModule = await decryptAndExecuteAsync(path.join(currentDir, '../controller/plus.js'))
if (typeof plusModule?.startHeartbeat === 'function') {
plusModule.startHeartbeat()
} else {
@@ -102,5 +105,5 @@ function scheduleNextActivation() {
if (retryTimer.unref) retryTimer.unref()
}
module.exports = getLicenseInfo
module.exports.startActivation = activateOrRetry
export default getLicenseInfo
export { activateOrRetry as startActivation }
+7 -7
View File
@@ -1,9 +1,9 @@
const nodemailer = require('nodemailer')
const TelegramBot = require('node-telegram-bot-api')
const axios = require('axios')
const FormData = require('form-data')
const commonTemp = require('../template/commonTemp')
const { NotifyDB, NotifyConfigDB } = require('./db-class')
import nodemailer from 'nodemailer'
import TelegramBot from 'node-telegram-bot-api'
import axios from 'axios'
import FormData from 'form-data'
import commonTemp from '../template/commonTemp.js'
import { NotifyDB, NotifyConfigDB } from './db-class.js'
const notifyConfigDB = new NotifyConfigDB().getInstance()
const notifyDB = new NotifyDB().getInstance()
@@ -251,7 +251,7 @@ async function sendNoticeAsync(noticeAction, title, content) {
}
}
module.exports = {
export {
sendNoticeAsync,
sendServerChan,
sendEmail,
+6 -6
View File
@@ -1,6 +1,6 @@
module.exports = {
plusServers: [
'https://easynode-auth1.chaoszhu.com',
'https://easynode-auth2.chaoszhu.com'
]
}
const plusServers = [
'https://easynode-auth1.chaoszhu.com',
'https://easynode-auth2.chaoszhu.com'
]
export { plusServers }
+1 -1
View File
@@ -70,4 +70,4 @@ class RuntimeState {
}
}
module.exports = { RuntimeState }
export { RuntimeState }
+2 -2
View File
@@ -1,4 +1,4 @@
const selfsigned = require('selfsigned')
import selfsigned from 'selfsigned'
/**
* 生成自签名证书
@@ -53,6 +53,6 @@ function generateSelfSignedCert() {
}
}
module.exports = {
export {
generateSelfSignedCert
}
+4 -4
View File
@@ -200,7 +200,7 @@ class TerminalSession {
}
// 创建新的SSH连接
const { Client: SSHClient } = require('ssh2')
const { Client: SSHClient } = (await import('ssh2')).default
const newClient = new SSHClient()
await new Promise((resolve, reject) => {
@@ -299,7 +299,7 @@ class SessionManager {
*/
async loadConfigFromDB() {
try {
const { TerminalSessionDB } = require('./db-class')
const { TerminalSessionDB } = await import('./db-class.js')
const terminalSessionDB = new TerminalSessionDB().getInstance()
const config = await terminalSessionDB.findOneAsync({})
@@ -327,7 +327,7 @@ class SessionManager {
// 数据库中存储的是KB,需要转换为字节
this.maxBufferSize = config.maxBufferSize * 1024
}
logger.info(`已从数据库加载终端会话配置: maxSuspendedPerUser=${this.maxSuspendedPerUser}, maxSuspendTime=${this.maxSuspendTime / 1000 / 60 / 60}小时`)
logger.info(`已从数据库加载终端会话配置: maxSuspendedPerUser=${ this.maxSuspendedPerUser }, maxSuspendTime=${ this.maxSuspendTime / 1000 / 60 / 60 }小时`)
} else {
logger.info('数据库中无终端会话配置,使用默认配置')
}
@@ -644,7 +644,7 @@ class SessionManager {
// 导出单例
const sessionManager = new SessionManager()
module.exports = {
export {
SessionStatus,
TerminalSession,
sessionManager,
+8 -8
View File
@@ -1,11 +1,11 @@
const { exec } = require('child_process')
const crypto = require('crypto')
const os = require('os')
const net = require('net')
const iconv = require('iconv-lite')
const axios = require('axios')
import { exec } from 'node:child_process'
import crypto from 'node:crypto'
import os from 'node:os'
import net from 'node:net'
import iconv from 'iconv-lite'
import axios from 'axios'
const request = axios.create({ timeout: 3000 })
const { plusServers } = require('./plus-server')
import { plusServers } from './plus-server.js'
// 为空时请求本地IP
const getNetIPInfo = async (searchIp = '') => {
@@ -438,7 +438,7 @@ const timingSafeEqual = (a, b) => {
return crypto.timingSafeEqual(bufA, bufB)
}
module.exports = {
export {
getNetIPInfo,
getLocalNetIP,
throwError,
+6 -6
View File
@@ -1,8 +1,8 @@
const jwt = require('jsonwebtoken')
const { AESDecryptAsync } = require('./encrypt')
const { isAllowedIp, getClientIP } = require('../utils/tools')
const { SHA256Encrypt } = require('../utils/encrypt')
const { KeyDB, SessionDB } = require('./db-class')
import jwt from 'jsonwebtoken'
import { AESDecryptAsync } from './encrypt.js'
import { isAllowedIp, getClientIP } from '../utils/tools.js'
import { SHA256Encrypt } from '../utils/encrypt.js'
import { KeyDB, SessionDB } from './db-class.js'
const keyDB = new KeyDB().getInstance()
const sessionDB = new SessionDB().getInstance()
@@ -95,7 +95,7 @@ const verifyWsAuthSync = async (socket, next) => {
next()
}
module.exports = {
export {
enumLoginCode,
verifyAuthSync,
verifyWsAuthSync,
+4 -4
View File
@@ -1,5 +1,5 @@
const { Server } = require('socket.io')
const { verifyWsAuthSync } = require('./verify-auth')
import { Server } from 'socket.io'
import { verifyWsAuthSync } from './verify-auth.js'
const createSecureWs = (httpServer, path, otherConfig = {}) => {
const serverIo = new Server(httpServer, {
@@ -16,6 +16,6 @@ const createSecureWs = (httpServer, path, otherConfig = {}) => {
return serverIo
}
module.exports = {
export {
createSecureWs
}
}
+3 -3
View File
@@ -1,3 +1,3 @@
#!/usr/bin/env node
console.log('start time', new Date())
require('../index.js')
#!/usr/bin/env node
console.log('start time', new Date())
await import('../index.js')
+7 -3
View File
@@ -1,7 +1,11 @@
const { spawn } = require('child_process')
const treeKill = require('tree-kill')
import { spawn } from 'node:child_process'
import { createRequire } from 'node:module'
import { dirname } from 'node:path'
import { fileURLToPath } from 'node:url'
import treeKill from 'tree-kill'
const serverRoot = __dirname
const serverRoot = dirname(fileURLToPath(import.meta.url))
const require = createRequire(import.meta.url)
const nodemonBin = require.resolve('nodemon/bin/nodemon.js')
const child = spawn(process.execPath, [nodemonBin, 'index.js'], {
cwd: serverRoot,
+6 -3
View File
@@ -1,5 +1,8 @@
// AES-256-CBC requires a 32-byte key. Keep the random bytes as a Buffer;
// converting them to hex produces a 64-character value and breaks RDP token encryption.
global.rpdToken = require('crypto').randomBytes(32)
require('dotenv').config()
require('./app/main.js')
import crypto from 'node:crypto'
import dotenv from 'dotenv'
global.rpdToken = crypto.randomBytes(32)
dotenv.config()
await import('./app/main.js')
+3 -1
View File
@@ -2,6 +2,7 @@
"name": "server",
"version": "3.7.1",
"description": "easynode-server",
"type": "module",
"bin": "./bin/www",
"scripts": {
"local": "cross-env EXEC_ENV=local node dev-local.js",
@@ -30,6 +31,7 @@
"cross-env": "^7.0.3",
"crypto-js": "4.2.0",
"dotenv": "^16.4.5",
"es-module-lexer": "^2.3.1",
"eslint": "^10.4.1",
"fs-extra": "^11.2.0",
"global": "^4.4.0",
@@ -37,7 +39,7 @@
"http-proxy-middleware": "^3.0.5",
"iconv-lite": "^0.6.3",
"jsonwebtoken": "9.0.2",
"koa": "2.16.2",
"koa": "2.16.4",
"koa-body": "^6.0.1",
"koa-compose": "^4.1.0",
"koa-compress": "^5.1.1",
+1 -1
View File
@@ -1,4 +1,4 @@
const axios = require('axios')
import axios from 'axios'
const BASE_URL = 'http://localhost:8082/api/v1'
+1 -1
View File
@@ -1,4 +1,4 @@
const io = require('socket.io-client')
import io from 'socket.io-client'
const SERVER_URL = 'http://localhost:8082'
const VALID_TOKEN = 'U2FsdGVkX1+26QCTo4JlGxKnQFcDjOxHyZthx/zucoUMh4CVGc3d4DdBPG2LK52gLuO5RRtmnclYoZESSyQrP7RDoJxh4PLkF6Dm7m3PiO112i1DWxp/xANsRQBzotJ1soPa1ym82BNQRNoziZHbG2RmC/wM953x1zEBgK0wD6LW0I9cQMNIaiO+TV8f/qYt9m4QEoG3UBnLWCN5+oHU0DTOMJQgXBl7zFVwj/9YENt0rN5tBLZSSZv6krM94lmTO7V/mXycUqa/fWJuz7+B0ThlxFNFwzHdizGB+iqTHLoFrDL9Nw0d4oHnBOEkzSmwjIzNysVttfESpjAjNZ6gfmpV7+qERGxt9VHTogWP2cIaT5Dqjkc1ldG63yfYzXCx'
+41 -5
View File
@@ -2706,6 +2706,11 @@ es-errors@^1.3.0:
resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f"
integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==
es-module-lexer@^2.3.1:
version "2.3.1"
resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-2.3.1.tgz#5bf2df06999dbbe5f006a5f46a11fb9f5b7b391b"
integrity sha512-shc1dbU90Yl/xq1QrC7QRtfcwURZuVRfPhZbDoldJ1cn1gzDvBaBWlv0eFolj5+0znnPJz5TXLxsN77X/12KTA==
es-object-atoms@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.0.0.tgz#ddb55cd47ac2e240701260bc2a8e31ecb643d941"
@@ -4053,10 +4058,10 @@ koa2-connect-history-api-fallback@^0.1.3:
resolved "https://registry.yarnpkg.com/koa2-connect-history-api-fallback/-/koa2-connect-history-api-fallback-0.1.3.tgz#dd07b6183ab111d48a6e14f0896d39397c2b879b"
integrity sha512-6SucVC8sn7ffaAKOhpNn1OJUqZDK37Jg/PSBAGSribQIikU/Et1aOkUcPH34dm55Kl94RrH4d1snOG6EErzE1Q==
koa@2.16.2:
version "2.16.2"
resolved "https://registry.yarnpkg.com/koa/-/koa-2.16.2.tgz#1292a3b415a9b9f3dd6872c1835229630a4ecae3"
integrity sha512-+CCssgnrWKx9aI3OeZwroa/ckG4JICxvIFnSiOUyl2Uv+UTI+xIw0FfFrWS7cQFpoePpr9o8csss7KzsTzNL8Q==
koa@2.16.4:
version "2.16.4"
resolved "https://registry.yarnpkg.com/koa/-/koa-2.16.4.tgz#303b996f5c3f2a3bb771c7db5e4303ee05f2265f"
integrity sha512-3An0GCLDSR34tsCO4H8Tef8Pp2ngtaZDAZnsWJYelqXUK5wyiHvGItgK/xcSkmHLSTn1Jcho1mRQs2ehRzvKKw==
dependencies:
accepts "^1.3.5"
cache-content-type "^1.0.0"
@@ -4547,6 +4552,11 @@ object-inspect@^1.13.3:
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.3.tgz#f14c183de51130243d6d18ae149375ff50ea488a"
integrity sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==
object-inspect@^1.13.4:
version "1.13.4"
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.4.tgz#8375265e21bc20d0fa582c22e1b13485d6e00213"
integrity sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==
object-keys@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
@@ -4858,7 +4868,14 @@ qrcode@^1.5.4:
pngjs "^5.0.0"
yargs "^15.3.1"
qs@6.13.1, qs@^6.11.0, qs@^6.14.1, qs@^6.5.2:
qs@6.13.1:
version "6.13.1"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.13.1.tgz#3ce5fc72bd3a8171b85c99b93c65dd20b7d1b16e"
integrity sha512-EJPeIn0CYrGu+hli1xilKAPXODtJ12T0sP63Ijx2/khC2JtuaN3JyNIpvmnkmaEtha9ocbG4A4cMcr+TvqvwQg==
dependencies:
side-channel "^1.0.6"
qs@^6.11.0, qs@^6.5.2:
version "6.15.2"
resolved "https://registry.npmmirror.com/qs/-/qs-6.15.2.tgz#fd55426d710403ddccc45e0f9eab16db7727ece9"
integrity sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==
@@ -5178,6 +5195,14 @@ side-channel-list@^1.0.0:
es-errors "^1.3.0"
object-inspect "^1.13.3"
side-channel-list@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/side-channel-list/-/side-channel-list-1.0.1.tgz#c2e0b5a14a540aebee3bbc6c3f8666cc9b509127"
integrity sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==
dependencies:
es-errors "^1.3.0"
object-inspect "^1.13.4"
side-channel-map@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/side-channel-map/-/side-channel-map-1.0.1.tgz#d6bb6b37902c6fef5174e5f533fab4c732a26f42"
@@ -5199,6 +5224,17 @@ side-channel-weakmap@^1.0.2:
object-inspect "^1.13.3"
side-channel-map "^1.0.1"
side-channel@^1.0.6:
version "1.1.1"
resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.1.1.tgz#ea02c62e05dc4bea67d4442f0fb71ee192f8e0ab"
integrity sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==
dependencies:
es-errors "^1.3.0"
object-inspect "^1.13.4"
side-channel-list "^1.0.1"
side-channel-map "^1.0.1"
side-channel-weakmap "^1.0.2"
side-channel@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.1.0.tgz#c3fcff9c4da932784873335ec9765fa94ff66bc9"