diff --git a/packages/core/pipeline/package.json b/packages/core/pipeline/package.json index efd5351e..1c76b83b 100644 --- a/packages/core/pipeline/package.json +++ b/packages/core/pipeline/package.json @@ -3,8 +3,13 @@ "private": true, "version": "0.3.0", "main": "./src/index.ts", - "module": "./dist/pipeline.mjs", - "types": "./dist/es/index.d.ts", + "module": "./src/index.ts", + "types": "./src/index.ts", + "publishConfig": { + "main": "./dist/pipeline.umd.js", + "module": "./dist/pipeline.mjs", + "types": "./dist/d/index.d.ts" + }, "scripts": { "dev": "vite", "build": "vue-tsc --noEmit && vite build", @@ -39,6 +44,7 @@ "@types/node-forge": "^1.3.0", "@typescript-eslint/eslint-plugin": "^5.38.1", "@typescript-eslint/parser": "^5.38.1", + "@rollup/plugin-typescript": "^11.0.0", "chai": "^4.3.6", "eslint": "^8.24.0", "eslint-config-prettier": "^8.5.0", diff --git a/packages/core/pipeline/src/core/executor.ts b/packages/core/pipeline/src/core/executor.ts index 95f41b06..a51eb2fa 100644 --- a/packages/core/pipeline/src/core/executor.ts +++ b/packages/core/pipeline/src/core/executor.ts @@ -39,6 +39,8 @@ export class Executor { await this.runWithHistory(this.pipeline, "pipeline", async () => { await this.runStages(); }); + } catch (e) { + this.logger.error("pipeline 执行失败", e); } finally { this.logger.info(`pipeline.${this.pipeline.id} end`); } @@ -54,12 +56,13 @@ export class Executor { if (runnable.strategy?.runStrategy === RunStrategy.SkipWhenSucceed) { //如果是成功后跳过策略 const lastResult = await this.pipelineContext.getObj(contextKey); - const lastInput = await this.pipelineContext.getObj(inputKey); + const lastInput = await this.pipelineContext.get(inputKey); let inputChanged = false; //TODO 参数不变 if (runnableType === "step") { const step = runnable as Step; const input = JSON.stringify(step.input); + await this.pipelineContext.set(inputKey, input); if (input != null && lastInput !== input) { inputChanged = true; } diff --git a/packages/core/pipeline/tsconfig.json b/packages/core/pipeline/tsconfig.json index 528911f6..a3c9536c 100644 --- a/packages/core/pipeline/tsconfig.json +++ b/packages/core/pipeline/tsconfig.json @@ -13,7 +13,8 @@ "lib": ["ESNext", "DOM"], "skipLibCheck": true, "experimentalDecorators": true, - "emitDecoratorMetadata": true + "emitDecoratorMetadata": true, + "outDir": "./dist/ts" }, "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue","test/**/*.ts"], } diff --git a/packages/core/pipeline/vite.config.ts b/packages/core/pipeline/vite.config.js similarity index 60% rename from packages/core/pipeline/vite.config.ts rename to packages/core/pipeline/vite.config.js index a3f2fd3c..6b9492ac 100644 --- a/packages/core/pipeline/vite.config.ts +++ b/packages/core/pipeline/vite.config.js @@ -1,4 +1,5 @@ import { defineConfig } from "vite"; +import typescript from "@rollup/plugin-typescript"; // https://vitejs.dev/config/ export default defineConfig({ plugins: [], @@ -8,13 +9,23 @@ export default defineConfig({ name: "pipeline", }, rollupOptions: { + plugins: [ + typescript({ + target: "esnext", + rootDir: "src", + declaration: true, + declarationDir: "dist/d", + exclude: ["./node_modules/**", "./src/**/*.vue"], + allowSyntheticDefaultImports: true, + }), + ], external: ["vue", "lodash", "dayjs", "@fast-crud/fast-crud"], output: { // Provide global variables to use in the UMD build // for externalized deps globals: { vue: "Vue", - "lodash": "_", + lodash: "_", dayjs: "dayjs", "@fast-crud/fast-crud": "FastCrud", }, diff --git a/packages/plugins/plugin-cert/src/dns-provider/decorator.ts b/packages/plugins/plugin-cert/src/dns-provider/decorator.ts index 7a560683..0d62c392 100644 --- a/packages/plugins/plugin-cert/src/dns-provider/decorator.ts +++ b/packages/plugins/plugin-cert/src/dns-provider/decorator.ts @@ -1,4 +1,3 @@ -// src/decorator/memoryCache.decorator.ts import { dnsProviderRegistry } from "./registry"; import { DnsProviderDefine } from "./api"; import { Decorator, AUTOWIRE_KEY } from "@certd/pipeline"; diff --git a/packages/plugins/plugin-cert/src/dns-provider/registry.ts b/packages/plugins/plugin-cert/src/dns-provider/registry.ts index fe0c64d6..d4df2745 100644 --- a/packages/plugins/plugin-cert/src/dns-provider/registry.ts +++ b/packages/plugins/plugin-cert/src/dns-provider/registry.ts @@ -1,4 +1,3 @@ import { Registry } from "@certd/pipeline"; -// @ts-ignore export const dnsProviderRegistry = new Registry(); diff --git a/packages/plugins/plugin-cert/src/plugin/cert-plugin/acme.ts b/packages/plugins/plugin-cert/src/plugin/cert-plugin/acme.ts index ed745aa5..1f11ff55 100644 --- a/packages/plugins/plugin-cert/src/plugin/cert-plugin/acme.ts +++ b/packages/plugins/plugin-cert/src/plugin/cert-plugin/acme.ts @@ -5,7 +5,11 @@ import { Challenge } from "@certd/acme-client/types/rfc8555"; import { Logger } from "log4js"; import { IContext } from "@certd/pipeline/src/core/context"; import { IDnsProvider } from "../../dns-provider"; - +export type CertInfo = { + crt: string; + key: string; + csr: string; +}; export class AcmeService { userContext: IContext; logger: Logger; @@ -166,7 +170,7 @@ export class AcmeService { }, }); - const cert = { + const cert: CertInfo = { crt: crt.toString(), key: key.toString(), csr: csr.toString(), diff --git a/packages/plugins/plugin-cert/src/plugin/cert-plugin/cert-reader.ts b/packages/plugins/plugin-cert/src/plugin/cert-plugin/cert-reader.ts new file mode 100644 index 00000000..373cd9ac --- /dev/null +++ b/packages/plugins/plugin-cert/src/plugin/cert-plugin/cert-reader.ts @@ -0,0 +1,52 @@ +import { CertInfo } from "./acme"; +import fs from "fs"; +import os from "os"; +import forge from "node-forge"; +import path from "path"; +export class CertReader implements CertInfo { + crt: string; + key: string; + csr: string; + + detail: any; + expires: number; + constructor(certInfo: CertInfo) { + this.crt = certInfo.crt; + this.key = certInfo.key; + this.csr = certInfo.csr; + + const { detail, expires } = this.getCrtDetail(this.crt); + this.detail = detail; + this.expires = expires.getTime(); + } + + toCertInfo(): CertInfo { + return { + crt: this.crt, + key: this.key, + csr: this.csr, + }; + } + + getCrtDetail(crt: string) { + const pki = forge.pki; + const detail = pki.certificateFromPem(crt.toString()); + const expires = detail.validity.notAfter; + return { detail, expires }; + } + + saveToFile(type: "crt" | "key", filepath?: string) { + if (filepath == null) { + //写入临时目录 + filepath = path.join(os.tmpdir(), "/certd/tmp/", Math.floor(Math.random() * 1000000) + "", `cert.${type}`); + } + + const dir = path.dirname(filepath); + if (!fs.existsSync(dir)) { + fs.mkdirSync(dir, { recursive: true }); + } + + fs.writeFileSync(filepath, this[type]); + return filepath; + } +} diff --git a/packages/plugins/plugin-cert/src/plugin/cert-plugin/index.ts b/packages/plugins/plugin-cert/src/plugin/cert-plugin/index.ts index 39c7a336..0f55349f 100644 --- a/packages/plugins/plugin-cert/src/plugin/cert-plugin/index.ts +++ b/packages/plugins/plugin-cert/src/plugin/cert-plugin/index.ts @@ -1,46 +1,15 @@ import { Autowire, HttpClient, IAccessService, IContext, IsTaskPlugin, ITaskPlugin, RunStrategy, TaskInput, TaskOutput } from "@certd/pipeline"; -import forge from "node-forge"; import dayjs from "dayjs"; -import { AcmeService } from "./acme"; +import { AcmeService, CertInfo } from "./acme"; import _ from "lodash"; import { Logger } from "log4js"; import { Decorator } from "@certd/pipeline/src/decorator"; import { DnsProviderDefine, dnsProviderRegistry } from "../../dns-provider"; -import fs from "fs"; -import os from "os"; -export class CertInfo { - crt: string; - key: string; - csr: string; +import { CertReader } from "./cert-reader"; - detail: any; - expires: number; - constructor(opts: { crt: string; key: string; csr: string }) { - this.crt = opts.crt; - this.key = opts.key; - this.csr = opts.csr; +export { CertReader }; +export type { CertInfo }; - const { detail, expires } = this.getCrtDetail(this.crt); - this.detail = detail; - this.expires = expires.getTime(); - } - - getCrtDetail(crt: string) { - const pki = forge.pki; - const detail = pki.certificateFromPem(crt.toString()); - const expires = detail.validity.notAfter; - return { detail, expires }; - } - - saveToFile(type: "crt" | "key", path?: string) { - if (path == null) { - //写入临时目录 - path = `${os.tmpdir()}/certd/tmp/${Math.floor(Math.random() * 1000000)}/cert.${type}`; - } - fs.writeFileSync(path, this[type]); - return path; - } -} @IsTaskPlugin({ name: "CertApply", title: "证书申请", @@ -166,10 +135,14 @@ export class CertApplyPlugin implements ITaskPlugin { return this.output(oldCert); } const cert = await this.doCertApply(); - return this.output(cert); + if (cert != null) { + this.output(cert.toCertInfo()); + } else { + throw new Error("申请证书失败"); + } } - output(cert: any) { + output(cert: CertInfo) { this.cert = cert; } @@ -187,12 +160,12 @@ export class CertApplyPlugin implements ITaskPlugin { const oldInputStr = await this.pipelineContext.getObj(inputCacheKey); await this.pipelineContext.setObj(inputCacheKey, this.domains); const oldInput = JSON.stringify(oldInputStr); - const thisInput = JSON.stringify(this.cert); + const thisInput = JSON.stringify(this.domains); if (oldInput !== thisInput) { inputChanged = true; } - let oldCert; + let oldCert: CertReader | undefined = undefined; try { oldCert = await this.readCurrentCert(); } catch (e) { @@ -257,10 +230,7 @@ export class CertApplyPlugin implements ITaskPlugin { await this.writeCert(cert); const ret = await this.readCurrentCert(); - return { - ...ret, - isNew: true, - }; + return ret; } formatCert(pem: string) { @@ -271,7 +241,7 @@ export class CertApplyPlugin implements ITaskPlugin { } async writeCert(cert: { crt: string; key: string; csr: string }) { - const newCert = { + const newCert: CertInfo = { crt: this.formatCert(cert.crt), key: this.formatCert(cert.key), csr: this.formatCert(cert.csr), @@ -282,12 +252,12 @@ export class CertApplyPlugin implements ITaskPlugin { await this.pipelineContext.set("cert.csr", newCert.csr); } - async readCurrentCert() { - const cert: any = await this.pipelineContext.getObj("cert"); + async readCurrentCert(): Promise { + const cert: CertInfo = await this.pipelineContext.getObj("cert"); if (cert == null) { return undefined; } - return new CertInfo(cert); + return new CertReader(cert); } /** diff --git a/packages/plugins/plugin-cert/src/plugin/index.ts b/packages/plugins/plugin-cert/src/plugin/index.ts index 5cc2a15b..06c4122d 100644 --- a/packages/plugins/plugin-cert/src/plugin/index.ts +++ b/packages/plugins/plugin-cert/src/plugin/index.ts @@ -1 +1,2 @@ export * from "./cert-plugin"; + diff --git a/packages/plugins/plugin-cert/tsconfig.json b/packages/plugins/plugin-cert/tsconfig.json index 62621e72..cce0228e 100644 --- a/packages/plugins/plugin-cert/tsconfig.json +++ b/packages/plugins/plugin-cert/tsconfig.json @@ -1,5 +1,6 @@ { "compilerOptions": { + "noImplicitAny": true, "target": "ESNext", "useDefineForClassFields": true, "module": "commonjs", diff --git a/packages/plugins/plugin-host/src/access/ssh-access.ts b/packages/plugins/plugin-host/src/access/ssh-access.ts index 8d8ee07a..1ddcfb74 100644 --- a/packages/plugins/plugin-host/src/access/ssh-access.ts +++ b/packages/plugins/plugin-host/src/access/ssh-access.ts @@ -42,6 +42,10 @@ export class SshAccess implements IAccess { @AccessInput({ title: "密钥", helper: "密钥或密码必填一项", + component: { + name: "a-textarea", + vModel: "value", + }, }) privateKey!: string; } diff --git a/packages/plugins/plugin-host/src/plugin/host-shell-execute/index.ts b/packages/plugins/plugin-host/src/plugin/host-shell-execute/index.ts index 5794e51d..64f60803 100644 --- a/packages/plugins/plugin-host/src/plugin/host-shell-execute/index.ts +++ b/packages/plugins/plugin-host/src/plugin/host-shell-execute/index.ts @@ -1,6 +1,5 @@ -import { Autowire, IAccessService, IsTaskPlugin, ILogger, RunStrategy, TaskInput, ITaskPlugin } from "@certd/pipeline"; +import { Autowire, IAccessService, ILogger, IsTaskPlugin, ITaskPlugin, RunStrategy, TaskInput } from "@certd/pipeline"; import { SshClient } from "../../lib/ssh"; -import { CertInfo } from "@certd/plugin-cert"; @IsTaskPlugin({ name: "hostShellExecute", @@ -24,15 +23,6 @@ export class HostShellExecutePlugin implements ITaskPlugin { required: true, }) accessId!: string; - @TaskInput({ - title: "域名证书", - helper: "请选择前置任务输出的域名证书", - component: { - name: "pi-output-selector", - }, - required: true, - }) - cert!: CertInfo; @TaskInput({ title: "shell脚本命令", component: { @@ -51,7 +41,7 @@ export class HostShellExecutePlugin implements ITaskPlugin { async onInstance() {} async execute(): Promise { const { script, accessId } = this; - const connectConf = this.accessService.getById(accessId); + const connectConf = await this.accessService.getById(accessId); const sshClient = new SshClient(this.logger); const ret = await sshClient.exec({ connectConf, diff --git a/packages/plugins/plugin-host/src/plugin/upload-to-host/index.ts b/packages/plugins/plugin-host/src/plugin/upload-to-host/index.ts index 32d9309d..5ef0ce30 100644 --- a/packages/plugins/plugin-host/src/plugin/upload-to-host/index.ts +++ b/packages/plugins/plugin-host/src/plugin/upload-to-host/index.ts @@ -1,6 +1,6 @@ import { Autowire, IAccessService, IsTaskPlugin, ITaskPlugin, ILogger, RunStrategy, TaskInput, TaskOutput } from "@certd/pipeline"; import { SshClient } from "../../lib/ssh"; -import { CertInfo } from "@certd/plugin-cert"; +import { CertInfo, CertReader } from "@certd/plugin-cert"; import * as fs from "fs"; @IsTaskPlugin({ @@ -67,11 +67,12 @@ export class UploadCertToHostPlugin implements ITaskPlugin { async onInstance() {} async execute(): Promise { const { crtPath, keyPath, cert, accessId, sudo } = this; - const connectConf = this.accessService.getById(accessId); + const certReader = new CertReader(cert); + const connectConf = await this.accessService.getById(accessId); const sshClient = new SshClient(this.logger); - const saveCrtPath = cert.saveToFile("crt"); - const saveKeyPath = cert.saveToFile("key"); + const saveCrtPath = certReader.saveToFile("crt"); + const saveKeyPath = certReader.saveToFile("key"); await sshClient.uploadFiles({ connectConf, diff --git a/packages/plugins/plugin-host/tsconfig.json b/packages/plugins/plugin-host/tsconfig.json index 62621e72..cce0228e 100644 --- a/packages/plugins/plugin-host/tsconfig.json +++ b/packages/plugins/plugin-host/tsconfig.json @@ -1,5 +1,6 @@ { "compilerOptions": { + "noImplicitAny": true, "target": "ESNext", "useDefineForClassFields": true, "module": "commonjs", diff --git a/packages/plugins/plugin-huawei/src/dns-provider/huawei-dns-provider.ts b/packages/plugins/plugin-huawei/src/dns-provider/huawei-dns-provider.ts index d343b6e6..dac90b4f 100644 --- a/packages/plugins/plugin-huawei/src/dns-provider/huawei-dns-provider.ts +++ b/packages/plugins/plugin-huawei/src/dns-provider/huawei-dns-provider.ts @@ -73,7 +73,7 @@ export class HuaweiDnsProvider implements IDnsProvider { if (records && records.length > 0) { for (const record of records) { await this.removeRecord({ - record: records[0], + record, ...options, }); } diff --git a/packages/plugins/plugin-huawei/src/lib/client.ts b/packages/plugins/plugin-huawei/src/lib/client.ts index ba40b13b..94ef3433 100644 --- a/packages/plugins/plugin-huawei/src/lib/client.ts +++ b/packages/plugins/plugin-huawei/src/lib/client.ts @@ -1,6 +1,5 @@ // @ts-ignore import signer from "./signer"; -import https from "https"; import { HuaweiAccess } from "../access"; import { axios } from "@certd/acme-client"; import { logger } from "@certd/pipeline"; diff --git a/packages/plugins/plugin-huawei/tsconfig.json b/packages/plugins/plugin-huawei/tsconfig.json index 62621e72..cce0228e 100644 --- a/packages/plugins/plugin-huawei/tsconfig.json +++ b/packages/plugins/plugin-huawei/tsconfig.json @@ -1,5 +1,6 @@ { "compilerOptions": { + "noImplicitAny": true, "target": "ESNext", "useDefineForClassFields": true, "module": "commonjs", diff --git a/packages/ui/certd-client/package.json b/packages/ui/certd-client/package.json index f851347f..3085b9eb 100644 --- a/packages/ui/certd-client/package.json +++ b/packages/ui/certd-client/package.json @@ -20,11 +20,14 @@ "author": "Greper", "license": "MIT", "dependencies": { + "@certd/acme-client": "workspace:^0.3.0", + "@certd/pipeline": "workspace:^0.3.0", "@ant-design/colors": "^6.0.0", "@ant-design/icons-vue": "^6.0.1", - "@fast-crud/fast-crud": "^1.9.2", - "@fast-crud/fast-extends": "^1.9.2", - "@fast-crud/ui-antdv": "^1.9.2", + "@fast-crud/fast-crud": "^1.13.8", + "@fast-crud/fast-extends": "^1.13.8", + "@fast-crud/ui-antdv": "^1.13.8", + "@fast-crud/ui-interface": "^1.13.8", "@iconify/iconify": "^3.0.1", "@iconify/json": "^2.1.151", "@purge-icons/generated": "^0.9.0", diff --git a/packages/ui/certd-client/src/views/certd/access/access-selector/access/crud.jsx b/packages/ui/certd-client/src/views/certd/access/access-selector/access/crud.tsx similarity index 70% rename from packages/ui/certd-client/src/views/certd/access/access-selector/access/crud.jsx rename to packages/ui/certd-client/src/views/certd/access/access-selector/access/crud.tsx index c780d644..e454bf3c 100644 --- a/packages/ui/certd-client/src/views/certd/access/access-selector/access/crud.jsx +++ b/packages/ui/certd-client/src/views/certd/access/access-selector/access/crud.tsx @@ -1,25 +1,31 @@ +// @ts-ignore import * as api from "/@/views/certd/access/api"; import { ref } from "vue"; import { getCommonColumnDefine } from "/@/views/certd/access/common"; +import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud"; -export default function ({ expose, props, ctx }) { - const { crudBinding } = expose; +export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet { + const { crudBinding } = crudExpose; + const { props, ctx } = context; const lastResRef = ref(); - const pageRequest = async (query) => { + const pageRequest = async (query: UserPageQuery): Promise => { return await api.GetList(query); }; - const editRequest = async ({ form, row }) => { + const editRequest = async (req: EditReq) => { + const { form, row } = req; form.id = row.id; form.type = props.type; const res = await api.UpdateObj(form); lastResRef.value = res; return res; }; - const delRequest = async ({ row }) => { + const delRequest = async (req: DelReq) => { + const { row } = req; return await api.DelObj(row.id); }; - const addRequest = async ({ form }) => { + const addRequest = async (req: AddReq) => { + const { form } = req; form.type = props.type; const res = await api.AddObj(form); lastResRef.value = res; @@ -27,24 +33,15 @@ export default function ({ expose, props, ctx }) { }; const selectedRowKey = ref([props.modelValue]); - // watch( - // () => { - // return props.modelValue; - // }, - // (value) => { - // selectedRowKey.value = [value]; - // }, - // { - // immediate: true - // } - // ); - const onSelectChange = (changed) => { + + const onSelectChange = (changed: any) => { selectedRowKey.value = changed; ctx.emit("update:modelValue", changed[0]); }; const typeRef = ref("aliyun"); - const commonColumnsDefine = getCommonColumnDefine(crudBinding, typeRef); + context.typeRef = typeRef; + const commonColumnsDefine = getCommonColumnDefine(crudExpose, typeRef); commonColumnsDefine.type.form.component.disabled = true; return { typeRef, @@ -75,7 +72,7 @@ export default function ({ expose, props, ctx }) { selectedRowKeys: selectedRowKey, onChange: onSelectChange }, - customRow: (record) => { + customRow: (record: any) => { return { onClick: () => { onSelectChange([record.id]); diff --git a/packages/ui/certd-client/src/views/certd/access/access-selector/access/index.vue b/packages/ui/certd-client/src/views/certd/access/access-selector/access/index.vue index d4b60341..f7163106 100644 --- a/packages/ui/certd-client/src/views/certd/access/access-selector/access/index.vue +++ b/packages/ui/certd-client/src/views/certd/access/access-selector/access/index.vue @@ -4,9 +4,9 @@ -