diff --git a/docker/run/docker-compose.yaml b/docker/run/docker-compose.yaml index 69812e4d..6aa1b865 100644 --- a/docker/run/docker-compose.yaml +++ b/docker/run/docker-compose.yaml @@ -1,34 +1,37 @@ version: '3.3' services: certd: - # 镜像 # ↓↓↓↓↓ --- 1、 镜像版本号,建议改成固定版本号【可选】 + # 镜像 # ↓↓↓↓↓ --- 镜像版本号,建议改成固定版本号【可选】 image: registry.cn-shenzhen.aliyuncs.com/handsfree/certd:latest container_name: certd # 容器名 restart: unless-stopped # 自动重启 volumes: - # ↓↓↓↓↓ ------------------------------------------------------- 2、 数据库以及证书存储路径,默认存在宿主机的/data/certd/目录下【可选】 + # ↓↓↓↓↓ -------------------------------------------------------- 数据库以及证书存储路径,默认存在宿主机的/data/certd/目录下【可选】 - /data/certd:/app/data ports: # 端口映射 - # ↓↓↓↓ ----------------------------------------------------------3、如果端口有冲突,可以修改第一个7001为其他不冲突的端口号【可选】 + # ↓↓↓↓ ---------------------------------------------------------- 如果端口有冲突,可以修改第一个7001为其他不冲突的端口号【可选】 - "7001:7001" dns: # 如果出现getaddrinfo ENOTFOUND等错误,可以尝试修改或注释dns配置 - 223.5.5.5 - 223.6.6.6 - # ↓↓↓↓ ----------------------------------------------------------如果你服务器部署在国外,可以用8.8.8.8替换上面的dns【可选】 + # ↓↓↓↓ ---------------------------------------------------------- 如果你服务器部署在国外,可以用8.8.8.8替换上面的dns【可选】 # - 8.8.8.8 # - 8.8.4.4 environment: # 环境变量 - TZ=Asia/Shanghai + #- HTTPS_PROXY=http://xxxxxx:xx + #- HTTP_PROXY=http://xxxxxx:xx + # ↑↑↑↑↑ ------------------------------------- 这里可以设置http代理【可选】 - certd_system_resetAdminPasswd=false - # ↑↑↑↑↑---------------------------4、如果忘记管理员密码,可以设置为true,重启之后,管理员密码将改成123456,然后请及时修改回false【可选】 + # ↑↑↑↑↑--------------------------- 如果忘记管理员密码,可以设置为true,重启之后,管理员密码将改成123456,然后请及时修改回false【可选】 - certd_cron_immediateTriggerOnce=false - # ↑↑↑↑↑---------------------------5、如果设置为true,启动后所有配置了cron的流水线任务都将被立即触发一次【可选】 + # ↑↑↑↑↑--------------------------- 如果设置为true,启动后所有配置了cron的流水线任务都将被立即触发一次【可选】 - VITE_APP_ICP_NO= - # ↑↑↑↑↑ -----------------------------------------6、这里可以设置备案号【可选】 + # ↑↑↑↑↑ ----------------------------------------- 这里可以设置备案号【可选】 #- certd_koa_key=./data/ssl/cert.key #- certd_koa_cert=./data/ssl/cert.crt - # ↑↑↑↑↑ -----------------------------------------7、配置证书和key,则表示https方式启动,访问网址要使用 https://your.domain:7001【可选】 + # ↑↑↑↑↑ ----------------------------------------- 配置证书和key,则表示https方式启动,访问网址要使用 https://your.domain:7001【可选】 # 设置环境变量即可自定义certd配置 # 服务端配置项见: packages/ui/certd-server/src/config/config.default.ts diff --git a/init.sh b/init.sh new file mode 100644 index 00000000..3baacbc8 --- /dev/null +++ b/init.sh @@ -0,0 +1,20 @@ +current_pwd=$(pwd) + +echo "开始设置git配置" + +read -p "请输入username:" username +git config user.name $username + +read -p "请输入email:" email +git config user.email $email + +git config credential.helper "store --file=$current_pwd/.git/credential.store" +echo "已设置记住git账号密码" + +git config core.autocrlf input +echo "已设置auto crlf = input" + +git config core.filemode false +echo "已设置忽略文件模式变化" + +echo "git配置完成" diff --git a/package.json b/package.json index 8de896d0..81d7d0f0 100644 --- a/package.json +++ b/package.json @@ -24,9 +24,9 @@ "license": "AGPL-3.0", "dependencies": { "axios": "^1.7.2", - "lodash": "^4.17.21" + "lodash-es": "^4.17.21" }, "workspaces": [ "packages/**" ] -} +} \ No newline at end of file diff --git a/packages/core/acme-client/src/verify.js b/packages/core/acme-client/src/verify.js index 22c2b07d..1b30f4f7 100644 --- a/packages/core/acme-client/src/verify.js +++ b/packages/core/acme-client/src/verify.js @@ -111,7 +111,7 @@ async function verifyDnsChallenge(authz, challenge, keyAuthorization, prefix = ' log(`DNS query finished successfully, found ${recordValues.length} TXT records`); if (!recordValues.length || !recordValues.includes(keyAuthorization)) { - throw new Error(`Authorization not found in DNS TXT record: ${recordName}`); + throw new Error(`Authorization not found in DNS TXT record: ${recordName},need:${keyAuthorization},found:${recordValues}`); } log(`Key authorization match for ${challenge.type}/${recordName}, ACME challenge verified`); diff --git a/packages/core/pipeline/src/utils/util.sp.ts b/packages/core/pipeline/src/utils/util.sp.ts index 4a434a30..c7710e15 100644 --- a/packages/core/pipeline/src/utils/util.sp.ts +++ b/packages/core/pipeline/src/utils/util.sp.ts @@ -66,6 +66,8 @@ async function spawn(opts: SpawnOption): Promise { cmd = item; } } + }else{ + cmd = opts.cmd } log.info(`执行命令: ${cmd}`); let stdout = ""; diff --git a/packages/plugins/plugin-cert/src/plugin/cert-convert/index.ts b/packages/plugins/plugin-cert/src/plugin/cert-convert/index.ts index 5b848b2a..f48ff3a6 100644 --- a/packages/plugins/plugin-cert/src/plugin/cert-convert/index.ts +++ b/packages/plugins/plugin-cert/src/plugin/cert-convert/index.ts @@ -42,10 +42,35 @@ export class CertConvertPlugin extends AbstractTaskPlugin { name: "a-input-password", vModel: "value", }, - required: true, + required: false, }) pfxPassword!: string; + @TaskInput({ + title: "输出PFX", + value:true, + component: { + name: "a-switch", + vModel: "checked", + }, + required: true, + }) + pfxEnabled: boolean = true; + + + @TaskInput({ + title: "输出DER", + value:true, + component: { + name: "a-switch", + vModel: "checked", + }, + required: true, + }) + derEnabled: boolean = true; + + + @TaskOutput({ title: "pfx格式证书", type: "PfxCert", @@ -64,11 +89,19 @@ export class CertConvertPlugin extends AbstractTaskPlugin { const certReader = new CertReader(this.cert); const handle = async (opts: CertReaderHandleContext) => { - // 调用openssl 转pfx - await this.convertPfx(opts); - - // 转der - await this.convertDer(opts); + if(this.pfxEnabled){ + // 调用openssl 转pfx + await this.convertPfx(opts); + }else{ + this.logger.info("pfx证书已禁用"); + } + + if(this.pfxEnabled){ + // 转der + await this.convertDer(opts); + }else{ + this.logger.info("der证书已禁用"); + } }; await certReader.readCertFile({ logger: this.logger, handle }); @@ -86,13 +119,18 @@ export class CertConvertPlugin extends AbstractTaskPlugin { const pfxPath = path.join(os.tmpdir(), "/certd/tmp/", Math.floor(Math.random() * 1000000) + "", "cert.pfx"); + const dir = path.dirname(pfxPath) + if (!fs.existsSync(dir)) { + fs.mkdirSync(dir, { recursive: true }); + } + let passwordArg = "-passout pass:"; if (this.pfxPassword) { passwordArg = `-password pass:${this.pfxPassword}`; } await this.exec(`openssl pkcs12 -export -out ${pfxPath} -inkey ${tmpKeyPath} -in ${tmpCrtPath} ${passwordArg}`); this.pfxCert = pfxPath; - + const applyTime = new Date().getTime(); const filename = reader.buildCertFileName("pfx", applyTime); const fileBuffer = fs.readFileSync(pfxPath); @@ -102,6 +140,13 @@ export class CertConvertPlugin extends AbstractTaskPlugin { private async convertDer(opts: CertReaderHandleContext) { const { reader, tmpCrtPath } = opts; const derPath = path.join(os.tmpdir(), "/certd/tmp/", Math.floor(Math.random() * 1000000) + "", `cert.der`); + + const dir = path.dirname(derPath) + if (!fs.existsSync(dir)) { + fs.mkdirSync(dir, { recursive: true }); + } + + await this.exec(`openssl x509 -outform der -in ${tmpCrtPath} -out ${derPath}`); this.derCert = derPath; 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 index 8a4271ab..312495a0 100644 --- a/packages/plugins/plugin-cert/src/plugin/cert-plugin/cert-reader.ts +++ b/packages/plugins/plugin-cert/src/plugin/cert-plugin/cert-reader.ts @@ -4,6 +4,7 @@ import os from "os"; import path from "path"; import { crypto } from "@certd/acme-client"; import { ILogger } from "@certd/pipeline"; +import dayjs from "dayjs"; export type CertReaderHandleContext = { reader: CertReader; tmpCrtPath: string; tmpKeyPath: string }; export type CertReaderHandle = (ctx: CertReaderHandleContext) => Promise; @@ -78,6 +79,7 @@ export class CertReader implements CertInfo { const detail = this.getCrtDetail(); let domain = detail.detail.domains.commonName; domain = domain.replace(".", "_").replace("*", "_"); - return `${prefix}_${domain}_${applyTime}.${suffix}`; + const timeStr = dayjs(applyTime).format("YYYYMMDDHHmmss"); + return `${prefix}_${domain}_${timeStr}.${suffix}`; } } diff --git a/packages/ui/certd-server/package.json b/packages/ui/certd-server/package.json index 1b5a7489..a9f68438 100644 --- a/packages/ui/certd-server/package.json +++ b/packages/ui/certd-server/package.json @@ -48,7 +48,7 @@ "cron-parser": "^4.9.0", "dayjs": "^1.11.7", "glob": "^10.4.5", - "https-proxy-agent": "^7.0.4", + "https-proxy-agent": "^7.0.5", "iconv-lite": "^0.6.3", "js-yaml": "^4.1.0", "jsonwebtoken": "^9.0.0", diff --git a/packages/ui/certd-server/src/plugins/plugin-aliyun/dns-provider/aliyun-dns-provider.ts b/packages/ui/certd-server/src/plugins/plugin-aliyun/dns-provider/aliyun-dns-provider.ts index 77dac961..c6f6fa9e 100644 --- a/packages/ui/certd-server/src/plugins/plugin-aliyun/dns-provider/aliyun-dns-provider.ts +++ b/packages/ui/certd-server/src/plugins/plugin-aliyun/dns-provider/aliyun-dns-provider.ts @@ -1,6 +1,7 @@ import { AbstractDnsProvider, CreateRecordOptions, IsDnsProvider, RemoveRecordOptions } from '@certd/plugin-cert'; import { Autowire, ILogger } from '@certd/pipeline'; -import { AliyunAccess } from '@certd/plugin-plus'; +import { AliyunAccess, AliyunClient } from '@certd/plugin-plus'; + @IsDnsProvider({ name: 'aliyun', title: '阿里云', @@ -15,13 +16,14 @@ export class AliyunDnsProvider extends AbstractDnsProvider { logger!: ILogger; async onInstance() { const access: any = this.access; - const Core = await import('@alicloud/pop-core'); - this.client = new Core.default({ + + this.client = new AliyunClient({logger:this.logger}) + await this.client.init({ accessKeyId: access.accessKeyId, accessKeySecret: access.accessKeySecret, endpoint: 'https://alidns.aliyuncs.com', apiVersion: '2015-01-09', - }); + }) } // // async getDomainList() { @@ -99,6 +101,7 @@ export class AliyunDnsProvider extends AbstractDnsProvider { // Line: 'oversea' // 海外 }; + const requestOption = { method: 'POST', }; diff --git a/packages/ui/certd-server/src/plugins/plugin-aliyun/plugin/deploy-to-ack-ingress/index.ts b/packages/ui/certd-server/src/plugins/plugin-aliyun/plugin/deploy-to-ack-ingress/index.ts index e7ccba53..e4b92b7c 100644 --- a/packages/ui/certd-server/src/plugins/plugin-aliyun/plugin/deploy-to-ack-ingress/index.ts +++ b/packages/ui/certd-server/src/plugins/plugin-aliyun/plugin/deploy-to-ack-ingress/index.ts @@ -1,5 +1,5 @@ import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput, utils } from '@certd/pipeline'; -import { AliyunAccess } from '@certd/plugin-plus'; +import { AliyunAccess, AliyunClient } from '@certd/plugin-plus'; import { appendTimeSuffix } from '../../utils/index.js'; import { CertInfo } from '@certd/plugin-cert'; @@ -200,14 +200,15 @@ export class DeployCertToAliyunAckIngressPlugin extends AbstractTaskPlugin { } async getClient(aliyunProvider: any, regionId: string) { - const Core = await import('@alicloud/pop-core'); - return new Core.default({ + const client = new AliyunClient({logger:this.logger}) + await client.init({ accessKeyId: aliyunProvider.accessKeyId, accessKeySecret: aliyunProvider.accessKeySecret, endpoint: `https://cs.${regionId}.aliyuncs.com`, apiVersion: '2015-12-15', - }); + }) + return client } async getKubeConfig(client: any, clusterId: string, isPrivateIpAddress = false) { diff --git a/packages/ui/certd-server/src/plugins/plugin-aliyun/plugin/deploy-to-cdn/index.ts b/packages/ui/certd-server/src/plugins/plugin-aliyun/plugin/deploy-to-cdn/index.ts index 3a8adf14..daf6bd52 100644 --- a/packages/ui/certd-server/src/plugins/plugin-aliyun/plugin/deploy-to-cdn/index.ts +++ b/packages/ui/certd-server/src/plugins/plugin-aliyun/plugin/deploy-to-cdn/index.ts @@ -1,6 +1,6 @@ import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline'; import dayjs from 'dayjs'; -import { AliyunAccess } from "@certd/plugin-plus"; +import { AliyunAccess, AliyunClient } from "@certd/plugin-plus"; @IsTaskPlugin({ name: 'DeployCertToAliyunCDN', title: '部署证书至阿里云CDN', @@ -59,14 +59,14 @@ export class DeployCertToAliyunCDN extends AbstractTaskPlugin { } async getClient(access: AliyunAccess) { - const Core = await import('@alicloud/pop-core'); - - return new Core.default({ + const client = new AliyunClient({logger:this.logger}) + await client.init({ accessKeyId: access.accessKeyId, accessKeySecret: access.accessKeySecret, endpoint: 'https://cdn.aliyuncs.com', apiVersion: '2018-05-10', - }); + }) + return client } async buildParams() { diff --git a/packages/ui/certd-server/src/plugins/plugin-aliyun/plugin/deploy-to-dcdn/index.ts b/packages/ui/certd-server/src/plugins/plugin-aliyun/plugin/deploy-to-dcdn/index.ts index eff620ba..ccdeaab6 100644 --- a/packages/ui/certd-server/src/plugins/plugin-aliyun/plugin/deploy-to-dcdn/index.ts +++ b/packages/ui/certd-server/src/plugins/plugin-aliyun/plugin/deploy-to-dcdn/index.ts @@ -1,6 +1,6 @@ import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline'; import dayjs from 'dayjs'; -import { AliyunAccess } from "@certd/plugin-plus"; +import { AliyunAccess, AliyunClient } from "@certd/plugin-plus"; @IsTaskPlugin({ name: 'DeployCertToAliyunDCDN', title: '部署证书至阿里云DCDN', @@ -59,13 +59,14 @@ export class DeployCertToAliyunDCDN extends AbstractTaskPlugin { } async getClient(access: AliyunAccess) { - const sdk = await import('@alicloud/pop-core'); - return new sdk.default({ + const client = new AliyunClient({logger:this.logger}) + await client.init({ accessKeyId: access.accessKeyId, accessKeySecret: access.accessKeySecret, endpoint: 'https://dcdn.aliyuncs.com', apiVersion: '2018-01-15', - }); + }) + return client } async buildParams() { diff --git a/packages/ui/certd-server/src/plugins/plugin-aliyun/plugin/upload-to-aliyun/index.ts b/packages/ui/certd-server/src/plugins/plugin-aliyun/plugin/upload-to-aliyun/index.ts index 1854eefb..69e771a4 100644 --- a/packages/ui/certd-server/src/plugins/plugin-aliyun/plugin/upload-to-aliyun/index.ts +++ b/packages/ui/certd-server/src/plugins/plugin-aliyun/plugin/upload-to-aliyun/index.ts @@ -1,6 +1,6 @@ import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput, TaskOutput } from '@certd/pipeline'; import { appendTimeSuffix, checkRet } from '../../utils/index.js'; -import { AliyunAccess } from "@certd/plugin-plus"; +import { AliyunAccess, AliyunClient } from "@certd/plugin-plus"; @IsTaskPlugin({ name: 'uploadCertToAliyun', @@ -86,13 +86,14 @@ export class UploadCertToAliyun extends AbstractTaskPlugin { } async getClient(aliyunProvider: AliyunAccess) { - const Core = await import('@alicloud/pop-core'); - return new Core.default({ + const client = new AliyunClient({logger:this.logger}) + await client.init({ accessKeyId: aliyunProvider.accessKeyId, accessKeySecret: aliyunProvider.accessKeySecret, endpoint: 'https://cas.aliyuncs.com', apiVersion: '2018-07-13', - }); + }) + return client } } //注册插件 diff --git a/packages/ui/certd-server/src/plugins/plugin-host/plugin/copy-to-local/index.ts b/packages/ui/certd-server/src/plugins/plugin-host/plugin/copy-to-local/index.ts index 43b6d866..077afbce 100644 --- a/packages/ui/certd-server/src/plugins/plugin-host/plugin/copy-to-local/index.ts +++ b/packages/ui/certd-server/src/plugins/plugin-host/plugin/copy-to-local/index.ts @@ -21,6 +21,7 @@ export class CopyCertToLocalPlugin extends AbstractTaskPlugin { component: { placeholder: './tmp/cert.pem', }, + required: true, }) crtPath!: string; @TaskInput({ @@ -29,6 +30,7 @@ export class CopyCertToLocalPlugin extends AbstractTaskPlugin { component: { placeholder: './tmp/cert.key', }, + required: true, }) keyPath!: string; @TaskInput({ @@ -36,7 +38,7 @@ export class CopyCertToLocalPlugin extends AbstractTaskPlugin { helper: '请选择前置任务输出的域名证书', component: { name: 'pi-output-selector', - from: 'CertApply', + from: ['CertApply','CertConvert'], }, required: true, }) @@ -44,11 +46,13 @@ export class CopyCertToLocalPlugin extends AbstractTaskPlugin { @TaskOutput({ title: '证书保存路径', + type:"HostCrtPath" }) hostCrtPath!: string; @TaskOutput({ title: '私钥保存路径', + type:"HostKeyPath" }) hostKeyPath!: string;