From b101ac7c7f913425673421498844fc59486b70a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=85=B7=E6=9B=A6=E7=A7=91=E6=8A=80?= Date: Tue, 17 Dec 2024 00:06:21 +0800 Subject: [PATCH 1/5] Update README.md Include the Docker compose configuration file content for automatic version updates. --- README.md | 49 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 36023b4fe..0a3ad1bf0 100644 --- a/README.md +++ b/README.md @@ -90,7 +90,7 @@ https://certd.handfree.work/ 1. 修改`docker-compose.yaml`中的镜像版本号 2. 运行`docker compose up -d` 即可 -如果使用`latest`版本 +如果需要使用最新版本 ```shell #重新拉取镜像 docker pull registry.cn-shenzhen.aliyuncs.com/handsfree/certd:latest @@ -98,7 +98,54 @@ docker pull registry.cn-shenzhen.aliyuncs.com/handsfree/certd:latest docker compose down docker compose up -d ``` +关于自动升级(仅限尝鲜建议非生产使用) +```yaml +version: '3.3' +services: + certd: + image: registry.cn-shenzhen.aliyuncs.com/handsfree/certd:latest + container_name: certd + restart: unless-stopped + volumes: + - /data/certd:/app/data + ports: + - "7001:7001" + - "7002:7002" + # 如果需要修改系统配置,可以通过环境变量传递;初次运行请保持默认配置 + environment: + - certd_system_resetAdminPasswd=false + # 如果需要切换数据库类型,可以在此处设置为mysql或postgres + # - certd_typeorm_dataSource_default_type=mysql + # - certd_typeorm_dataSource_default_host=localhost + # - certd_typeorm_dataSource_default_port=3306 + # - certd_typeorm_dataSource_default_username=root + # - certd_typeorm_dataSource_default_password=123456 + # - certd_typeorm_dataSource_default_database=certd + labels: + com.centurylinklabs.watchtower.enable: "true" + certd-updater: # 添加 Watchtower 服务 + image: containrrr/watchtower:latest + container_name: certd-updater + restart: unless-stopped + volumes: + - /var/run/docker.sock:/var/run/docker.sock + # 配置 自动更新 + environment: + - WATCHTOWER_CLEANUP=true # 自动清理旧版本容器 + - WATCHTOWER_INCLUDE_STOPPED=false # 不更新已停止的容器 + - WATCHTOWER_LABEL_ENABLE=true # 根据容器标签进行更新 + - WATCHTOWER_POLL_INTERVAL=300 # 每 5 分钟检查一次更新 + +# 如果需要支持 IPv6,请取消以下注释 +# networks: +# ip6net: +# enable_ipv6: true +# ipam: +# config: +# - subnet: 2001:db8::/64 + +``` > 数据默认存在`/data/certd`目录下,不用担心数据丢失 From 0e7578043e4a466043727685f7111b33634f6641 Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Tue, 17 Dec 2024 22:45:14 +0800 Subject: [PATCH 2/5] chore: --- .../plugins/plugin-cert/src/plugin/cert-plugin/acme.ts | 1 + .../plugins/plugin-cert/src/plugin/cert-plugin/base.ts | 2 ++ .../plugin-cert/src/plugin/cert-plugin/cert-reader.ts | 7 +++++++ 3 files changed, 10 insertions(+) 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 410754da7..085466a51 100644 --- a/packages/plugins/plugin-cert/src/plugin/cert-plugin/acme.ts +++ b/packages/plugins/plugin-cert/src/plugin/cert-plugin/acme.ts @@ -32,6 +32,7 @@ export type CertInfo = { pfx?: string; der?: string; jks?: string; + one?: string; }; export type SSLProvider = "letsencrypt" | "google" | "zerossl"; export type PrivateKeyType = "rsa_1024" | "rsa_2048" | "rsa_3072" | "rsa_4096" | "ec_256" | "ec_384" | "ec_521"; diff --git a/packages/plugins/plugin-cert/src/plugin/cert-plugin/base.ts b/packages/plugins/plugin-cert/src/plugin/cert-plugin/base.ts index d7d172cb4..f8dcf1f31 100644 --- a/packages/plugins/plugin-cert/src/plugin/cert-plugin/base.ts +++ b/packages/plugins/plugin-cert/src/plugin/cert-plugin/base.ts @@ -192,6 +192,7 @@ export abstract class CertApplyBasePlugin extends AbstractTaskPlugin { zip.file("cert.key", cert.key); zip.file("intermediate.crt", cert.ic); zip.file("origin.crt", cert.oc); + zip.file("one.pem", cert.one); if (cert.pfx) { zip.file("cert.pfx", Buffer.from(cert.pfx, "base64")); } @@ -209,6 +210,7 @@ cert.crt:证书文件,包含证书链,pem格式 cert.key:私钥文件,pem格式 intermediate.crt:中间证书文件,pem格式 origin.crt:原始证书文件,不含证书链,pem格式 +one.pem: 证书和私钥简单合并成一个文件,pem格式,crt正文+key正文 cert.pfx:pfx格式证书文件,iis服务器使用 cert.der:der格式证书文件 cert.jks:jks格式证书文件,java服务器使用 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 907c3ab16..1b53a909d 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 @@ -25,6 +25,7 @@ export class CertReader { key: string; csr: string; ic: string; //中间证书 + one: string; //crt + key 合成一个pem文件 detail: any; expires: number; @@ -46,6 +47,12 @@ export class CertReader { this.cert.oc = this.oc; } + this.one = certInfo.one; + if (!this.one) { + this.one = this.crt + "\n" + this.key; + this.cert.one = this.one; + } + const { detail, expires } = this.getCrtDetail(this.cert.crt); this.detail = detail; this.expires = expires.getTime(); From 53c38cf714a6f7486abbf1d71c9f48f56a790100 Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Tue, 17 Dec 2024 22:50:18 +0800 Subject: [PATCH 3/5] =?UTF-8?q?perf:=20=E6=94=AF=E6=8C=81=E4=B8=80?= =?UTF-8?q?=E4=BD=93=E8=AF=81=E4=B9=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/plugin/cert-plugin/cert-reader.ts | 8 ++++++-- .../plugin/upload-to-host/index.ts | 19 +++++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) 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 1b53a909d..4128830d4 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 @@ -15,6 +15,7 @@ export type CertReaderHandleContext = { tmpDerPath?: string; tmpIcPath?: string; tmpJksPath?: string; + tmpOnePath?: string; }; export type CertReaderHandle = (ctx: CertReaderHandleContext) => Promise; export type HandleOpts = { logger: ILogger; handle: CertReaderHandle }; @@ -95,7 +96,7 @@ export class CertReader { return domains; } - saveToFile(type: "crt" | "key" | "pfx" | "der" | "oc" | "ic" | "jks", filepath?: string) { + saveToFile(type: "crt" | "key" | "pfx" | "der" | "oc" | "one" | "ic" | "jks", filepath?: string) { if (!this.cert[type]) { return; } @@ -109,7 +110,7 @@ export class CertReader { if (!fs.existsSync(dir)) { fs.mkdirSync(dir, { recursive: true }); } - if (type === "crt" || type === "key" || type === "ic" || type === "oc") { + if (type === "crt" || type === "key" || type === "ic" || type === "oc" || type === "one") { fs.writeFileSync(filepath, this.cert[type]); } else { fs.writeFileSync(filepath, Buffer.from(this.cert[type], "base64")); @@ -127,6 +128,7 @@ export class CertReader { const tmpOcPath = this.saveToFile("oc"); const tmpDerPath = this.saveToFile("der"); const tmpJksPath = this.saveToFile("jks"); + const tmpOnePath = this.saveToFile("one"); logger.info("本地文件写入成功"); try { return await opts.handle({ @@ -138,6 +140,7 @@ export class CertReader { tmpIcPath: tmpIcPath, tmpJksPath: tmpJksPath, tmpOcPath: tmpOcPath, + tmpOnePath, }); } catch (err) { throw err; @@ -156,6 +159,7 @@ export class CertReader { removeFile(tmpDerPath); removeFile(tmpIcPath); removeFile(tmpJksPath); + removeFile(tmpOnePath); } } diff --git a/packages/ui/certd-server/src/plugins/plugin-host/plugin/upload-to-host/index.ts b/packages/ui/certd-server/src/plugins/plugin-host/plugin/upload-to-host/index.ts index 933ead20f..204029834 100644 --- a/packages/ui/certd-server/src/plugins/plugin-host/plugin/upload-to-host/index.ts +++ b/packages/ui/certd-server/src/plugins/plugin-host/plugin/upload-to-host/index.ts @@ -38,6 +38,7 @@ export class UploadCertToHostPlugin extends AbstractTaskPlugin { { value: 'pfx', label: 'pfx,一般用于IIS' }, { value: 'der', label: 'der,一般用于Apache' }, { value: 'jks', label: 'jks,一般用于JAVA应用' }, + { value: 'one', label: '证书私钥一体,crt+key简单合并为一个pem文件' }, ], }, required: true, @@ -150,6 +151,24 @@ export class UploadCertToHostPlugin extends AbstractTaskPlugin { }) jksPath!: string; + @TaskInput({ + title: '一体证书保存路径', + helper: '填写应用原本的证书保存路径,路径要包含证书文件名,例如:/tmp/crt_key.pem', + component: { + placeholder: '/root/deploy/app/crt_key.pem', + }, + mergeScript: ` + return { + show: ctx.compute(({form})=>{ + return form.certType === 'one'; + }) + } + `, + required: true, + rules: [{ type: 'filepath' }], + }) + onePath!: string; + @TaskInput({ title: '主机登录配置', helper: 'access授权', From eda45c1528199648b3970505e87f492d398226cd Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Wed, 18 Dec 2024 00:38:27 +0800 Subject: [PATCH 4/5] =?UTF-8?q?perf:=20=E6=94=AF=E6=8C=81plesk=E7=BD=91?= =?UTF-8?q?=E7=AB=99=E8=AF=81=E4=B9=A6=E9=83=A8=E7=BD=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/core/basic/src/utils/util.options.ts | 2 ++ packages/core/basic/src/utils/util.request.ts | 5 +++-- packages/core/pipeline/src/core/executor.ts | 2 +- packages/core/pipeline/src/core/run-history.ts | 4 ++++ 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/core/basic/src/utils/util.options.ts b/packages/core/basic/src/utils/util.options.ts index 96180e60e..4689c9df7 100644 --- a/packages/core/basic/src/utils/util.options.ts +++ b/packages/core/basic/src/utils/util.options.ts @@ -37,6 +37,8 @@ function buildGroupOptions(options: any[], inDomains: string[]) { } export const optionsUtils = { + //获取分组 groupByDomain, + //构建分组后的选项列表,常用 buildGroupOptions, }; diff --git a/packages/core/basic/src/utils/util.request.ts b/packages/core/basic/src/utils/util.request.ts index 9342d73aa..5f119214d 100644 --- a/packages/core/basic/src/utils/util.request.ts +++ b/packages/core/basic/src/utils/util.request.ts @@ -156,13 +156,13 @@ export function createAxiosService({ logger }: { logger: Logger }) { error.message = '请求错误'; break; case 401: - error.message = '未授权,请登录'; + error.message = '认证/登录失败'; break; case 403: error.message = '拒绝访问'; break; case 404: - error.message = `请求地址出错: ${error.response.config.url}`; + error.message = `请求地址出错`; break; case 408: error.message = '请求超时'; @@ -216,6 +216,7 @@ export type HttpRequestConfig = { logParams?: boolean; logRes?: boolean; httpProxy?: string; + returnResponse?: boolean; } & AxiosRequestConfig; export type HttpClient = { request(config: HttpRequestConfig): Promise>; diff --git a/packages/core/pipeline/src/core/executor.ts b/packages/core/pipeline/src/core/executor.ts index 874c525a7..3f09b402a 100644 --- a/packages/core/pipeline/src/core/executor.ts +++ b/packages/core/pipeline/src/core/executor.ts @@ -385,7 +385,7 @@ export class Executor { content = `流水线ID:${this.pipeline.id},运行ID:${this.runtime.id}`; } else if (when === "error") { subject = `执行失败,${this.pipeline.title}【${this.pipeline.id}】`; - content = `流水线ID:${this.pipeline.id},运行ID:${this.runtime.id}\n错误详情:${error.message}`; + content = `流水线ID:${this.pipeline.id},运行ID:${this.runtime.id}\n\n${this.currentStatusMap?.currentStep?.title} 执行失败\n\n错误详情:${error.message}`; } else { return; } diff --git a/packages/core/pipeline/src/core/run-history.ts b/packages/core/pipeline/src/core/run-history.ts index 1c2711867..be7e11117 100644 --- a/packages/core/pipeline/src/core/run-history.ts +++ b/packages/core/pipeline/src/core/run-history.ts @@ -134,6 +134,7 @@ export class RunHistory { export class RunnableCollection { private collection: RunnableMap = {}; private pipeline!: Pipeline; + currentStep!: Step; constructor(pipeline?: Pipeline) { if (!pipeline) { return; @@ -193,5 +194,8 @@ export class RunnableCollection { add(runnable: Runnable) { this.collection[runnable.id] = runnable; + if (runnable.runnableType === "step") { + this.currentStep = runnable as Step; + } } } From 549525fb37c9793c2880fe2d88d71e941fb6c4eb Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Wed, 18 Dec 2024 10:22:22 +0800 Subject: [PATCH 5/5] chore: plesk ok --- packages/core/basic/src/utils/util.request.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/core/basic/src/utils/util.request.ts b/packages/core/basic/src/utils/util.request.ts index 5f119214d..3be865ba0 100644 --- a/packages/core/basic/src/utils/util.request.ts +++ b/packages/core/basic/src/utils/util.request.ts @@ -1,4 +1,4 @@ -import axios, { AxiosRequestConfig } from 'axios'; +import axios, { AxiosHeaders, AxiosRequestConfig } from 'axios'; import { ILogger, logger } from './util.log.js'; import { Logger } from 'log4js'; import { HttpProxyAgent } from 'http-proxy-agent'; @@ -13,7 +13,7 @@ export class HttpError extends Error { statusText?: string; code?: string; request?: { baseURL: string; url: string; method: string; params?: any; data?: any }; - response?: { data: any }; + response?: { data: any; headers: AxiosHeaders }; cause?: any; constructor(error: any) { if (!error) { @@ -55,6 +55,7 @@ export class HttpError extends Error { this.response = { data: error.response?.data, + headers: error.response?.headers, }; const { stack, cause } = error;