mirror of
https://github.com/certd/certd.git
synced 2026-05-18 06:17:31 +08:00
perf: 重构自动加载模块并优化EAB授权处理
refactor(ui): 将分散的auto-*模块整合为统一命名的auto-register模块 perf(plugin-cert): 增强EAB授权功能,支持账号私钥刷新和类型选择 test: 添加EAB授权服务和ACME账号配置的单元测试 docs: 更新AGENTS.md补充ACME/EAB使用注意事项 chore: 统一各package.json中的测试脚本配置
This commit is contained in:
@@ -142,6 +142,12 @@ Certd 是一个支持私有化部署的 SSL/TLS 证书自动化管理平台。
|
|||||||
|
|
||||||
如果只是某个服务商或部署目标的问题,不要轻易修改共享 pipeline/core 行为,除非确实是可复用的公共能力。
|
如果只是某个服务商或部署目标的问题,不要轻易修改共享 pipeline/core 行为,除非确实是可复用的公共能力。
|
||||||
|
|
||||||
|
### ACME / EAB 注意事项
|
||||||
|
|
||||||
|
- 公共 EAB(尤其是 Google EAB)可能只能创建一次 ACME 账号。要跨用户复用公共 EAB,应保存并复用同一个 ACME account private key;`accountUrl` 如果存到 `userContext` 里,只能视为当前用户缓存,因为 `userContext` 跟用户 id 走。
|
||||||
|
- ACME 协议的 `newAccount` 支持 `onlyReturnExisting`。使用同一个 account private key 调用 `newAccount({ onlyReturnExisting: true })` 可以取回已创建账号的 URL,且不会再次消费 EAB。
|
||||||
|
- 修改 EAB 的 `kid` 后,应重新生成绑定该 `kid` 的 account private key;否则应阻止继续申请并提示用户刷新账号私钥。
|
||||||
|
|
||||||
## 数据与迁移
|
## 数据与迁移
|
||||||
|
|
||||||
后端使用 TypeORM 实体加 SQL 迁移。
|
后端使用 TypeORM 实体加 SQL 迁移。
|
||||||
@@ -161,6 +167,7 @@ Certd 是一个支持私有化部署的 SSL/TLS 证书自动化管理平台。
|
|||||||
- 优先沿用现有模块、插件、服务模式,再考虑新增抽象。
|
- 优先沿用现有模块、插件、服务模式,再考虑新增抽象。
|
||||||
- `packages/ui/certd-server/data/`、`logs/`、生成的 metadata/dist 等通常视为运行时或构建产物,除非任务明确要求处理它们。
|
- `packages/ui/certd-server/data/`、`logs/`、生成的 metadata/dist 等通常视为运行时或构建产物,除非任务明确要求处理它们。
|
||||||
- 注意本地数据和配置里可能包含凭据、证书材料等敏感信息。
|
- 注意本地数据和配置里可能包含凭据、证书材料等敏感信息。
|
||||||
|
- 本仓库代码注释优先使用中文,尤其是解释业务规则、兼容逻辑、协议细节和隐藏风险时;除非文件已有明确英文注释风格或引用外部英文术语,否则不要新增英文说明性注释。
|
||||||
|
|
||||||
## 插件开发技能
|
## 插件开发技能
|
||||||
|
|
||||||
|
|||||||
@@ -35,10 +35,12 @@
|
|||||||
"@typescript-eslint/parser": "^8.26.1",
|
"@typescript-eslint/parser": "^8.26.1",
|
||||||
"chai": "^4.4.1",
|
"chai": "^4.4.1",
|
||||||
"chai-as-promised": "^7.1.2",
|
"chai-as-promised": "^7.1.2",
|
||||||
|
"cross-env": "^7.0.3",
|
||||||
"eslint": "^8.57.0",
|
"eslint": "^8.57.0",
|
||||||
"eslint-config-prettier": "^8.5.0",
|
"eslint-config-prettier": "^8.5.0",
|
||||||
"eslint-plugin-import": "^2.29.1",
|
"eslint-plugin-import": "^2.29.1",
|
||||||
"eslint-plugin-prettier": "^4.2.1",
|
"eslint-plugin-prettier": "^4.2.1",
|
||||||
|
"esmock": "^2.7.5",
|
||||||
"jsdoc-to-markdown": "^8.0.1",
|
"jsdoc-to-markdown": "^8.0.1",
|
||||||
"mocha": "^10.6.0",
|
"mocha": "^10.6.0",
|
||||||
"nock": "^13.5.4",
|
"nock": "^13.5.4",
|
||||||
@@ -55,7 +57,7 @@
|
|||||||
"prepublishOnly": "npm run build && npm run build-docs",
|
"prepublishOnly": "npm run build && npm run build-docs",
|
||||||
"test": "mocha -t 60000 \"test/setup.js\" \"test/**/*.spec.js\"",
|
"test": "mocha -t 60000 \"test/setup.js\" \"test/**/*.spec.js\"",
|
||||||
"before-test:unit": "node -e \"const fs=require('fs');fs.rmSync('dist-test',{recursive:true,force:true});fs.rmSync('tsconfig.test.tsbuildinfo',{force:true});\"",
|
"before-test:unit": "node -e \"const fs=require('fs');fs.rmSync('dist-test',{recursive:true,force:true});fs.rmSync('tsconfig.test.tsbuildinfo',{force:true});\"",
|
||||||
"test:unit": "npm run before-test:unit && tsc -p tsconfig.test.json --skipLibCheck && mocha -t 60000 \"dist-test/**/*.test.js\"",
|
"test:unit": "cross-env NODE_ENV=unittest npm run before-test:unit && cross-env NODE_ENV=unittest tsc -p tsconfig.test.json --skipLibCheck && cross-env NODE_ENV=unittest mocha -t 60000 \"dist-test/**/*.test.js\"",
|
||||||
"pub": "npm publish",
|
"pub": "npm publish",
|
||||||
"compile": "tsc --skipLibCheck --watch"
|
"compile": "tsc --skipLibCheck --watch"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
"dev-build": "npm run build",
|
"dev-build": "npm run build",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"test": "mocha --loader=ts-node/esm",
|
"test": "mocha --loader=ts-node/esm",
|
||||||
"test:unit": "mocha --node-option no-warnings --node-option loader=ts-node/esm \"src/**/*.test.ts\"",
|
"test:unit": "cross-env NODE_ENV=unittest mocha --node-option no-warnings --node-option loader=ts-node/esm \"src/**/*.test.ts\"",
|
||||||
"pub": "npm publish",
|
"pub": "npm publish",
|
||||||
"compile": "tsc --skipLibCheck --watch"
|
"compile": "tsc --skipLibCheck --watch"
|
||||||
},
|
},
|
||||||
@@ -40,9 +40,11 @@
|
|||||||
"@typescript-eslint/eslint-plugin": "^8.26.1",
|
"@typescript-eslint/eslint-plugin": "^8.26.1",
|
||||||
"@typescript-eslint/parser": "^8.26.1",
|
"@typescript-eslint/parser": "^8.26.1",
|
||||||
"chai": "4.3.10",
|
"chai": "4.3.10",
|
||||||
|
"cross-env": "^7.0.3",
|
||||||
"eslint": "^8.41.0",
|
"eslint": "^8.41.0",
|
||||||
"eslint-config-prettier": "^8.8.0",
|
"eslint-config-prettier": "^8.8.0",
|
||||||
"eslint-plugin-prettier": "^4.2.1",
|
"eslint-plugin-prettier": "^4.2.1",
|
||||||
|
"esmock": "^2.7.5",
|
||||||
"mocha": "^10.2.0",
|
"mocha": "^10.2.0",
|
||||||
"prettier": "^2.8.8",
|
"prettier": "^2.8.8",
|
||||||
"rimraf": "^5.0.5",
|
"rimraf": "^5.0.5",
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
"build3": "rollup -c",
|
"build3": "rollup -c",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"test": "mocha --loader=ts-node/esm",
|
"test": "mocha --loader=ts-node/esm",
|
||||||
"test:unit": "mocha --no-config --node-option no-warnings --node-option loader=ts-node/esm \"src/**/*.test.ts\"",
|
"test:unit": "cross-env NODE_ENV=unittest mocha --no-config --node-option no-warnings --node-option loader=ts-node/esm \"src/**/*.test.ts\"",
|
||||||
"pub": "npm publish",
|
"pub": "npm publish",
|
||||||
"compile": "tsc --skipLibCheck --watch"
|
"compile": "tsc --skipLibCheck --watch"
|
||||||
},
|
},
|
||||||
@@ -37,9 +37,11 @@
|
|||||||
"@typescript-eslint/eslint-plugin": "^8.26.1",
|
"@typescript-eslint/eslint-plugin": "^8.26.1",
|
||||||
"@typescript-eslint/parser": "^8.26.1",
|
"@typescript-eslint/parser": "^8.26.1",
|
||||||
"chai": "4.3.10",
|
"chai": "4.3.10",
|
||||||
|
"cross-env": "^7.0.3",
|
||||||
"eslint": "^8.41.0",
|
"eslint": "^8.41.0",
|
||||||
"eslint-config-prettier": "^8.8.0",
|
"eslint-config-prettier": "^8.8.0",
|
||||||
"eslint-plugin-prettier": "^4.2.1",
|
"eslint-plugin-prettier": "^4.2.1",
|
||||||
|
"esmock": "^2.7.5",
|
||||||
"mocha": "^10.2.0",
|
"mocha": "^10.2.0",
|
||||||
"prettier": "^2.8.8",
|
"prettier": "^2.8.8",
|
||||||
"rimraf": "^5.0.5",
|
"rimraf": "^5.0.5",
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
"build": "npm run before-build && rollup -c ",
|
"build": "npm run before-build && rollup -c ",
|
||||||
"dev-build": "npm run build",
|
"dev-build": "npm run build",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"test:unit": "echo no unit tests",
|
"test:unit": "cross-env NODE_ENV=unittest echo no unit tests",
|
||||||
"pub": "npm publish"
|
"pub": "npm publish"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -22,6 +22,8 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@typescript-eslint/eslint-plugin": "^8.26.1",
|
"@typescript-eslint/eslint-plugin": "^8.26.1",
|
||||||
"@typescript-eslint/parser": "^8.26.1",
|
"@typescript-eslint/parser": "^8.26.1",
|
||||||
|
"cross-env": "^7.0.3",
|
||||||
|
"esmock": "^2.7.5",
|
||||||
"prettier": "^2.8.8",
|
"prettier": "^2.8.8",
|
||||||
"tslib": "^2.8.1"
|
"tslib": "^2.8.1"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
"build3": "rollup -c",
|
"build3": "rollup -c",
|
||||||
"build2": "vue-tsc --noEmit && vite build",
|
"build2": "vue-tsc --noEmit && vite build",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"test:unit": "echo no unit tests",
|
"test:unit": "cross-env NODE_ENV=unittest echo no unit tests",
|
||||||
"pub": "npm publish"
|
"pub": "npm publish"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -24,9 +24,11 @@
|
|||||||
"@types/chai": "^4.3.3",
|
"@types/chai": "^4.3.3",
|
||||||
"@typescript-eslint/eslint-plugin": "^8.26.1",
|
"@typescript-eslint/eslint-plugin": "^8.26.1",
|
||||||
"@typescript-eslint/parser": "^8.26.1",
|
"@typescript-eslint/parser": "^8.26.1",
|
||||||
|
"cross-env": "^7.0.3",
|
||||||
"eslint": "^8.24.0",
|
"eslint": "^8.24.0",
|
||||||
"eslint-config-prettier": "^8.5.0",
|
"eslint-config-prettier": "^8.5.0",
|
||||||
"eslint-plugin-prettier": "^4.2.1",
|
"eslint-plugin-prettier": "^4.2.1",
|
||||||
|
"esmock": "^2.7.5",
|
||||||
"prettier": "^2.8.8",
|
"prettier": "^2.8.8",
|
||||||
"rimraf": "^5.0.5",
|
"rimraf": "^5.0.5",
|
||||||
"tslib": "^2.8.1",
|
"tslib": "^2.8.1",
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "rollup -c ",
|
"build": "rollup -c ",
|
||||||
"dev-build": "npm run build",
|
"dev-build": "npm run build",
|
||||||
"test:unit": "echo no unit tests",
|
"test:unit": "cross-env NODE_ENV=unittest echo no unit tests",
|
||||||
"pub": "npm publish"
|
"pub": "npm publish"
|
||||||
},
|
},
|
||||||
"author": "",
|
"author": "",
|
||||||
@@ -30,7 +30,8 @@
|
|||||||
"@typescript-eslint/parser": "^8.26.1",
|
"@typescript-eslint/parser": "^8.26.1",
|
||||||
"chai": "^4.1.2",
|
"chai": "^4.1.2",
|
||||||
"config": "^1.30.0",
|
"config": "^1.30.0",
|
||||||
"cross-env": "^5.1.4",
|
"cross-env": "^7.0.3",
|
||||||
|
"esmock": "^2.7.5",
|
||||||
"js-yaml": "^3.11.0",
|
"js-yaml": "^3.11.0",
|
||||||
"mocha": "^5.0.0",
|
"mocha": "^5.0.0",
|
||||||
"prettier": "^2.8.8",
|
"prettier": "^2.8.8",
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
"build3": "rollup -c",
|
"build3": "rollup -c",
|
||||||
"build2": "vue-tsc --noEmit && vite build",
|
"build2": "vue-tsc --noEmit && vite build",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"test:unit": "echo no unit tests",
|
"test:unit": "cross-env NODE_ENV=unittest echo no unit tests",
|
||||||
"pub": "npm publish",
|
"pub": "npm publish",
|
||||||
"compile": "tsc --skipLibCheck --watch"
|
"compile": "tsc --skipLibCheck --watch"
|
||||||
},
|
},
|
||||||
@@ -26,9 +26,11 @@
|
|||||||
"@types/chai": "^4.3.3",
|
"@types/chai": "^4.3.3",
|
||||||
"@typescript-eslint/eslint-plugin": "^8.26.1",
|
"@typescript-eslint/eslint-plugin": "^8.26.1",
|
||||||
"@typescript-eslint/parser": "^8.26.1",
|
"@typescript-eslint/parser": "^8.26.1",
|
||||||
|
"cross-env": "^7.0.3",
|
||||||
"eslint": "^8.24.0",
|
"eslint": "^8.24.0",
|
||||||
"eslint-config-prettier": "^8.5.0",
|
"eslint-config-prettier": "^8.5.0",
|
||||||
"eslint-plugin-prettier": "^4.2.1",
|
"eslint-plugin-prettier": "^4.2.1",
|
||||||
|
"esmock": "^2.7.5",
|
||||||
"prettier": "^2.8.8",
|
"prettier": "^2.8.8",
|
||||||
"rimraf": "^5.0.5",
|
"rimraf": "^5.0.5",
|
||||||
"tslib": "^2.8.1",
|
"tslib": "^2.8.1",
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
"build": "npm run before-build && tsc --skipLibCheck",
|
"build": "npm run before-build && tsc --skipLibCheck",
|
||||||
"dev-build": "npm run build",
|
"dev-build": "npm run build",
|
||||||
"test": "midway-bin test --ts -V",
|
"test": "midway-bin test --ts -V",
|
||||||
"test:unit": "mocha --no-config --node-option no-warnings --node-option loader=ts-node/esm \"src/**/*.test.ts\"",
|
"test:unit": "cross-env NODE_ENV=unittest mocha --no-config --node-option no-warnings --node-option loader=ts-node/esm \"src/**/*.test.ts\"",
|
||||||
"test1": "midway-bin test --ts -V -f test/blank.test.ts -t 'hash-check'",
|
"test1": "midway-bin test --ts -V -f test/blank.test.ts -t 'hash-check'",
|
||||||
"cov": "midway-bin cov --ts",
|
"cov": "midway-bin cov --ts",
|
||||||
"lint": "mwts check",
|
"lint": "mwts check",
|
||||||
@@ -44,7 +44,6 @@
|
|||||||
"@midwayjs/upload": "3.20.13",
|
"@midwayjs/upload": "3.20.13",
|
||||||
"@midwayjs/validate": "3.20.13",
|
"@midwayjs/validate": "3.20.13",
|
||||||
"better-sqlite3": "^11.1.2",
|
"better-sqlite3": "^11.1.2",
|
||||||
"cross-env": "^7.0.3",
|
|
||||||
"dayjs": "^1.11.7",
|
"dayjs": "^1.11.7",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"mwts": "^1.3.0",
|
"mwts": "^1.3.0",
|
||||||
@@ -57,9 +56,11 @@
|
|||||||
"@types/node": "^18",
|
"@types/node": "^18",
|
||||||
"@typescript-eslint/eslint-plugin": "^8.26.1",
|
"@typescript-eslint/eslint-plugin": "^8.26.1",
|
||||||
"@typescript-eslint/parser": "^8.26.1",
|
"@typescript-eslint/parser": "^8.26.1",
|
||||||
|
"cross-env": "^7.0.3",
|
||||||
"eslint": "^8.24.0",
|
"eslint": "^8.24.0",
|
||||||
"eslint-config-prettier": "^8.5.0",
|
"eslint-config-prettier": "^8.5.0",
|
||||||
"eslint-plugin-prettier": "^4.2.1",
|
"eslint-plugin-prettier": "^4.2.1",
|
||||||
|
"esmock": "^2.7.5",
|
||||||
"mocha": "^10.2.0",
|
"mocha": "^10.2.0",
|
||||||
"prettier": "^2.8.8",
|
"prettier": "^2.8.8",
|
||||||
"rimraf": "^5.0.5",
|
"rimraf": "^5.0.5",
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import assert from "assert";
|
||||||
|
import { AccessService } from "./access-service.js";
|
||||||
|
|
||||||
|
describe("AccessService", () => {
|
||||||
|
it("does not write id into access setting when updating selected fields", async () => {
|
||||||
|
let updateParam: any;
|
||||||
|
const service = new AccessService();
|
||||||
|
service.info = async () => ({
|
||||||
|
id: 12,
|
||||||
|
type: "eab",
|
||||||
|
} as any);
|
||||||
|
service.decryptAccessEntity = () => ({
|
||||||
|
kid: "kid-1",
|
||||||
|
});
|
||||||
|
service.update = async (param: any) => {
|
||||||
|
updateParam = param;
|
||||||
|
return param;
|
||||||
|
};
|
||||||
|
|
||||||
|
await service.updateAccess({
|
||||||
|
id: 12,
|
||||||
|
accountKey: "account-key",
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.deepEqual(JSON.parse(updateParam.setting), {
|
||||||
|
kid: "kid-1",
|
||||||
|
accountKey: "account-key",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -123,6 +123,25 @@ export class AccessService extends BaseService<AccessEntity> {
|
|||||||
return await super.update(param);
|
return await super.update(param);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async updateAccess(access: any) {
|
||||||
|
const oldEntity = await this.info(access.id);
|
||||||
|
if (oldEntity == null) {
|
||||||
|
throw new ValidateException('该授权配置不存在,请确认是否已被删除');
|
||||||
|
}
|
||||||
|
const setting = this.decryptAccessEntity(oldEntity);
|
||||||
|
for (const key of Object.keys(access)) {
|
||||||
|
if (key === 'id') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
setting[key] = access[key];
|
||||||
|
}
|
||||||
|
return await this.update({
|
||||||
|
id: access.id,
|
||||||
|
type: oldEntity.type,
|
||||||
|
setting: JSON.stringify(setting),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async getSimpleInfo(id: number) {
|
async getSimpleInfo(id: number) {
|
||||||
const entity = await this.info(id);
|
const entity = await this.info(id);
|
||||||
if (entity == null) {
|
if (entity == null) {
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
"dev-build": "npm run build",
|
"dev-build": "npm run build",
|
||||||
"test": "midway-bin test --ts -V",
|
"test": "midway-bin test --ts -V",
|
||||||
"test1": "midway-bin test --ts -V -f test/blank.test.ts -t 'hash-check'",
|
"test1": "midway-bin test --ts -V -f test/blank.test.ts -t 'hash-check'",
|
||||||
"test:unit": "echo no unit tests",
|
"test:unit": "cross-env NODE_ENV=unittest echo no unit tests",
|
||||||
"cov": "midway-bin cov --ts",
|
"cov": "midway-bin cov --ts",
|
||||||
"prepublish": "npm run build",
|
"prepublish": "npm run build",
|
||||||
"pub": "npm publish"
|
"pub": "npm publish"
|
||||||
@@ -36,11 +36,13 @@
|
|||||||
"@types/node": "^18",
|
"@types/node": "^18",
|
||||||
"@typescript-eslint/eslint-plugin": "^8.26.1",
|
"@typescript-eslint/eslint-plugin": "^8.26.1",
|
||||||
"@typescript-eslint/parser": "^8.26.1",
|
"@typescript-eslint/parser": "^8.26.1",
|
||||||
|
"cross-env": "^7.0.3",
|
||||||
"eslint": "^8.24.0",
|
"eslint": "^8.24.0",
|
||||||
"eslint-config-prettier": "^8.5.0",
|
"eslint-config-prettier": "^8.5.0",
|
||||||
"eslint-plugin-import": "^2.26.0",
|
"eslint-plugin-import": "^2.26.0",
|
||||||
"eslint-plugin-node": "^11.1.0",
|
"eslint-plugin-node": "^11.1.0",
|
||||||
"eslint-plugin-prettier": "^4.2.1",
|
"eslint-plugin-prettier": "^4.2.1",
|
||||||
|
"esmock": "^2.7.5",
|
||||||
"prettier": "^2.8.8",
|
"prettier": "^2.8.8",
|
||||||
"rimraf": "^5.0.5",
|
"rimraf": "^5.0.5",
|
||||||
"tslib": "^2.8.1",
|
"tslib": "^2.8.1",
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
"build3": "rollup -c",
|
"build3": "rollup -c",
|
||||||
"build2": "vue-tsc --noEmit && vite build",
|
"build2": "vue-tsc --noEmit && vite build",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"test:unit": "echo no unit tests",
|
"test:unit": "cross-env NODE_ENV=unittest echo no unit tests",
|
||||||
"pub": "npm publish",
|
"pub": "npm publish",
|
||||||
"compile": "tsc --skipLibCheck --watch"
|
"compile": "tsc --skipLibCheck --watch"
|
||||||
},
|
},
|
||||||
@@ -31,9 +31,11 @@
|
|||||||
"@typescript-eslint/eslint-plugin": "^8.26.1",
|
"@typescript-eslint/eslint-plugin": "^8.26.1",
|
||||||
"@typescript-eslint/parser": "^8.26.1",
|
"@typescript-eslint/parser": "^8.26.1",
|
||||||
"chai": "^4.3.6",
|
"chai": "^4.3.6",
|
||||||
|
"cross-env": "^7.0.3",
|
||||||
"eslint": "^8.24.0",
|
"eslint": "^8.24.0",
|
||||||
"eslint-config-prettier": "^8.5.0",
|
"eslint-config-prettier": "^8.5.0",
|
||||||
"eslint-plugin-prettier": "^4.2.1",
|
"eslint-plugin-prettier": "^4.2.1",
|
||||||
|
"esmock": "^2.7.5",
|
||||||
"mocha": "^10.1.0",
|
"mocha": "^10.1.0",
|
||||||
"prettier": "^2.8.8",
|
"prettier": "^2.8.8",
|
||||||
"tslib": "^2.8.1",
|
"tslib": "^2.8.1",
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
"build3": "rollup -c",
|
"build3": "rollup -c",
|
||||||
"build2": "vue-tsc --noEmit && vite build",
|
"build2": "vue-tsc --noEmit && vite build",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"test:unit": "mocha --no-config --node-option no-warnings --node-option loader=ts-node/esm \"src/**/*.test.ts\"",
|
"test:unit": "cross-env NODE_ENV=unittest mocha --no-config --node-option no-warnings --node-option loader=ts-node/esm \"src/**/*.test.ts\"",
|
||||||
"pub": "npm publish",
|
"pub": "npm publish",
|
||||||
"compile": "tsc --skipLibCheck --watch"
|
"compile": "tsc --skipLibCheck --watch"
|
||||||
},
|
},
|
||||||
@@ -50,9 +50,11 @@
|
|||||||
"@typescript-eslint/eslint-plugin": "^8.26.1",
|
"@typescript-eslint/eslint-plugin": "^8.26.1",
|
||||||
"@typescript-eslint/parser": "^8.26.1",
|
"@typescript-eslint/parser": "^8.26.1",
|
||||||
"chai": "^4.3.6",
|
"chai": "^4.3.6",
|
||||||
|
"cross-env": "^7.0.3",
|
||||||
"eslint": "^8.24.0",
|
"eslint": "^8.24.0",
|
||||||
"eslint-config-prettier": "^8.5.0",
|
"eslint-config-prettier": "^8.5.0",
|
||||||
"eslint-plugin-prettier": "^4.2.1",
|
"eslint-plugin-prettier": "^4.2.1",
|
||||||
|
"esmock": "^2.7.5",
|
||||||
"mocha": "^10.1.0",
|
"mocha": "^10.1.0",
|
||||||
"prettier": "^2.8.8",
|
"prettier": "^2.8.8",
|
||||||
"ts-node": "^10.9.2",
|
"ts-node": "^10.9.2",
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
"debug:force": "vite --force --mode debug",
|
"debug:force": "vite --force --mode debug",
|
||||||
"build": "cross-env NODE_OPTIONS=--max-old-space-size=40960 vite build ",
|
"build": "cross-env NODE_OPTIONS=--max-old-space-size=40960 vite build ",
|
||||||
"dev-build": "echo 1",
|
"dev-build": "echo 1",
|
||||||
"test:unit": "echo no unit tests",
|
"test:unit": "cross-env NODE_ENV=unittest echo no unit tests",
|
||||||
"test:vue": "vitest run",
|
"test:vue": "vitest run",
|
||||||
"serve": "vite preview",
|
"serve": "vite preview",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
@@ -62,7 +62,6 @@
|
|||||||
"cos-js-sdk-v5": "^1.7.0",
|
"cos-js-sdk-v5": "^1.7.0",
|
||||||
"cron-parser": "^4.9.0",
|
"cron-parser": "^4.9.0",
|
||||||
"cropperjs": "^1.6.1",
|
"cropperjs": "^1.6.1",
|
||||||
"cross-env": "^7.0.3",
|
|
||||||
"cssnano": "^7.0.6",
|
"cssnano": "^7.0.6",
|
||||||
"dayjs": "^1.11.7",
|
"dayjs": "^1.11.7",
|
||||||
"defu": "^6.1.4",
|
"defu": "^6.1.4",
|
||||||
@@ -127,6 +126,7 @@
|
|||||||
"autoprefixer": "^10.4.21",
|
"autoprefixer": "^10.4.21",
|
||||||
"caller-path": "^4.0.0",
|
"caller-path": "^4.0.0",
|
||||||
"chai": "^5.1.0",
|
"chai": "^5.1.0",
|
||||||
|
"cross-env": "^7.0.3",
|
||||||
"dependency-cruiser": "^16.2.3",
|
"dependency-cruiser": "^16.2.3",
|
||||||
"dot": "^1.1.3",
|
"dot": "^1.1.3",
|
||||||
"eslint": "8.57.0",
|
"eslint": "8.57.0",
|
||||||
@@ -136,6 +136,7 @@
|
|||||||
"eslint-plugin-prettier": "^5.1.3",
|
"eslint-plugin-prettier": "^5.1.3",
|
||||||
"eslint-plugin-promise": "^6.1.1",
|
"eslint-plugin-promise": "^6.1.1",
|
||||||
"eslint-plugin-vue": "^9.23.0",
|
"eslint-plugin-vue": "^9.23.0",
|
||||||
|
"esmock": "^2.7.5",
|
||||||
"less": "^4.2.0",
|
"less": "^4.2.0",
|
||||||
"less-loader": "^12.2.0",
|
"less-loader": "^12.2.0",
|
||||||
"postcss": "^8.4.35",
|
"postcss": "^8.4.35",
|
||||||
|
|||||||
@@ -0,0 +1,106 @@
|
|||||||
|
<template>
|
||||||
|
<div class="refresh-input">
|
||||||
|
<div class="refresh-input-line">
|
||||||
|
<a-input class="refresh-input-control" :value="value" :placeholder="placeholder" allow-clear @update:value="emit('update:value', $event)"></a-input>
|
||||||
|
<fs-button :loading="loading" type="primary" :text="buttonText" :icon="icon" @click="doRefresh"></fs-button>
|
||||||
|
</div>
|
||||||
|
<div class="helper" :class="{ error: hasError }">
|
||||||
|
{{ message }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ComponentPropsType, doRequest } from "/@/components/plugins/lib";
|
||||||
|
import { computed, inject, ref } from "vue";
|
||||||
|
import { Form } from "ant-design-vue";
|
||||||
|
import { getInputFromForm } from "./utils";
|
||||||
|
|
||||||
|
defineOptions({
|
||||||
|
name: "RefreshInput",
|
||||||
|
});
|
||||||
|
|
||||||
|
type RefreshInputProps = ComponentPropsType & {
|
||||||
|
buttonText?: string;
|
||||||
|
icon?: string;
|
||||||
|
placeholder?: string;
|
||||||
|
successMessage?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const fromType: any = inject("getFromType");
|
||||||
|
const getScope: any = inject("get:scope");
|
||||||
|
const getPluginType: any = inject("get:plugin:type", () => {
|
||||||
|
return "access";
|
||||||
|
});
|
||||||
|
const formItemContext = Form.useInjectFormItemContext();
|
||||||
|
const props = defineProps<RefreshInputProps>();
|
||||||
|
const emit = defineEmits<{
|
||||||
|
"update:value": [value: string];
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const loading = ref(false);
|
||||||
|
const message = ref("");
|
||||||
|
const hasError = ref(false);
|
||||||
|
|
||||||
|
const action = computed(() => props.action);
|
||||||
|
const buttonText = computed(() => props.buttonText || "刷新");
|
||||||
|
const icon = computed(() => props.icon || "ion:refresh-outline");
|
||||||
|
const placeholder = computed(() => props.placeholder || "");
|
||||||
|
const successMessage = computed(() => props.successMessage || "刷新成功,请保存配置");
|
||||||
|
|
||||||
|
const doRefresh = async () => {
|
||||||
|
if (loading.value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!action.value) {
|
||||||
|
hasError.value = true;
|
||||||
|
message.value = "缺少刷新动作配置";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
formItemContext.onFieldChange();
|
||||||
|
|
||||||
|
const { form } = getScope();
|
||||||
|
const pluginType = getPluginType();
|
||||||
|
const { input, record } = getInputFromForm(form, pluginType);
|
||||||
|
|
||||||
|
loading.value = true;
|
||||||
|
message.value = "";
|
||||||
|
hasError.value = false;
|
||||||
|
try {
|
||||||
|
const res = await doRequest(
|
||||||
|
{
|
||||||
|
type: pluginType,
|
||||||
|
typeName: form.type,
|
||||||
|
action: action.value,
|
||||||
|
input,
|
||||||
|
record,
|
||||||
|
fromType,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
onError(err: any) {
|
||||||
|
hasError.value = true;
|
||||||
|
message.value = err.message;
|
||||||
|
},
|
||||||
|
showErrorNotify: false,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
emit("update:value", res);
|
||||||
|
message.value = successMessage.value;
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.refresh-input-line {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.refresh-input-control {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -12,6 +12,7 @@ import AccessSelector from "/@/views/certd/access/access-selector/index.vue";
|
|||||||
import InputPassword from "./common/input-password.vue";
|
import InputPassword from "./common/input-password.vue";
|
||||||
import CertInfoUpdater from "/@/views/certd/pipeline/cert-upload/index.vue";
|
import CertInfoUpdater from "/@/views/certd/pipeline/cert-upload/index.vue";
|
||||||
import ApiTest from "./common/api-test.vue";
|
import ApiTest from "./common/api-test.vue";
|
||||||
|
import RefreshInput from "./common/refresh-input.vue";
|
||||||
import ParamsShow from "./common/params-show.vue";
|
import ParamsShow from "./common/params-show.vue";
|
||||||
export * from "./cert/index.js";
|
export * from "./cert/index.js";
|
||||||
export default {
|
export default {
|
||||||
@@ -23,6 +24,7 @@ export default {
|
|||||||
app.component("CertInfoUpdater", CertInfoUpdater);
|
app.component("CertInfoUpdater", CertInfoUpdater);
|
||||||
|
|
||||||
app.component("ApiTest", ApiTest);
|
app.component("ApiTest", ApiTest);
|
||||||
|
app.component("RefreshInput", RefreshInput);
|
||||||
|
|
||||||
app.component("SynologyDeviceIdGetter", SynologyIdDeviceGetter);
|
app.component("SynologyDeviceIdGetter", SynologyIdDeviceGetter);
|
||||||
app.component("RemoteAutoComplete", RemoteAutoComplete);
|
app.component("RemoteAutoComplete", RemoteAutoComplete);
|
||||||
|
|||||||
@@ -101,7 +101,6 @@
|
|||||||
"cache-manager": "^6.1.0",
|
"cache-manager": "^6.1.0",
|
||||||
"cos-nodejs-sdk-v5": "^2.14.6",
|
"cos-nodejs-sdk-v5": "^2.14.6",
|
||||||
"cron-parser": "^4.9.0",
|
"cron-parser": "^4.9.0",
|
||||||
"cross-env": "^7.0.3",
|
|
||||||
"crypto-js": "^4.2.0",
|
"crypto-js": "^4.2.0",
|
||||||
"dayjs": "^1.11.7",
|
"dayjs": "^1.11.7",
|
||||||
"esdk-obs-nodejs": "^3.25.6",
|
"esdk-obs-nodejs": "^3.25.6",
|
||||||
@@ -159,6 +158,8 @@
|
|||||||
"@types/node": "^18",
|
"@types/node": "^18",
|
||||||
"@types/nodemailer": "^6.4.8",
|
"@types/nodemailer": "^6.4.8",
|
||||||
"c8": "^10.1.2",
|
"c8": "^10.1.2",
|
||||||
|
"cross-env": "^7.0.3",
|
||||||
|
"esmock": "^2.7.5",
|
||||||
"mocha": "^10.2.0",
|
"mocha": "^10.2.0",
|
||||||
"prettier": "^2.8.8",
|
"prettier": "^2.8.8",
|
||||||
"rimraf": "^5.0.5",
|
"rimraf": "^5.0.5",
|
||||||
|
|||||||
+3
-4
@@ -1,7 +1,7 @@
|
|||||||
import { logger } from '@certd/basic';
|
import { logger } from '@certd/basic';
|
||||||
import { SysSettingsService, SysSiteInfo } from '@certd/lib-server';
|
import { SysSettingsService, SysSiteInfo } from '@certd/lib-server';
|
||||||
import { getPlusInfo, isPlus } from "@certd/plus-core";
|
import { getPlusInfo, isPlus } from "@certd/plus-core";
|
||||||
import { Autoload, Config, Init, Inject, Scope, ScopeEnum } from '@midwayjs/core';
|
import { Config, Inject, Provide, Scope, ScopeEnum } from '@midwayjs/core';
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import { Between } from "typeorm";
|
import { Between } from "typeorm";
|
||||||
import { DomainService } from '../cert/service/domain-service.js';
|
import { DomainService } from '../cert/service/domain-service.js';
|
||||||
@@ -14,9 +14,9 @@ import { PipelineService } from '../pipeline/service/pipeline-service.js';
|
|||||||
import { UserService } from "../sys/authority/service/user-service.js";
|
import { UserService } from "../sys/authority/service/user-service.js";
|
||||||
import { ProjectService } from '../sys/enterprise/service/project-service.js';
|
import { ProjectService } from '../sys/enterprise/service/project-service.js';
|
||||||
|
|
||||||
@Autoload()
|
@Provide()
|
||||||
@Scope(ScopeEnum.Request, { allowDowngrade: true })
|
@Scope(ScopeEnum.Request, { allowDowngrade: true })
|
||||||
export class AutoCRegisterCron {
|
export class AutoCron {
|
||||||
@Inject()
|
@Inject()
|
||||||
pipelineService: PipelineService;
|
pipelineService: PipelineService;
|
||||||
|
|
||||||
@@ -53,7 +53,6 @@ export class AutoCRegisterCron {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Init()
|
|
||||||
async init() {
|
async init() {
|
||||||
logger.info('加载定时trigger开始');
|
logger.info('加载定时trigger开始');
|
||||||
await this.pipelineService.onStartup(this.immediateTriggerOnce, this.onlyAdminUser);
|
await this.pipelineService.onStartup(this.immediateTriggerOnce, this.onlyAdminUser);
|
||||||
@@ -0,0 +1,182 @@
|
|||||||
|
import assert from "assert";
|
||||||
|
import esmock from "esmock";
|
||||||
|
import { AutoFix, buildEabAccountKeyValue, buildLegacyGoogleAccountConfigWhere, parseStorageValue } from "./auto-fix.js";
|
||||||
|
|
||||||
|
function createAutoFix(options: { pluginConfigService?: any; accessService?: any; storageService?: any }) {
|
||||||
|
const autoFix = new AutoFix();
|
||||||
|
autoFix.pluginConfigService = options.pluginConfigService;
|
||||||
|
autoFix.accessService = options.accessService;
|
||||||
|
autoFix.storageService = options.storageService;
|
||||||
|
return autoFix;
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("AutoFix", () => {
|
||||||
|
it("parses legacy storage values", () => {
|
||||||
|
const config = parseStorageValue(
|
||||||
|
JSON.stringify({
|
||||||
|
value: {
|
||||||
|
key: "legacy-private-key",
|
||||||
|
accountUrl: "https://example.com/acct/1",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.equal(config.key, "legacy-private-key");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("builds the EAB account key payload", () => {
|
||||||
|
const payload = JSON.parse(buildEabAccountKeyValue("kid-1", "private-key"));
|
||||||
|
|
||||||
|
assert.deepEqual(payload, {
|
||||||
|
kid: "kid-1",
|
||||||
|
privateKey: "private-key",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("builds legacy Google account config query by exact email key only", () => {
|
||||||
|
assert.deepEqual(buildLegacyGoogleAccountConfigWhere("user@example.com"), {
|
||||||
|
userId: 1,
|
||||||
|
scope: "user",
|
||||||
|
namespace: "1",
|
||||||
|
key: "acme.config.google.user@example.com",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("finds legacy Google account config by exact email key only", async () => {
|
||||||
|
let findOneWhere: any;
|
||||||
|
let findCalled = false;
|
||||||
|
const autoFix = createAutoFix({
|
||||||
|
pluginConfigService: null as any,
|
||||||
|
accessService: null as any,
|
||||||
|
storageService: {
|
||||||
|
getRepository() {
|
||||||
|
return {
|
||||||
|
async findOne(options: any) {
|
||||||
|
findOneWhere = options.where;
|
||||||
|
return {
|
||||||
|
value: JSON.stringify({
|
||||||
|
value: {
|
||||||
|
privateKey: "legacy-private-key",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
async find() {
|
||||||
|
findCalled = true;
|
||||||
|
return [];
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
} as any,
|
||||||
|
});
|
||||||
|
|
||||||
|
const config = await autoFix.getLegacyGoogleAccountConfig("user@example.com");
|
||||||
|
|
||||||
|
assert.equal(config.privateKey, "legacy-private-key");
|
||||||
|
assert.deepEqual(findOneWhere, buildLegacyGoogleAccountConfigWhere("user@example.com"));
|
||||||
|
assert.equal(findCalled, false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not query legacy Google account config without email", async () => {
|
||||||
|
let repositoryCalled = false;
|
||||||
|
const autoFix = createAutoFix({
|
||||||
|
pluginConfigService: null as any,
|
||||||
|
accessService: null as any,
|
||||||
|
storageService: {
|
||||||
|
getRepository() {
|
||||||
|
repositoryCalled = true;
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
} as any,
|
||||||
|
});
|
||||||
|
|
||||||
|
const config = await autoFix.getLegacyGoogleAccountConfig();
|
||||||
|
|
||||||
|
assert.equal(config, null);
|
||||||
|
assert.equal(repositoryCalled, false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("skips Google common EAB account key fix outside commercial edition", async () => {
|
||||||
|
let pluginConfigCalled = false;
|
||||||
|
const autoFix = createAutoFix({
|
||||||
|
pluginConfigService: {
|
||||||
|
async getPluginConfig() {
|
||||||
|
pluginConfigCalled = true;
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
} as any,
|
||||||
|
accessService: null as any,
|
||||||
|
storageService: null as any,
|
||||||
|
});
|
||||||
|
|
||||||
|
await autoFix.init();
|
||||||
|
|
||||||
|
assert.equal(pluginConfigCalled, false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("fixes Google common EAB account key in commercial edition", async () => {
|
||||||
|
const { AutoFix: MockedAutoFix } = await esmock("./auto-fix.js", {
|
||||||
|
"@certd/plus-core": {
|
||||||
|
isComm: () => true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
let getAccessByIdArgs: any[] = [];
|
||||||
|
let findOneWhere: any;
|
||||||
|
let updateAccessParam: any;
|
||||||
|
const autoFix = new MockedAutoFix();
|
||||||
|
autoFix.pluginConfigService = {
|
||||||
|
async getPluginConfig(options: any) {
|
||||||
|
assert.deepEqual(options, {
|
||||||
|
name: "CertApply",
|
||||||
|
type: "builtIn",
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
sysSetting: {
|
||||||
|
input: {
|
||||||
|
googleCommonEabAccessId: 12,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
autoFix.accessService = {
|
||||||
|
async getAccessById(...args: any[]) {
|
||||||
|
getAccessByIdArgs = args;
|
||||||
|
return {
|
||||||
|
kid: "kid-1",
|
||||||
|
email: "user@example.com",
|
||||||
|
};
|
||||||
|
},
|
||||||
|
async updateAccess(param: any) {
|
||||||
|
updateAccessParam = param;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
autoFix.storageService = {
|
||||||
|
getRepository() {
|
||||||
|
return {
|
||||||
|
async findOne(options: any) {
|
||||||
|
findOneWhere = options.where;
|
||||||
|
return {
|
||||||
|
value: JSON.stringify({
|
||||||
|
value: {
|
||||||
|
privateKey: "legacy-private-key",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
await autoFix.fixGoogleCommonEabAccountKey();
|
||||||
|
|
||||||
|
assert.deepEqual(getAccessByIdArgs, [12, false]);
|
||||||
|
assert.deepEqual(findOneWhere, buildLegacyGoogleAccountConfigWhere("user@example.com"));
|
||||||
|
assert.deepEqual(updateAccessParam, {
|
||||||
|
id: 12,
|
||||||
|
eabType: "google",
|
||||||
|
accountKey: buildEabAccountKeyValue("kid-1", "legacy-private-key"),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
import { Inject, Provide, Scope, ScopeEnum } from "@midwayjs/core";
|
||||||
|
import { logger } from "@certd/basic";
|
||||||
|
import { AccessService } from "@certd/lib-server";
|
||||||
|
import { isComm } from "@certd/plus-core";
|
||||||
|
import { PluginConfigService } from "../plugin/service/plugin-config-service.js";
|
||||||
|
import { StorageService } from "../pipeline/service/storage-service.js";
|
||||||
|
|
||||||
|
export function parseStorageValue(value?: string) {
|
||||||
|
if (!value) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(value);
|
||||||
|
return parsed?.value || null;
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildEabAccountKeyValue(kid: string, privateKey: string) {
|
||||||
|
return JSON.stringify({
|
||||||
|
kid,
|
||||||
|
privateKey,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildLegacyGoogleAccountConfigWhere(email: string) {
|
||||||
|
return {
|
||||||
|
userId: 1,
|
||||||
|
scope: "user",
|
||||||
|
namespace: "1",
|
||||||
|
key: `acme.config.google.${email}`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provide()
|
||||||
|
@Scope(ScopeEnum.Request, { allowDowngrade: true })
|
||||||
|
export class AutoFix {
|
||||||
|
@Inject()
|
||||||
|
pluginConfigService: PluginConfigService;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
accessService: AccessService;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
storageService: StorageService;
|
||||||
|
|
||||||
|
async init() {
|
||||||
|
await this.fixGoogleCommonEabAccountKey();
|
||||||
|
}
|
||||||
|
async fixGoogleCommonEabAccountKey() {
|
||||||
|
if (!isComm()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const certApplyConfig = await this.pluginConfigService.getPluginConfig({
|
||||||
|
name: "CertApply",
|
||||||
|
type: "builtIn",
|
||||||
|
});
|
||||||
|
const googleCommonEabAccessId = certApplyConfig?.sysSetting?.input?.googleCommonEabAccessId;
|
||||||
|
if (!googleCommonEabAccessId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const eabAccess = await this.accessService.getAccessById(googleCommonEabAccessId, false);
|
||||||
|
if (eabAccess.accountKey) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!eabAccess.kid) {
|
||||||
|
logger.info("公共Google EAB授权缺少KID,跳过历史ACME账号私钥修复");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const accountConfig = await this.getLegacyGoogleAccountConfig(eabAccess.email);
|
||||||
|
const privateKey = accountConfig?.privateKey || accountConfig?.key || accountConfig?.accountKey;
|
||||||
|
if (!privateKey) {
|
||||||
|
logger.info("未找到可迁移到公共Google EAB授权的历史ACME账号私钥");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const accountKey = buildEabAccountKeyValue(eabAccess.kid, privateKey);
|
||||||
|
await this.accessService.updateAccess({ id: googleCommonEabAccessId, eabType: "google", accountKey });
|
||||||
|
logger.info(`已修复公共Google EAB授权的ACME账号私钥,accessId=${googleCommonEabAccessId}`);
|
||||||
|
} catch (e: any) {
|
||||||
|
logger.error("修复公共Google EAB授权ACME账号私钥失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async getLegacyGoogleAccountConfig(email?: string) {
|
||||||
|
if (!email) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const repository = this.storageService.getRepository();
|
||||||
|
const exact = await repository.findOne({
|
||||||
|
where: buildLegacyGoogleAccountConfigWhere(email),
|
||||||
|
});
|
||||||
|
const exactValue = this.parseStorageValue(exact?.value);
|
||||||
|
if (exactValue?.key || exactValue?.privateKey || exactValue?.accountKey) {
|
||||||
|
return exactValue;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
parseStorageValue(value?: string) {
|
||||||
|
return parseStorageValue(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
+3
-4
@@ -1,14 +1,14 @@
|
|||||||
import { logger } from '@certd/basic';
|
import { logger } from '@certd/basic';
|
||||||
import { PlusService, SysInstallInfo, SysPrivateSettings, SysSettingsService } from '@certd/lib-server';
|
import { PlusService, SysInstallInfo, SysPrivateSettings, SysSettingsService } from '@certd/lib-server';
|
||||||
import { Autoload, Config, Init, Inject, Scope, ScopeEnum } from '@midwayjs/core';
|
import { Config, Inject, Provide, Scope, ScopeEnum } from '@midwayjs/core';
|
||||||
import crypto from 'crypto';
|
import crypto from 'crypto';
|
||||||
import { nanoid } from 'nanoid';
|
import { nanoid } from 'nanoid';
|
||||||
import { UserService } from '../sys/authority/service/user-service.js';
|
import { UserService } from '../sys/authority/service/user-service.js';
|
||||||
import { SafeService } from "../sys/settings/safe-service.js";
|
import { SafeService } from "../sys/settings/safe-service.js";
|
||||||
|
|
||||||
@Autoload()
|
@Provide()
|
||||||
@Scope(ScopeEnum.Request, { allowDowngrade: true })
|
@Scope(ScopeEnum.Request, { allowDowngrade: true })
|
||||||
export class AutoAInitSite {
|
export class AutoInitSite {
|
||||||
@Inject()
|
@Inject()
|
||||||
userService: UserService;
|
userService: UserService;
|
||||||
|
|
||||||
@@ -22,7 +22,6 @@ export class AutoAInitSite {
|
|||||||
@Inject()
|
@Inject()
|
||||||
safeService: SafeService;
|
safeService: SafeService;
|
||||||
|
|
||||||
@Init()
|
|
||||||
async init() {
|
async init() {
|
||||||
logger.info('初始化站点开始');
|
logger.info('初始化站点开始');
|
||||||
await this.startOptimizeDb();
|
await this.startOptimizeDb();
|
||||||
+3
-4
@@ -1,16 +1,15 @@
|
|||||||
import { Autoload, Init, Inject, Scope, ScopeEnum } from "@midwayjs/core";
|
import { Inject, Provide, Scope, ScopeEnum } from "@midwayjs/core";
|
||||||
import { logger } from "@certd/basic";
|
import { logger } from "@certd/basic";
|
||||||
import { PluginService } from "../plugin/service/plugin-service.js";
|
import { PluginService } from "../plugin/service/plugin-service.js";
|
||||||
import { registerPaymentProviders } from "../suite/payments/index.js";
|
import { registerPaymentProviders } from "../suite/payments/index.js";
|
||||||
|
|
||||||
@Autoload()
|
@Provide()
|
||||||
@Scope(ScopeEnum.Request, { allowDowngrade: true })
|
@Scope(ScopeEnum.Request, { allowDowngrade: true })
|
||||||
export class AutoBLoadPlugins {
|
export class AutoLoadPlugins {
|
||||||
@Inject()
|
@Inject()
|
||||||
pluginService: PluginService;
|
pluginService: PluginService;
|
||||||
|
|
||||||
|
|
||||||
@Init()
|
|
||||||
async init() {
|
async init() {
|
||||||
logger.info(`加载插件开始,加载模式:${process.env.certd_plugin_loadmode}`);
|
logger.info(`加载插件开始,加载模式:${process.env.certd_plugin_loadmode}`);
|
||||||
if (process.env.certd_plugin_loadmode === "metadata") {
|
if (process.env.certd_plugin_loadmode === "metadata") {
|
||||||
+3
-4
@@ -1,14 +1,13 @@
|
|||||||
import { logger, utils } from '@certd/basic';
|
import { logger, utils } from '@certd/basic';
|
||||||
import { UserSuiteService } from '@certd/commercial-core';
|
import { UserSuiteService } from '@certd/commercial-core';
|
||||||
import { Autoload, Init, Inject, Scope, ScopeEnum } from '@midwayjs/core';
|
import { Inject, Provide, Scope, ScopeEnum } from '@midwayjs/core';
|
||||||
|
|
||||||
@Autoload()
|
@Provide()
|
||||||
@Scope(ScopeEnum.Request, { allowDowngrade: true })
|
@Scope(ScopeEnum.Request, { allowDowngrade: true })
|
||||||
export class AutoDMitterRegister {
|
export class AutoMitterRegister {
|
||||||
@Inject()
|
@Inject()
|
||||||
userSuiteService: UserSuiteService;
|
userSuiteService: UserSuiteService;
|
||||||
|
|
||||||
@Init()
|
|
||||||
async init() {
|
async init() {
|
||||||
await this.registerOnNewUser();
|
await this.registerOnNewUser();
|
||||||
}
|
}
|
||||||
+5
-5
@@ -1,21 +1,21 @@
|
|||||||
import { Autoload, Init, Inject, Scope, ScopeEnum } from "@midwayjs/core";
|
import { Inject, Provide, Scope, ScopeEnum } from "@midwayjs/core";
|
||||||
import { CertInfoService } from "../monitor/index.js";
|
import { CertInfoService } from "../monitor/index.js";
|
||||||
import { pipelineEmitter } from "@certd/pipeline";
|
import { pipelineEmitter } from "@certd/pipeline";
|
||||||
import { CertInfo, EVENT_CERT_APPLY_SUCCESS } from "@certd/plugin-cert";
|
import { CertInfo, EVENT_CERT_APPLY_SUCCESS } from "@certd/plugin-cert";
|
||||||
import { PipelineEvent } from "@certd/pipeline";
|
import { PipelineEvent } from "@certd/pipeline";
|
||||||
|
|
||||||
@Autoload()
|
@Provide()
|
||||||
@Scope(ScopeEnum.Request, { allowDowngrade: true })
|
@Scope(ScopeEnum.Request, { allowDowngrade: true })
|
||||||
export class AutoEPipelineEmitterRegister {
|
export class AutoPipelineEmitterRegister {
|
||||||
@Inject()
|
@Inject()
|
||||||
certInfoService: CertInfoService;
|
certInfoService: CertInfoService;
|
||||||
|
|
||||||
@Init()
|
|
||||||
async init() {
|
async init() {
|
||||||
await this.onCertApplySuccess();
|
await this.onCertApplySuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
async onCertApplySuccess() {
|
async onCertApplySuccess() {
|
||||||
pipelineEmitter.on(EVENT_CERT_APPLY_SUCCESS, async (event: PipelineEvent<{cert:CertInfo,file:string}>) => {
|
pipelineEmitter.on(EVENT_CERT_APPLY_SUCCESS, async (event: PipelineEvent<{ cert: CertInfo; file: string }>) => {
|
||||||
await this.certInfoService.updateCertByPipelineId(event.pipeline.id, event.event.cert, event.event.file);
|
await this.certInfoService.updateCertByPipelineId(event.pipeline.id, event.event.cert, event.event.file);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
+3
-4
@@ -1,4 +1,4 @@
|
|||||||
import { App, Autoload, Config, Init, Inject, Scope, ScopeEnum } from '@midwayjs/core';
|
import { App, Config, Inject, Provide, Scope, ScopeEnum } from '@midwayjs/core';
|
||||||
import { getPlusInfo, isPlus } from '@certd/plus-core';
|
import { getPlusInfo, isPlus } from '@certd/plus-core';
|
||||||
import { isDev, logger } from '@certd/basic';
|
import { isDev, logger } from '@certd/basic';
|
||||||
|
|
||||||
@@ -11,9 +11,9 @@ import { UserService } from '../sys/authority/service/user-service.js';
|
|||||||
import { UserSettingsService } from '../mine/service/user-settings-service.js';
|
import { UserSettingsService } from '../mine/service/user-settings-service.js';
|
||||||
import { startProxyServer } from './proxy/server.js';
|
import { startProxyServer } from './proxy/server.js';
|
||||||
|
|
||||||
@Autoload()
|
@Provide()
|
||||||
@Scope(ScopeEnum.Request, { allowDowngrade: true })
|
@Scope(ScopeEnum.Request, { allowDowngrade: true })
|
||||||
export class AutoZPrint {
|
export class AutoPrint {
|
||||||
@Inject()
|
@Inject()
|
||||||
sysSettingsService: SysSettingsService;
|
sysSettingsService: SysSettingsService;
|
||||||
|
|
||||||
@@ -34,7 +34,6 @@ export class AutoZPrint {
|
|||||||
@Config('system.resetAdminPasswd')
|
@Config('system.resetAdminPasswd')
|
||||||
private resetAdminPasswd: boolean;
|
private resetAdminPasswd: boolean;
|
||||||
|
|
||||||
@Init()
|
|
||||||
async init() {
|
async init() {
|
||||||
//监听https
|
//监听https
|
||||||
this.startHttpsServer();
|
this.startHttpsServer();
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
import { Autoload, Init, Inject, Scope, ScopeEnum } from "@midwayjs/core";
|
||||||
|
import { AutoInitSite } from "./auto-init-site.js";
|
||||||
|
import { AutoLoadPlugins } from "./auto-load-plugins.js";
|
||||||
|
import { AutoCron } from "./auto-cron.js";
|
||||||
|
import { AutoMitterRegister } from "./auto-mitter-register.js";
|
||||||
|
import { AutoPipelineEmitterRegister } from "./auto-pipeline-emitter-register.js";
|
||||||
|
import { AutoFix } from "./auto-fix.js";
|
||||||
|
import { AutoPrint } from "./auto-print.js";
|
||||||
|
|
||||||
|
@Autoload()
|
||||||
|
@Scope(ScopeEnum.Request, { allowDowngrade: true })
|
||||||
|
export class AutoRegister {
|
||||||
|
@Inject()
|
||||||
|
autoInitSite: AutoInitSite;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
autoLoadPlugins: AutoLoadPlugins;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
autoCron: AutoCron;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
autoMitterRegister: AutoMitterRegister;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
autoPipelineEmitterRegister: AutoPipelineEmitterRegister;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
autoPrint: AutoPrint;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
autoFix: AutoFix;
|
||||||
|
|
||||||
|
@Init()
|
||||||
|
async init() {
|
||||||
|
await this.autoInitSite.init();
|
||||||
|
await this.autoLoadPlugins.init();
|
||||||
|
await this.autoCron.init();
|
||||||
|
await this.autoMitterRegister.init();
|
||||||
|
await this.autoPipelineEmitterRegister.init();
|
||||||
|
await this.autoFix.init();
|
||||||
|
await this.autoPrint.init();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import assert from "assert";
|
||||||
|
import { EabAccess } from "./eab-access.js";
|
||||||
|
|
||||||
|
describe("EabAccess", () => {
|
||||||
|
it("generates an account key payload for the current kid", async () => {
|
||||||
|
const access = new EabAccess();
|
||||||
|
access.kid = "kid-1";
|
||||||
|
|
||||||
|
const payload = JSON.parse(await access.onGenerateAccountKey());
|
||||||
|
|
||||||
|
assert.equal(payload.kid, "kid-1");
|
||||||
|
assert.match(payload.privateKey, /BEGIN (RSA )?PRIVATE KEY/);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("requires kid before generating the account key payload", async () => {
|
||||||
|
const access = new EabAccess();
|
||||||
|
|
||||||
|
await assert.rejects(() => access.onGenerateAccountKey(), /请先填写KID/);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import { IsAccess, AccessInput, BaseAccess } from "@certd/pipeline";
|
import { IsAccess, AccessInput, BaseAccess } from "@certd/pipeline";
|
||||||
|
import * as acme from "@certd/acme-client";
|
||||||
|
|
||||||
@IsAccess({
|
@IsAccess({
|
||||||
name: "eab",
|
name: "eab",
|
||||||
@@ -7,6 +8,23 @@ import { IsAccess, AccessInput, BaseAccess } from "@certd/pipeline";
|
|||||||
icon: "ic:outline-lock",
|
icon: "ic:outline-lock",
|
||||||
})
|
})
|
||||||
export class EabAccess extends BaseAccess {
|
export class EabAccess extends BaseAccess {
|
||||||
|
@AccessInput({
|
||||||
|
title: "EAB类型",
|
||||||
|
component: {
|
||||||
|
name: "a-select",
|
||||||
|
options: [
|
||||||
|
{ value: "google", label: "Google(免费)", icon: "flat-color-icons:google" },
|
||||||
|
{ value: "zerossl", label: "ZeroSSL(免费)", icon: "emojione:digit-zero" },
|
||||||
|
{ value: "litessl", label: "litessl(免费)", icon: "roentgen:free" },
|
||||||
|
{ value: "sslcom", label: "SSL.com(仅主域名和www免费)", icon: "la:expeditedssl" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
helper: "请选择EAB类型",
|
||||||
|
required: true,
|
||||||
|
encrypt: false,
|
||||||
|
})
|
||||||
|
eabType = "";
|
||||||
|
|
||||||
@AccessInput({
|
@AccessInput({
|
||||||
title: "KID",
|
title: "KID",
|
||||||
component: {
|
component: {
|
||||||
@@ -34,10 +52,35 @@ export class EabAccess extends BaseAccess {
|
|||||||
placeholder: "绑定一个邮箱",
|
placeholder: "绑定一个邮箱",
|
||||||
},
|
},
|
||||||
rules: [{ type: "email", message: "请输入正确的邮箱" }],
|
rules: [{ type: "email", message: "请输入正确的邮箱" }],
|
||||||
helper: "Google的EAB申请证书,更换邮箱会导致EAB失效,可以在此处绑定一个邮箱避免此问题",
|
helper: "绑定一个邮箱,避免失效",
|
||||||
required: true,
|
required: true,
|
||||||
})
|
})
|
||||||
email = "";
|
email = "";
|
||||||
|
|
||||||
|
@AccessInput({
|
||||||
|
title: "ACME账号私钥",
|
||||||
|
component: {
|
||||||
|
name: "refresh-input",
|
||||||
|
action: "GenerateAccountKey",
|
||||||
|
buttonText: "刷新账号私钥",
|
||||||
|
successMessage: "账号私钥已刷新,请保存授权配置",
|
||||||
|
},
|
||||||
|
required: true,
|
||||||
|
helper: "如果修改了KID,请点击刷新重新生成账号私钥",
|
||||||
|
encrypt: true,
|
||||||
|
})
|
||||||
|
accountKey = "";
|
||||||
|
|
||||||
|
async onGenerateAccountKey() {
|
||||||
|
if (!this.kid) {
|
||||||
|
throw new Error("请先填写KID");
|
||||||
|
}
|
||||||
|
const key = await acme.crypto.createPrivateKey(2048);
|
||||||
|
return JSON.stringify({
|
||||||
|
kid: this.kid,
|
||||||
|
privateKey: key.toString(),
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
new EabAccess();
|
new EabAccess();
|
||||||
|
|||||||
@@ -0,0 +1,114 @@
|
|||||||
|
import assert from "assert";
|
||||||
|
import { AcmeService } from "./acme.js";
|
||||||
|
|
||||||
|
const logger = {
|
||||||
|
info() {},
|
||||||
|
error() {},
|
||||||
|
warn() {},
|
||||||
|
debug() {},
|
||||||
|
};
|
||||||
|
|
||||||
|
describe("AcmeService account config", () => {
|
||||||
|
it("keeps legacy email-based account config when EAB has no saved account key", async () => {
|
||||||
|
const userContext = {
|
||||||
|
async getObj(key: string) {
|
||||||
|
if (key === "acme.config.google.user@example.com") {
|
||||||
|
return {
|
||||||
|
key: "legacy-email-key",
|
||||||
|
accountUrl: "https://dv.acme-v02.api.pki.goog/acme/acct/legacy",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
async setObj() {},
|
||||||
|
};
|
||||||
|
const service = new AcmeService({
|
||||||
|
userId: 1,
|
||||||
|
userContext: userContext as any,
|
||||||
|
logger: logger as any,
|
||||||
|
sslProvider: "google",
|
||||||
|
eab: {
|
||||||
|
id: 12,
|
||||||
|
kid: "kid-1",
|
||||||
|
hmacKey: "hmac",
|
||||||
|
} as any,
|
||||||
|
domainParser: {} as any,
|
||||||
|
});
|
||||||
|
|
||||||
|
const conf = await service.getAccountConfig("user@example.com", { enabled: false, mappings: {} });
|
||||||
|
|
||||||
|
assert.equal(conf.key, "legacy-email-key");
|
||||||
|
assert.equal(conf.accountUrl, "https://dv.acme-v02.api.pki.goog/acme/acct/legacy");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("uses the account key saved on the EAB access before legacy email config", async () => {
|
||||||
|
const userContext = {
|
||||||
|
async getObj(key: string) {
|
||||||
|
if (key === "acme.config.google.access.12") {
|
||||||
|
return { accountUrl: "https://dv.acme-v02.api.pki.goog/acme/acct/1" };
|
||||||
|
}
|
||||||
|
if (key === "acme.config.google.user@example.com") {
|
||||||
|
return { key: "legacy-email-key" };
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
async setObj() {},
|
||||||
|
};
|
||||||
|
const service = new AcmeService({
|
||||||
|
userId: 1,
|
||||||
|
userContext: userContext as any,
|
||||||
|
logger: logger as any,
|
||||||
|
sslProvider: "google",
|
||||||
|
eab: {
|
||||||
|
id: 12,
|
||||||
|
kid: "kid-1",
|
||||||
|
hmacKey: "hmac",
|
||||||
|
accountKey: JSON.stringify({ kid: "kid-1", privateKey: "eab-account-key" }),
|
||||||
|
} as any,
|
||||||
|
domainParser: {} as any,
|
||||||
|
});
|
||||||
|
|
||||||
|
const conf = await service.getAccountConfig("user@example.com", { enabled: false, mappings: {} });
|
||||||
|
|
||||||
|
assert.equal(conf.key, "eab-account-key");
|
||||||
|
assert.equal(conf.accountUrl, "https://dv.acme-v02.api.pki.goog/acme/acct/1");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("rejects an EAB account key generated for another kid", async () => {
|
||||||
|
const service = new AcmeService({
|
||||||
|
userId: 1,
|
||||||
|
userContext: {} as any,
|
||||||
|
logger: logger as any,
|
||||||
|
sslProvider: "google",
|
||||||
|
eab: {
|
||||||
|
id: 12,
|
||||||
|
kid: "kid-2",
|
||||||
|
hmacKey: "hmac",
|
||||||
|
accountKey: JSON.stringify({ kid: "kid-1", privateKey: "eab-account-key" }),
|
||||||
|
} as any,
|
||||||
|
domainParser: {} as any,
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.throws(() => service.getEabAccountPrivateKey(), /请点击刷新重新生成ACME账号私钥/);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("formats expired EAB errors with a Chinese recovery hint", () => {
|
||||||
|
const service = new AcmeService({
|
||||||
|
userId: 1,
|
||||||
|
userContext: {} as any,
|
||||||
|
logger: logger as any,
|
||||||
|
sslProvider: "google",
|
||||||
|
eab: {
|
||||||
|
id: 12,
|
||||||
|
kid: "kid-1",
|
||||||
|
hmacKey: "hmac",
|
||||||
|
} as any,
|
||||||
|
domainParser: {} as any,
|
||||||
|
});
|
||||||
|
|
||||||
|
const error = service.formatCreateAccountError(new Error("Unknown external account binding (EAB) key. This may be due to the EAB key expiring"));
|
||||||
|
|
||||||
|
assert.match(error.message, /EAB授权已失效或已过期/);
|
||||||
|
assert.match(error.message, /请重新获取EAB授权并刷新ACME账号私钥后重试/);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -49,11 +49,15 @@ export type CertInfo = {
|
|||||||
};
|
};
|
||||||
export type SSLProvider = "letsencrypt" | "google" | "zerossl" | "sslcom" | "letsencrypt_staging";
|
export type SSLProvider = "letsencrypt" | "google" | "zerossl" | "sslcom" | "letsencrypt_staging";
|
||||||
export type PrivateKeyType = "rsa_1024" | "rsa_2048" | "rsa_3072" | "rsa_4096" | "ec_256" | "ec_384" | "ec_521";
|
export type PrivateKeyType = "rsa_1024" | "rsa_2048" | "rsa_3072" | "rsa_4096" | "ec_256" | "ec_384" | "ec_521";
|
||||||
|
type AcmeEabOptions = ClientExternalAccountBindingOptions & {
|
||||||
|
id?: number;
|
||||||
|
accountKey?: string;
|
||||||
|
};
|
||||||
type AcmeServiceOptions = {
|
type AcmeServiceOptions = {
|
||||||
userContext: IContext;
|
userContext: IContext;
|
||||||
logger: ILogger;
|
logger: ILogger;
|
||||||
sslProvider: SSLProvider;
|
sslProvider: SSLProvider;
|
||||||
eab?: ClientExternalAccountBindingOptions;
|
eab?: AcmeEabOptions;
|
||||||
skipLocalVerify?: boolean;
|
skipLocalVerify?: boolean;
|
||||||
useMappingProxy?: boolean;
|
useMappingProxy?: boolean;
|
||||||
reverseProxy?: string;
|
reverseProxy?: string;
|
||||||
@@ -71,7 +75,7 @@ export class AcmeService {
|
|||||||
logger: ILogger;
|
logger: ILogger;
|
||||||
sslProvider: SSLProvider;
|
sslProvider: SSLProvider;
|
||||||
skipLocalVerify = true;
|
skipLocalVerify = true;
|
||||||
eab?: ClientExternalAccountBindingOptions;
|
eab?: AcmeEabOptions;
|
||||||
constructor(options: AcmeServiceOptions) {
|
constructor(options: AcmeServiceOptions) {
|
||||||
this.options = options;
|
this.options = options;
|
||||||
this.userContext = options.userContext;
|
this.userContext = options.userContext;
|
||||||
@@ -85,7 +89,14 @@ export class AcmeService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getAccountConfig(email: string, urlMapping: UrlMapping): Promise<any> {
|
async getAccountConfig(email: string, urlMapping: UrlMapping): Promise<any> {
|
||||||
const conf = (await this.userContext.getObj(this.buildAccountKey(email))) || {};
|
let conf = (await this.userContext.getObj(this.buildAccountKey(email))) || {};
|
||||||
|
const eabAccountKey = this.getEabAccountPrivateKey();
|
||||||
|
if (eabAccountKey) {
|
||||||
|
conf = {
|
||||||
|
...((await this.userContext.getObj(this.buildAccessAccountKey())) || {}),
|
||||||
|
key: eabAccountKey,
|
||||||
|
};
|
||||||
|
}
|
||||||
if (urlMapping && urlMapping.mappings) {
|
if (urlMapping && urlMapping.mappings) {
|
||||||
for (const key in urlMapping.mappings) {
|
for (const key in urlMapping.mappings) {
|
||||||
if (Object.prototype.hasOwnProperty.call(urlMapping.mappings, key)) {
|
if (Object.prototype.hasOwnProperty.call(urlMapping.mappings, key)) {
|
||||||
@@ -104,16 +115,49 @@ export class AcmeService {
|
|||||||
return `acme.config.${this.sslProvider}.${email}`;
|
return `acme.config.${this.sslProvider}.${email}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buildAccessAccountKey() {
|
||||||
|
return `acme.config.${this.sslProvider}.access.${this.eab.id}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
getEabAccountPrivateKey() {
|
||||||
|
if (!this.eab?.accountKey) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
let accountKey;
|
||||||
|
try {
|
||||||
|
accountKey = JSON.parse(this.eab.accountKey);
|
||||||
|
} catch {
|
||||||
|
return this.eab.accountKey;
|
||||||
|
}
|
||||||
|
if (accountKey.kid !== this.eab.kid) {
|
||||||
|
throw new Error("EAB的KID已变化,请点击刷新重新生成ACME账号私钥");
|
||||||
|
}
|
||||||
|
return accountKey.privateKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
formatCreateAccountError(e: any) {
|
||||||
|
const message = e?.message || "";
|
||||||
|
if (message.includes("Unknown external account binding (EAB) key")) {
|
||||||
|
return new Error(`EAB授权已失效或已过期,请重新获取EAB授权并刷新ACME账号私钥后重试。原始错误:${message}`);
|
||||||
|
}
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
async saveAccountConfig(email: string, conf: any) {
|
async saveAccountConfig(email: string, conf: any) {
|
||||||
|
if (this.getEabAccountPrivateKey()) {
|
||||||
|
// userContext 跟用户走。公共 EAB 场景下这里仅作为当前用户缓存;
|
||||||
|
// 其他用户会通过 onlyReturnExisting 用同一个账号私钥取回 accountUrl。
|
||||||
|
await this.userContext.setObj(this.buildAccessAccountKey(), { accountUrl: conf.accountUrl });
|
||||||
|
return;
|
||||||
|
}
|
||||||
await this.userContext.setObj(this.buildAccountKey(email), conf);
|
await this.userContext.setObj(this.buildAccountKey(email), conf);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getAcmeClient(email: string): Promise<acme.Client> {
|
async getAcmeClient(email: string): Promise<acme.Client> {
|
||||||
|
|
||||||
const directoryUrl = acme.getDirectoryUrl({ sslProvider: this.sslProvider, pkType: this.options.privateKeyType });
|
const directoryUrl = acme.getDirectoryUrl({ sslProvider: this.sslProvider, pkType: this.options.privateKeyType });
|
||||||
let targetUrl = directoryUrl.replace("https://", "");
|
let targetUrl = directoryUrl.replace("https://", "");
|
||||||
targetUrl = targetUrl.substring(0, targetUrl.indexOf("/"));
|
targetUrl = targetUrl.substring(0, targetUrl.indexOf("/"));
|
||||||
|
|
||||||
const mappings = {
|
const mappings = {
|
||||||
"acme-v02.api.letsencrypt.org": "le.px.certd.handfree.work",
|
"acme-v02.api.letsencrypt.org": "le.px.certd.handfree.work",
|
||||||
"dv.acme-v02.api.pki.goog": "gg.px.certd.handfree.work",
|
"dv.acme-v02.api.pki.goog": "gg.px.certd.handfree.work",
|
||||||
@@ -171,7 +215,23 @@ export class AcmeService {
|
|||||||
contact: [`mailto:${email}`],
|
contact: [`mailto:${email}`],
|
||||||
externalAccountBinding: this.eab,
|
externalAccountBinding: this.eab,
|
||||||
};
|
};
|
||||||
await client.createAccount(accountPayload);
|
if (this.getEabAccountPrivateKey()) {
|
||||||
|
try {
|
||||||
|
// RFC 8555 的 newAccount 支持 onlyReturnExisting。
|
||||||
|
// 使用同一个账号私钥时,CA 会返回已存在账号的 URL,不会再次消费 EAB。
|
||||||
|
await client.createAccount({ onlyReturnExisting: true });
|
||||||
|
conf.accountUrl = client.getAccountUrl();
|
||||||
|
await this.saveAccountConfig(email, conf);
|
||||||
|
return client;
|
||||||
|
} catch (e: any) {
|
||||||
|
this.logger.info(`未找到已存在的ACME账号,准备创建新账号:${e.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
await client.createAccount(accountPayload);
|
||||||
|
} catch (e: any) {
|
||||||
|
throw this.formatCreateAccountError(e);
|
||||||
|
}
|
||||||
conf.accountUrl = client.getAccountUrl();
|
conf.accountUrl = client.getAccountUrl();
|
||||||
await this.saveAccountConfig(email, conf);
|
await this.saveAccountConfig(email, conf);
|
||||||
}
|
}
|
||||||
|
|||||||
Generated
+112
-57
@@ -94,6 +94,9 @@ importers:
|
|||||||
chai-as-promised:
|
chai-as-promised:
|
||||||
specifier: ^7.1.2
|
specifier: ^7.1.2
|
||||||
version: 7.1.2(chai@4.5.0)
|
version: 7.1.2(chai@4.5.0)
|
||||||
|
cross-env:
|
||||||
|
specifier: ^7.0.3
|
||||||
|
version: 7.0.3
|
||||||
eslint:
|
eslint:
|
||||||
specifier: ^8.57.0
|
specifier: ^8.57.0
|
||||||
version: 8.57.0
|
version: 8.57.0
|
||||||
@@ -106,6 +109,9 @@ importers:
|
|||||||
eslint-plugin-prettier:
|
eslint-plugin-prettier:
|
||||||
specifier: ^4.2.1
|
specifier: ^4.2.1
|
||||||
version: 4.2.1(eslint-config-prettier@8.10.0(eslint@8.57.0))(eslint@8.57.0)(prettier@2.8.8)
|
version: 4.2.1(eslint-config-prettier@8.10.0(eslint@8.57.0))(eslint@8.57.0)(prettier@2.8.8)
|
||||||
|
esmock:
|
||||||
|
specifier: ^2.7.5
|
||||||
|
version: 2.7.5
|
||||||
jsdoc-to-markdown:
|
jsdoc-to-markdown:
|
||||||
specifier: ^8.0.1
|
specifier: ^8.0.1
|
||||||
version: 8.0.3
|
version: 8.0.3
|
||||||
@@ -188,6 +194,9 @@ importers:
|
|||||||
chai:
|
chai:
|
||||||
specifier: 4.3.10
|
specifier: 4.3.10
|
||||||
version: 4.3.10
|
version: 4.3.10
|
||||||
|
cross-env:
|
||||||
|
specifier: ^7.0.3
|
||||||
|
version: 7.0.3
|
||||||
eslint:
|
eslint:
|
||||||
specifier: ^8.41.0
|
specifier: ^8.41.0
|
||||||
version: 8.57.0
|
version: 8.57.0
|
||||||
@@ -197,6 +206,9 @@ importers:
|
|||||||
eslint-plugin-prettier:
|
eslint-plugin-prettier:
|
||||||
specifier: ^4.2.1
|
specifier: ^4.2.1
|
||||||
version: 4.2.1(eslint-config-prettier@8.10.0(eslint@8.57.0))(eslint@8.57.0)(prettier@2.8.8)
|
version: 4.2.1(eslint-config-prettier@8.10.0(eslint@8.57.0))(eslint@8.57.0)(prettier@2.8.8)
|
||||||
|
esmock:
|
||||||
|
specifier: ^2.7.5
|
||||||
|
version: 2.7.5
|
||||||
mocha:
|
mocha:
|
||||||
specifier: ^10.2.0
|
specifier: ^10.2.0
|
||||||
version: 10.8.2
|
version: 10.8.2
|
||||||
@@ -267,6 +279,9 @@ importers:
|
|||||||
chai:
|
chai:
|
||||||
specifier: 4.3.10
|
specifier: 4.3.10
|
||||||
version: 4.3.10
|
version: 4.3.10
|
||||||
|
cross-env:
|
||||||
|
specifier: ^7.0.3
|
||||||
|
version: 7.0.3
|
||||||
eslint:
|
eslint:
|
||||||
specifier: ^8.41.0
|
specifier: ^8.41.0
|
||||||
version: 8.57.0
|
version: 8.57.0
|
||||||
@@ -276,6 +291,9 @@ importers:
|
|||||||
eslint-plugin-prettier:
|
eslint-plugin-prettier:
|
||||||
specifier: ^4.2.1
|
specifier: ^4.2.1
|
||||||
version: 4.2.1(eslint-config-prettier@8.10.0(eslint@8.57.0))(eslint@8.57.0)(prettier@2.8.8)
|
version: 4.2.1(eslint-config-prettier@8.10.0(eslint@8.57.0))(eslint@8.57.0)(prettier@2.8.8)
|
||||||
|
esmock:
|
||||||
|
specifier: ^2.7.5
|
||||||
|
version: 2.7.5
|
||||||
mocha:
|
mocha:
|
||||||
specifier: ^10.2.0
|
specifier: ^10.2.0
|
||||||
version: 10.8.2
|
version: 10.8.2
|
||||||
@@ -313,6 +331,12 @@ importers:
|
|||||||
'@typescript-eslint/parser':
|
'@typescript-eslint/parser':
|
||||||
specifier: ^8.26.1
|
specifier: ^8.26.1
|
||||||
version: 8.32.1(eslint@8.57.0)(typescript@5.9.3)
|
version: 8.32.1(eslint@8.57.0)(typescript@5.9.3)
|
||||||
|
cross-env:
|
||||||
|
specifier: ^7.0.3
|
||||||
|
version: 7.0.3
|
||||||
|
esmock:
|
||||||
|
specifier: ^2.7.5
|
||||||
|
version: 2.7.5
|
||||||
prettier:
|
prettier:
|
||||||
specifier: ^2.8.8
|
specifier: ^2.8.8
|
||||||
version: 2.8.8
|
version: 2.8.8
|
||||||
@@ -335,6 +359,9 @@ importers:
|
|||||||
'@typescript-eslint/parser':
|
'@typescript-eslint/parser':
|
||||||
specifier: ^8.26.1
|
specifier: ^8.26.1
|
||||||
version: 8.32.1(eslint@8.57.0)(typescript@5.9.3)
|
version: 8.32.1(eslint@8.57.0)(typescript@5.9.3)
|
||||||
|
cross-env:
|
||||||
|
specifier: ^7.0.3
|
||||||
|
version: 7.0.3
|
||||||
eslint:
|
eslint:
|
||||||
specifier: ^8.24.0
|
specifier: ^8.24.0
|
||||||
version: 8.57.0
|
version: 8.57.0
|
||||||
@@ -344,6 +371,9 @@ importers:
|
|||||||
eslint-plugin-prettier:
|
eslint-plugin-prettier:
|
||||||
specifier: ^4.2.1
|
specifier: ^4.2.1
|
||||||
version: 4.2.1(eslint-config-prettier@8.10.0(eslint@8.57.0))(eslint@8.57.0)(prettier@2.8.8)
|
version: 4.2.1(eslint-config-prettier@8.10.0(eslint@8.57.0))(eslint@8.57.0)(prettier@2.8.8)
|
||||||
|
esmock:
|
||||||
|
specifier: ^2.7.5
|
||||||
|
version: 2.7.5
|
||||||
prettier:
|
prettier:
|
||||||
specifier: ^2.8.8
|
specifier: ^2.8.8
|
||||||
version: 2.8.8
|
version: 2.8.8
|
||||||
@@ -403,8 +433,11 @@ importers:
|
|||||||
specifier: ^1.30.0
|
specifier: ^1.30.0
|
||||||
version: 1.31.0
|
version: 1.31.0
|
||||||
cross-env:
|
cross-env:
|
||||||
specifier: ^5.1.4
|
specifier: ^7.0.3
|
||||||
version: 5.2.1
|
version: 7.0.3
|
||||||
|
esmock:
|
||||||
|
specifier: ^2.7.5
|
||||||
|
version: 2.7.5
|
||||||
js-yaml:
|
js-yaml:
|
||||||
specifier: ^3.11.0
|
specifier: ^3.11.0
|
||||||
version: 3.14.1
|
version: 3.14.1
|
||||||
@@ -436,6 +469,9 @@ importers:
|
|||||||
'@typescript-eslint/parser':
|
'@typescript-eslint/parser':
|
||||||
specifier: ^8.26.1
|
specifier: ^8.26.1
|
||||||
version: 8.32.1(eslint@8.57.0)(typescript@5.9.3)
|
version: 8.32.1(eslint@8.57.0)(typescript@5.9.3)
|
||||||
|
cross-env:
|
||||||
|
specifier: ^7.0.3
|
||||||
|
version: 7.0.3
|
||||||
eslint:
|
eslint:
|
||||||
specifier: ^8.24.0
|
specifier: ^8.24.0
|
||||||
version: 8.57.0
|
version: 8.57.0
|
||||||
@@ -445,6 +481,9 @@ importers:
|
|||||||
eslint-plugin-prettier:
|
eslint-plugin-prettier:
|
||||||
specifier: ^4.2.1
|
specifier: ^4.2.1
|
||||||
version: 4.2.1(eslint-config-prettier@8.10.0(eslint@8.57.0))(eslint@8.57.0)(prettier@2.8.8)
|
version: 4.2.1(eslint-config-prettier@8.10.0(eslint@8.57.0))(eslint@8.57.0)(prettier@2.8.8)
|
||||||
|
esmock:
|
||||||
|
specifier: ^2.7.5
|
||||||
|
version: 2.7.5
|
||||||
prettier:
|
prettier:
|
||||||
specifier: ^2.8.8
|
specifier: ^2.8.8
|
||||||
version: 2.8.8
|
version: 2.8.8
|
||||||
@@ -505,9 +544,6 @@ importers:
|
|||||||
better-sqlite3:
|
better-sqlite3:
|
||||||
specifier: ^11.1.2
|
specifier: ^11.1.2
|
||||||
version: 11.10.0
|
version: 11.10.0
|
||||||
cross-env:
|
|
||||||
specifier: ^7.0.3
|
|
||||||
version: 7.0.3
|
|
||||||
dayjs:
|
dayjs:
|
||||||
specifier: ^1.11.7
|
specifier: ^1.11.7
|
||||||
version: 1.11.13
|
version: 1.11.13
|
||||||
@@ -539,6 +575,9 @@ importers:
|
|||||||
'@typescript-eslint/parser':
|
'@typescript-eslint/parser':
|
||||||
specifier: ^8.26.1
|
specifier: ^8.26.1
|
||||||
version: 8.32.1(eslint@8.57.0)(typescript@5.9.3)
|
version: 8.32.1(eslint@8.57.0)(typescript@5.9.3)
|
||||||
|
cross-env:
|
||||||
|
specifier: ^7.0.3
|
||||||
|
version: 7.0.3
|
||||||
eslint:
|
eslint:
|
||||||
specifier: ^8.24.0
|
specifier: ^8.24.0
|
||||||
version: 8.57.0
|
version: 8.57.0
|
||||||
@@ -548,6 +587,9 @@ importers:
|
|||||||
eslint-plugin-prettier:
|
eslint-plugin-prettier:
|
||||||
specifier: ^4.2.1
|
specifier: ^4.2.1
|
||||||
version: 4.2.1(eslint-config-prettier@8.10.0(eslint@8.57.0))(eslint@8.57.0)(prettier@2.8.8)
|
version: 4.2.1(eslint-config-prettier@8.10.0(eslint@8.57.0))(eslint@8.57.0)(prettier@2.8.8)
|
||||||
|
esmock:
|
||||||
|
specifier: ^2.7.5
|
||||||
|
version: 2.7.5
|
||||||
mocha:
|
mocha:
|
||||||
specifier: ^10.2.0
|
specifier: ^10.2.0
|
||||||
version: 10.8.2
|
version: 10.8.2
|
||||||
@@ -594,6 +636,9 @@ importers:
|
|||||||
'@typescript-eslint/parser':
|
'@typescript-eslint/parser':
|
||||||
specifier: ^8.26.1
|
specifier: ^8.26.1
|
||||||
version: 8.32.1(eslint@8.57.0)(typescript@5.9.3)
|
version: 8.32.1(eslint@8.57.0)(typescript@5.9.3)
|
||||||
|
cross-env:
|
||||||
|
specifier: ^7.0.3
|
||||||
|
version: 7.0.3
|
||||||
eslint:
|
eslint:
|
||||||
specifier: ^8.24.0
|
specifier: ^8.24.0
|
||||||
version: 8.57.0
|
version: 8.57.0
|
||||||
@@ -609,6 +654,9 @@ importers:
|
|||||||
eslint-plugin-prettier:
|
eslint-plugin-prettier:
|
||||||
specifier: ^4.2.1
|
specifier: ^4.2.1
|
||||||
version: 4.2.1(eslint-config-prettier@8.10.0(eslint@8.57.0))(eslint@8.57.0)(prettier@2.8.8)
|
version: 4.2.1(eslint-config-prettier@8.10.0(eslint@8.57.0))(eslint@8.57.0)(prettier@2.8.8)
|
||||||
|
esmock:
|
||||||
|
specifier: ^2.7.5
|
||||||
|
version: 2.7.5
|
||||||
prettier:
|
prettier:
|
||||||
specifier: ^2.8.8
|
specifier: ^2.8.8
|
||||||
version: 2.8.8
|
version: 2.8.8
|
||||||
@@ -661,6 +709,9 @@ importers:
|
|||||||
chai:
|
chai:
|
||||||
specifier: ^4.3.6
|
specifier: ^4.3.6
|
||||||
version: 4.5.0
|
version: 4.5.0
|
||||||
|
cross-env:
|
||||||
|
specifier: ^7.0.3
|
||||||
|
version: 7.0.3
|
||||||
eslint:
|
eslint:
|
||||||
specifier: ^8.24.0
|
specifier: ^8.24.0
|
||||||
version: 8.57.0
|
version: 8.57.0
|
||||||
@@ -670,6 +721,9 @@ importers:
|
|||||||
eslint-plugin-prettier:
|
eslint-plugin-prettier:
|
||||||
specifier: ^4.2.1
|
specifier: ^4.2.1
|
||||||
version: 4.2.1(eslint-config-prettier@8.10.0(eslint@8.57.0))(eslint@8.57.0)(prettier@2.8.8)
|
version: 4.2.1(eslint-config-prettier@8.10.0(eslint@8.57.0))(eslint@8.57.0)(prettier@2.8.8)
|
||||||
|
esmock:
|
||||||
|
specifier: ^2.7.5
|
||||||
|
version: 2.7.5
|
||||||
mocha:
|
mocha:
|
||||||
specifier: ^10.1.0
|
specifier: ^10.1.0
|
||||||
version: 10.8.2
|
version: 10.8.2
|
||||||
@@ -776,6 +830,9 @@ importers:
|
|||||||
chai:
|
chai:
|
||||||
specifier: ^4.3.6
|
specifier: ^4.3.6
|
||||||
version: 4.5.0
|
version: 4.5.0
|
||||||
|
cross-env:
|
||||||
|
specifier: ^7.0.3
|
||||||
|
version: 7.0.3
|
||||||
eslint:
|
eslint:
|
||||||
specifier: ^8.24.0
|
specifier: ^8.24.0
|
||||||
version: 8.57.0
|
version: 8.57.0
|
||||||
@@ -785,6 +842,9 @@ importers:
|
|||||||
eslint-plugin-prettier:
|
eslint-plugin-prettier:
|
||||||
specifier: ^4.2.1
|
specifier: ^4.2.1
|
||||||
version: 4.2.1(eslint-config-prettier@8.10.0(eslint@8.57.0))(eslint@8.57.0)(prettier@2.8.8)
|
version: 4.2.1(eslint-config-prettier@8.10.0(eslint@8.57.0))(eslint@8.57.0)(prettier@2.8.8)
|
||||||
|
esmock:
|
||||||
|
specifier: ^2.7.5
|
||||||
|
version: 2.7.5
|
||||||
mocha:
|
mocha:
|
||||||
specifier: ^10.1.0
|
specifier: ^10.1.0
|
||||||
version: 10.8.2
|
version: 10.8.2
|
||||||
@@ -861,6 +921,9 @@ importers:
|
|||||||
'@typescript-eslint/parser':
|
'@typescript-eslint/parser':
|
||||||
specifier: ^8.26.1
|
specifier: ^8.26.1
|
||||||
version: 8.32.1(eslint@8.57.0)(typescript@5.9.3)
|
version: 8.32.1(eslint@8.57.0)(typescript@5.9.3)
|
||||||
|
cross-env:
|
||||||
|
specifier: ^7.0.3
|
||||||
|
version: 7.0.3
|
||||||
eslint:
|
eslint:
|
||||||
specifier: ^8.24.0
|
specifier: ^8.24.0
|
||||||
version: 8.57.0
|
version: 8.57.0
|
||||||
@@ -870,6 +933,9 @@ importers:
|
|||||||
eslint-plugin-prettier:
|
eslint-plugin-prettier:
|
||||||
specifier: ^4.2.1
|
specifier: ^4.2.1
|
||||||
version: 4.2.1(eslint-config-prettier@8.10.0(eslint@8.57.0))(eslint@8.57.0)(prettier@2.8.8)
|
version: 4.2.1(eslint-config-prettier@8.10.0(eslint@8.57.0))(eslint@8.57.0)(prettier@2.8.8)
|
||||||
|
esmock:
|
||||||
|
specifier: ^2.7.5
|
||||||
|
version: 2.7.5
|
||||||
mocha:
|
mocha:
|
||||||
specifier: ^10.2.0
|
specifier: ^10.2.0
|
||||||
version: 10.8.2
|
version: 10.8.2
|
||||||
@@ -952,6 +1018,9 @@ importers:
|
|||||||
chai:
|
chai:
|
||||||
specifier: 4.3.10
|
specifier: 4.3.10
|
||||||
version: 4.3.10
|
version: 4.3.10
|
||||||
|
cross-env:
|
||||||
|
specifier: ^7.0.3
|
||||||
|
version: 7.0.3
|
||||||
eslint:
|
eslint:
|
||||||
specifier: ^8.41.0
|
specifier: ^8.41.0
|
||||||
version: 8.57.0
|
version: 8.57.0
|
||||||
@@ -961,6 +1030,9 @@ importers:
|
|||||||
eslint-plugin-prettier:
|
eslint-plugin-prettier:
|
||||||
specifier: ^4.2.1
|
specifier: ^4.2.1
|
||||||
version: 4.2.1(eslint-config-prettier@8.10.0(eslint@8.57.0))(eslint@8.57.0)(prettier@2.8.8)
|
version: 4.2.1(eslint-config-prettier@8.10.0(eslint@8.57.0))(eslint@8.57.0)(prettier@2.8.8)
|
||||||
|
esmock:
|
||||||
|
specifier: ^2.7.5
|
||||||
|
version: 2.7.5
|
||||||
mocha:
|
mocha:
|
||||||
specifier: ^10.2.0
|
specifier: ^10.2.0
|
||||||
version: 10.8.2
|
version: 10.8.2
|
||||||
@@ -1019,6 +1091,9 @@ importers:
|
|||||||
chai:
|
chai:
|
||||||
specifier: 4.3.10
|
specifier: 4.3.10
|
||||||
version: 4.3.10
|
version: 4.3.10
|
||||||
|
cross-env:
|
||||||
|
specifier: ^7.0.3
|
||||||
|
version: 7.0.3
|
||||||
eslint:
|
eslint:
|
||||||
specifier: ^8.41.0
|
specifier: ^8.41.0
|
||||||
version: 8.57.0
|
version: 8.57.0
|
||||||
@@ -1028,6 +1103,9 @@ importers:
|
|||||||
eslint-plugin-prettier:
|
eslint-plugin-prettier:
|
||||||
specifier: ^4.2.1
|
specifier: ^4.2.1
|
||||||
version: 4.2.1(eslint-config-prettier@8.10.0(eslint@8.57.0))(eslint@8.57.0)(prettier@2.8.8)
|
version: 4.2.1(eslint-config-prettier@8.10.0(eslint@8.57.0))(eslint@8.57.0)(prettier@2.8.8)
|
||||||
|
esmock:
|
||||||
|
specifier: ^2.7.5
|
||||||
|
version: 2.7.5
|
||||||
mocha:
|
mocha:
|
||||||
specifier: ^10.2.0
|
specifier: ^10.2.0
|
||||||
version: 10.8.2
|
version: 10.8.2
|
||||||
@@ -1154,9 +1232,6 @@ importers:
|
|||||||
cropperjs:
|
cropperjs:
|
||||||
specifier: ^1.6.1
|
specifier: ^1.6.1
|
||||||
version: 1.6.2
|
version: 1.6.2
|
||||||
cross-env:
|
|
||||||
specifier: ^7.0.3
|
|
||||||
version: 7.0.3
|
|
||||||
cssnano:
|
cssnano:
|
||||||
specifier: ^7.0.6
|
specifier: ^7.0.6
|
||||||
version: 7.0.7(postcss@8.5.6)
|
version: 7.0.7(postcss@8.5.6)
|
||||||
@@ -1344,6 +1419,9 @@ importers:
|
|||||||
chai:
|
chai:
|
||||||
specifier: ^5.1.0
|
specifier: ^5.1.0
|
||||||
version: 5.2.0
|
version: 5.2.0
|
||||||
|
cross-env:
|
||||||
|
specifier: ^7.0.3
|
||||||
|
version: 7.0.3
|
||||||
dependency-cruiser:
|
dependency-cruiser:
|
||||||
specifier: ^16.2.3
|
specifier: ^16.2.3
|
||||||
version: 16.10.2
|
version: 16.10.2
|
||||||
@@ -1371,6 +1449,9 @@ importers:
|
|||||||
eslint-plugin-vue:
|
eslint-plugin-vue:
|
||||||
specifier: ^9.23.0
|
specifier: ^9.23.0
|
||||||
version: 9.33.0(eslint@8.57.0)
|
version: 9.33.0(eslint@8.57.0)
|
||||||
|
esmock:
|
||||||
|
specifier: ^2.7.5
|
||||||
|
version: 2.7.5
|
||||||
less:
|
less:
|
||||||
specifier: ^4.2.0
|
specifier: ^4.2.0
|
||||||
version: 4.3.0
|
version: 4.3.0
|
||||||
@@ -1632,9 +1713,6 @@ importers:
|
|||||||
cron-parser:
|
cron-parser:
|
||||||
specifier: ^4.9.0
|
specifier: ^4.9.0
|
||||||
version: 4.9.0
|
version: 4.9.0
|
||||||
cross-env:
|
|
||||||
specifier: ^7.0.3
|
|
||||||
version: 7.0.3
|
|
||||||
crypto-js:
|
crypto-js:
|
||||||
specifier: ^4.2.0
|
specifier: ^4.2.0
|
||||||
version: 4.2.0
|
version: 4.2.0
|
||||||
@@ -1801,6 +1879,12 @@ importers:
|
|||||||
c8:
|
c8:
|
||||||
specifier: ^10.1.2
|
specifier: ^10.1.2
|
||||||
version: 10.1.3
|
version: 10.1.3
|
||||||
|
cross-env:
|
||||||
|
specifier: ^7.0.3
|
||||||
|
version: 7.0.3
|
||||||
|
esmock:
|
||||||
|
specifier: ^2.7.5
|
||||||
|
version: 2.7.5
|
||||||
mocha:
|
mocha:
|
||||||
specifier: ^10.2.0
|
specifier: ^10.2.0
|
||||||
version: 10.8.2
|
version: 10.8.2
|
||||||
@@ -4384,56 +4468,67 @@ packages:
|
|||||||
resolution: {integrity: sha512-u72Mzc6jyJwKjJbZZcIYmd9bumJu7KNmHYdue43vT1rXPm2rITwmPWF0mmPzLm9/vJWxIRbao/jrQmxTO0Sm9w==}
|
resolution: {integrity: sha512-u72Mzc6jyJwKjJbZZcIYmd9bumJu7KNmHYdue43vT1rXPm2rITwmPWF0mmPzLm9/vJWxIRbao/jrQmxTO0Sm9w==}
|
||||||
cpu: [arm]
|
cpu: [arm]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@rollup/rollup-linux-arm-musleabihf@4.50.0':
|
'@rollup/rollup-linux-arm-musleabihf@4.50.0':
|
||||||
resolution: {integrity: sha512-S4UefYdV0tnynDJV1mdkNawp0E5Qm2MtSs330IyHgaccOFrwqsvgigUD29uT+B/70PDY1eQ3t40+xf6wIvXJyg==}
|
resolution: {integrity: sha512-S4UefYdV0tnynDJV1mdkNawp0E5Qm2MtSs330IyHgaccOFrwqsvgigUD29uT+B/70PDY1eQ3t40+xf6wIvXJyg==}
|
||||||
cpu: [arm]
|
cpu: [arm]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
'@rollup/rollup-linux-arm64-gnu@4.50.0':
|
'@rollup/rollup-linux-arm64-gnu@4.50.0':
|
||||||
resolution: {integrity: sha512-1EhkSvUQXJsIhk4msxP5nNAUWoB4MFDHhtc4gAYvnqoHlaL9V3F37pNHabndawsfy/Tp7BPiy/aSa6XBYbaD1g==}
|
resolution: {integrity: sha512-1EhkSvUQXJsIhk4msxP5nNAUWoB4MFDHhtc4gAYvnqoHlaL9V3F37pNHabndawsfy/Tp7BPiy/aSa6XBYbaD1g==}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@rollup/rollup-linux-arm64-musl@4.50.0':
|
'@rollup/rollup-linux-arm64-musl@4.50.0':
|
||||||
resolution: {integrity: sha512-EtBDIZuDtVg75xIPIK1l5vCXNNCIRM0OBPUG+tbApDuJAy9mKago6QxX+tfMzbCI6tXEhMuZuN1+CU8iDW+0UQ==}
|
resolution: {integrity: sha512-EtBDIZuDtVg75xIPIK1l5vCXNNCIRM0OBPUG+tbApDuJAy9mKago6QxX+tfMzbCI6tXEhMuZuN1+CU8iDW+0UQ==}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
'@rollup/rollup-linux-loongarch64-gnu@4.50.0':
|
'@rollup/rollup-linux-loongarch64-gnu@4.50.0':
|
||||||
resolution: {integrity: sha512-BGYSwJdMP0hT5CCmljuSNx7+k+0upweM2M4YGfFBjnFSZMHOLYR0gEEj/dxyYJ6Zc6AiSeaBY8dWOa11GF/ppQ==}
|
resolution: {integrity: sha512-BGYSwJdMP0hT5CCmljuSNx7+k+0upweM2M4YGfFBjnFSZMHOLYR0gEEj/dxyYJ6Zc6AiSeaBY8dWOa11GF/ppQ==}
|
||||||
cpu: [loong64]
|
cpu: [loong64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@rollup/rollup-linux-ppc64-gnu@4.50.0':
|
'@rollup/rollup-linux-ppc64-gnu@4.50.0':
|
||||||
resolution: {integrity: sha512-I1gSMzkVe1KzAxKAroCJL30hA4DqSi+wGc5gviD0y3IL/VkvcnAqwBf4RHXHyvH66YVHxpKO8ojrgc4SrWAnLg==}
|
resolution: {integrity: sha512-I1gSMzkVe1KzAxKAroCJL30hA4DqSi+wGc5gviD0y3IL/VkvcnAqwBf4RHXHyvH66YVHxpKO8ojrgc4SrWAnLg==}
|
||||||
cpu: [ppc64]
|
cpu: [ppc64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@rollup/rollup-linux-riscv64-gnu@4.50.0':
|
'@rollup/rollup-linux-riscv64-gnu@4.50.0':
|
||||||
resolution: {integrity: sha512-bSbWlY3jZo7molh4tc5dKfeSxkqnf48UsLqYbUhnkdnfgZjgufLS/NTA8PcP/dnvct5CCdNkABJ56CbclMRYCA==}
|
resolution: {integrity: sha512-bSbWlY3jZo7molh4tc5dKfeSxkqnf48UsLqYbUhnkdnfgZjgufLS/NTA8PcP/dnvct5CCdNkABJ56CbclMRYCA==}
|
||||||
cpu: [riscv64]
|
cpu: [riscv64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@rollup/rollup-linux-riscv64-musl@4.50.0':
|
'@rollup/rollup-linux-riscv64-musl@4.50.0':
|
||||||
resolution: {integrity: sha512-LSXSGumSURzEQLT2e4sFqFOv3LWZsEF8FK7AAv9zHZNDdMnUPYH3t8ZlaeYYZyTXnsob3htwTKeWtBIkPV27iQ==}
|
resolution: {integrity: sha512-LSXSGumSURzEQLT2e4sFqFOv3LWZsEF8FK7AAv9zHZNDdMnUPYH3t8ZlaeYYZyTXnsob3htwTKeWtBIkPV27iQ==}
|
||||||
cpu: [riscv64]
|
cpu: [riscv64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
'@rollup/rollup-linux-s390x-gnu@4.50.0':
|
'@rollup/rollup-linux-s390x-gnu@4.50.0':
|
||||||
resolution: {integrity: sha512-CxRKyakfDrsLXiCyucVfVWVoaPA4oFSpPpDwlMcDFQvrv3XY6KEzMtMZrA+e/goC8xxp2WSOxHQubP8fPmmjOQ==}
|
resolution: {integrity: sha512-CxRKyakfDrsLXiCyucVfVWVoaPA4oFSpPpDwlMcDFQvrv3XY6KEzMtMZrA+e/goC8xxp2WSOxHQubP8fPmmjOQ==}
|
||||||
cpu: [s390x]
|
cpu: [s390x]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@rollup/rollup-linux-x64-gnu@4.50.0':
|
'@rollup/rollup-linux-x64-gnu@4.50.0':
|
||||||
resolution: {integrity: sha512-8PrJJA7/VU8ToHVEPu14FzuSAqVKyo5gg/J8xUerMbyNkWkO9j2ExBho/68RnJsMGNJq4zH114iAttgm7BZVkA==}
|
resolution: {integrity: sha512-8PrJJA7/VU8ToHVEPu14FzuSAqVKyo5gg/J8xUerMbyNkWkO9j2ExBho/68RnJsMGNJq4zH114iAttgm7BZVkA==}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@rollup/rollup-linux-x64-musl@4.50.0':
|
'@rollup/rollup-linux-x64-musl@4.50.0':
|
||||||
resolution: {integrity: sha512-SkE6YQp+CzpyOrbw7Oc4MgXFvTw2UIBElvAvLCo230pyxOLmYwRPwZ/L5lBe/VW/qT1ZgND9wJfOsdy0XptRvw==}
|
resolution: {integrity: sha512-SkE6YQp+CzpyOrbw7Oc4MgXFvTw2UIBElvAvLCo230pyxOLmYwRPwZ/L5lBe/VW/qT1ZgND9wJfOsdy0XptRvw==}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
'@rollup/rollup-openharmony-arm64@4.50.0':
|
'@rollup/rollup-openharmony-arm64@4.50.0':
|
||||||
resolution: {integrity: sha512-PZkNLPfvXeIOgJWA804zjSFH7fARBBCpCXxgkGDRjjAhRLOR8o0IGS01ykh5GYfod4c2yiiREuDM8iZ+pVsT+Q==}
|
resolution: {integrity: sha512-PZkNLPfvXeIOgJWA804zjSFH7fARBBCpCXxgkGDRjjAhRLOR8o0IGS01ykh5GYfod4c2yiiREuDM8iZ+pVsT+Q==}
|
||||||
@@ -6807,20 +6902,11 @@ packages:
|
|||||||
cropperjs@1.6.2:
|
cropperjs@1.6.2:
|
||||||
resolution: {integrity: sha512-nhymn9GdnV3CqiEHJVai54TULFAE3VshJTXSqSJKa8yXAKyBKDWdhHarnlIPrshJ0WMFTGuFvG02YjLXfPiuOA==}
|
resolution: {integrity: sha512-nhymn9GdnV3CqiEHJVai54TULFAE3VshJTXSqSJKa8yXAKyBKDWdhHarnlIPrshJ0WMFTGuFvG02YjLXfPiuOA==}
|
||||||
|
|
||||||
cross-env@5.2.1:
|
|
||||||
resolution: {integrity: sha512-1yHhtcfAd1r4nwQgknowuUNfIT9E8dOMMspC36g45dN+iD1blloi7xp8X/xAIDnjHWyt1uQ8PHk2fkNaym7soQ==}
|
|
||||||
engines: {node: '>=4.0'}
|
|
||||||
hasBin: true
|
|
||||||
|
|
||||||
cross-env@7.0.3:
|
cross-env@7.0.3:
|
||||||
resolution: {integrity: sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==}
|
resolution: {integrity: sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==}
|
||||||
engines: {node: '>=10.14', npm: '>=6', yarn: '>=1'}
|
engines: {node: '>=10.14', npm: '>=6', yarn: '>=1'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
cross-spawn@6.0.6:
|
|
||||||
resolution: {integrity: sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==}
|
|
||||||
engines: {node: '>=4.8'}
|
|
||||||
|
|
||||||
cross-spawn@7.0.6:
|
cross-spawn@7.0.6:
|
||||||
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
|
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
|
||||||
engines: {node: '>= 8'}
|
engines: {node: '>= 8'}
|
||||||
@@ -7600,6 +7686,10 @@ packages:
|
|||||||
deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options.
|
deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options.
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
esmock@2.7.5:
|
||||||
|
resolution: {integrity: sha512-jKwL7yYpVOERalCllSnPur59s9M0gV5BKijtmOKclqDMuhqdS7DT/a7cODjz6w1XusE0wAaHBTrK+zgab/ENgw==}
|
||||||
|
engines: {node: '>=14.16.0'}
|
||||||
|
|
||||||
esniff@2.0.1:
|
esniff@2.0.1:
|
||||||
resolution: {integrity: sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==}
|
resolution: {integrity: sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==}
|
||||||
engines: {node: '>=0.10'}
|
engines: {node: '>=0.10'}
|
||||||
@@ -9822,9 +9912,6 @@ packages:
|
|||||||
next-tick@1.1.0:
|
next-tick@1.1.0:
|
||||||
resolution: {integrity: sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==}
|
resolution: {integrity: sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==}
|
||||||
|
|
||||||
nice-try@1.0.5:
|
|
||||||
resolution: {integrity: sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==}
|
|
||||||
|
|
||||||
no-case@3.0.4:
|
no-case@3.0.4:
|
||||||
resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==}
|
resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==}
|
||||||
|
|
||||||
@@ -10234,10 +10321,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
|
resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
path-key@2.0.1:
|
|
||||||
resolution: {integrity: sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==}
|
|
||||||
engines: {node: '>=4'}
|
|
||||||
|
|
||||||
path-key@3.1.1:
|
path-key@3.1.1:
|
||||||
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
|
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
@@ -11475,18 +11558,10 @@ packages:
|
|||||||
shallow-equal@1.2.1:
|
shallow-equal@1.2.1:
|
||||||
resolution: {integrity: sha512-S4vJDjHHMBaiZuT9NPb616CSmLf618jawtv3sufLl6ivK8WocjAo58cXwbRV1cgqxH0Qbv+iUt6m05eqEa2IRA==}
|
resolution: {integrity: sha512-S4vJDjHHMBaiZuT9NPb616CSmLf618jawtv3sufLl6ivK8WocjAo58cXwbRV1cgqxH0Qbv+iUt6m05eqEa2IRA==}
|
||||||
|
|
||||||
shebang-command@1.2.0:
|
|
||||||
resolution: {integrity: sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==}
|
|
||||||
engines: {node: '>=0.10.0'}
|
|
||||||
|
|
||||||
shebang-command@2.0.0:
|
shebang-command@2.0.0:
|
||||||
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
|
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
shebang-regex@1.0.0:
|
|
||||||
resolution: {integrity: sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==}
|
|
||||||
engines: {node: '>=0.10.0'}
|
|
||||||
|
|
||||||
shebang-regex@3.0.0:
|
shebang-regex@3.0.0:
|
||||||
resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
|
resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
@@ -20418,22 +20493,10 @@ snapshots:
|
|||||||
|
|
||||||
cropperjs@1.6.2: {}
|
cropperjs@1.6.2: {}
|
||||||
|
|
||||||
cross-env@5.2.1:
|
|
||||||
dependencies:
|
|
||||||
cross-spawn: 6.0.6
|
|
||||||
|
|
||||||
cross-env@7.0.3:
|
cross-env@7.0.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
cross-spawn: 7.0.6
|
cross-spawn: 7.0.6
|
||||||
|
|
||||||
cross-spawn@6.0.6:
|
|
||||||
dependencies:
|
|
||||||
nice-try: 1.0.5
|
|
||||||
path-key: 2.0.1
|
|
||||||
semver: 5.7.2
|
|
||||||
shebang-command: 1.2.0
|
|
||||||
which: 1.3.1
|
|
||||||
|
|
||||||
cross-spawn@7.0.6:
|
cross-spawn@7.0.6:
|
||||||
dependencies:
|
dependencies:
|
||||||
path-key: 3.1.1
|
path-key: 3.1.1
|
||||||
@@ -21439,6 +21502,8 @@ snapshots:
|
|||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
|
esmock@2.7.5: {}
|
||||||
|
|
||||||
esniff@2.0.1:
|
esniff@2.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
d: 1.0.2
|
d: 1.0.2
|
||||||
@@ -23862,8 +23927,6 @@ snapshots:
|
|||||||
|
|
||||||
next-tick@1.1.0: {}
|
next-tick@1.1.0: {}
|
||||||
|
|
||||||
nice-try@1.0.5: {}
|
|
||||||
|
|
||||||
no-case@3.0.4:
|
no-case@3.0.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
lower-case: 2.0.2
|
lower-case: 2.0.2
|
||||||
@@ -24331,8 +24394,6 @@ snapshots:
|
|||||||
|
|
||||||
path-is-absolute@1.0.1: {}
|
path-is-absolute@1.0.1: {}
|
||||||
|
|
||||||
path-key@2.0.1: {}
|
|
||||||
|
|
||||||
path-key@3.1.1: {}
|
path-key@3.1.1: {}
|
||||||
|
|
||||||
path-key@4.0.0: {}
|
path-key@4.0.0: {}
|
||||||
@@ -25682,16 +25743,10 @@ snapshots:
|
|||||||
|
|
||||||
shallow-equal@1.2.1: {}
|
shallow-equal@1.2.1: {}
|
||||||
|
|
||||||
shebang-command@1.2.0:
|
|
||||||
dependencies:
|
|
||||||
shebang-regex: 1.0.0
|
|
||||||
|
|
||||||
shebang-command@2.0.0:
|
shebang-command@2.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
shebang-regex: 3.0.0
|
shebang-regex: 3.0.0
|
||||||
|
|
||||||
shebang-regex@1.0.0: {}
|
|
||||||
|
|
||||||
shebang-regex@3.0.0: {}
|
shebang-regex@3.0.0: {}
|
||||||
|
|
||||||
shiki@3.4.1:
|
shiki@3.4.1:
|
||||||
|
|||||||
Reference in New Issue
Block a user