Compare commits

...

21 Commits

Author SHA1 Message Date
xiaojunnuo
031df8fc35 v1.21.2 2024-07-08 15:58:51 +08:00
xiaojunnuo
62419a8212 build: prepare to build 2024-07-08 15:57:13 +08:00
xiaojunnuo
09d93af853 build: prepare to build 2024-07-08 15:47:51 +08:00
xiaojunnuo
b6ab178de9 chore: 1 2024-07-08 15:47:36 +08:00
xiaojunnuo
5a08f27d2c build: prepare to build 2024-07-08 15:36:18 +08:00
xiaojunnuo
fe91d94090 perf: 申请证书时可以选择跳过本地dns校验 2024-07-08 15:35:58 +08:00
xiaojunnuo
56ab3269d2 chore: 1 2024-07-08 12:05:56 +08:00
xiaojunnuo
c8243c573f chore: 1 2024-07-08 12:04:59 +08:00
xiaojunnuo
0b769a1c86 v1.21.1 2024-07-08 11:58:09 +08:00
xiaojunnuo
a8189a974d build: prepare to build 2024-07-08 11:46:13 +08:00
xiaojunnuo
322875d241 chore: 1 2024-07-08 11:45:31 +08:00
xiaojunnuo
ed8a54a2bc chore: 1 2024-07-08 11:29:11 +08:00
xiaojunnuo
5ba9831ed1 perf: 上传到主机,支持设置不mkdirs 2024-07-08 11:19:02 +08:00
xiaojunnuo
f9c9fce581 docs: 1 2024-07-08 11:10:08 +08:00
xiaojunnuo
bc650a32cd docs: 1 2024-07-08 10:59:19 +08:00
xiaojunnuo
c6d3e3fe5b docs: 1 2024-07-08 10:57:42 +08:00
xiaojunnuo
73acc62af1 docs: 1 2024-07-08 10:56:19 +08:00
xiaojunnuo
0d4491f3a0 docs: 1 2024-07-08 10:55:55 +08:00
xiaojunnuo
85248044ab docs: 1 2024-07-08 10:53:55 +08:00
xiaojunnuo
c532449102 docs: 1 2024-07-05 10:56:29 +08:00
xiaojunnuo
970c7fd8a0 perf: 说明优化,默认值优化 2024-07-04 02:22:52 +08:00
36 changed files with 321 additions and 125 deletions

View File

@@ -3,6 +3,19 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.21.2](https://github.com/certd/certd/compare/v1.21.1...v1.21.2) (2024-07-08)
### Performance Improvements
* 申请证书时可以选择跳过本地dns校验 ([fe91d94](https://github.com/certd/certd/commit/fe91d94090d22ed0a3ea753ba74dfaa1bf057c17))
## [1.21.1](https://github.com/certd/certd/compare/v1.21.0...v1.21.1) (2024-07-08)
### Performance Improvements
* 上传到主机支持设置不mkdirs ([5ba9831](https://github.com/certd/certd/commit/5ba9831ed1aa6ec6057df246f1035b36b9c41d2e))
* 说明优化,默认值优化 ([970c7fd](https://github.com/certd/certd/commit/970c7fd8a0f557770e973d8462ee5684ef742810))
# [1.21.0](https://github.com/certd/certd/compare/v1.20.17...v1.21.0) (2024-07-03) # [1.21.0](https://github.com/certd/certd/compare/v1.20.17...v1.21.0) (2024-07-03)
### Features ### Features

View File

@@ -1,13 +1,15 @@
# CertD # CertD
CertD 是一个免费全自动申请和部署SSL证书的工具。 CertD 是一个免费全自动申请和自动部署更新SSL证书的工具。
后缀D取自linux守护进程的命名风格意为证书守护进程。 后缀D取自linux守护进程的命名风格意为证书守护进程。
关键字:证书自动申请、证书自动更新、证书自动续期、证书自动续签
## 一、特性 ## 一、特性
本项目不仅支持证书申请过程自动化,还可以自动化部署证书,让你的证书永不过期。 本项目不仅支持证书申请过程自动化,还可以自动化部署更新证书,让你的证书永不过期。
* 全自动申请证书支持阿里云、腾讯云、华为云、Cloudflare注册的域名 * 全自动申请证书支持阿里云、腾讯云、华为云、Cloudflare注册的域名
* 全自动部署证书(目前支持服务器上传部署、部署到阿里云、腾讯云等) * 全自动部署更新证书(目前支持服务器上传部署、部署到阿里云、腾讯云等)
* 支持通配符域名 * 支持通配符域名
* 支持多个域名打到一个证书上 * 支持多个域名打到一个证书上
* 邮件通知 * 邮件通知
@@ -108,8 +110,8 @@ http://your_server_ip:7001
* http-01 在网站根目录下放置一份txt文件 * http-01 在网站根目录下放置一份txt文件
* dns-01 需要给域名添加txt解析记录通配符域名只能用这种方式 * dns-01 需要给域名添加txt解析记录通配符域名只能用这种方式
* 证书续期: * 证书续期:
* 实际上acme并没有续期概念 * 实际上没有办法不改变证书文件本身情况下直接续期或者续签
* 我们所说的续期,其实就是按照全套流程重新申请一份新证书。 * 我们所说的续期,其实就是按照全套流程重新申请一份新证书,然后重新部署上去
* 免费证书过期时间90天以后可能还会缩短所以自动化部署必不可少 * 免费证书过期时间90天以后可能还会缩短所以自动化部署必不可少
* 设置每天自动运行当证书过期前20天会自动重新申请证书并部署 * 设置每天自动运行当证书过期前20天会自动重新申请证书并部署
@@ -172,3 +174,7 @@ docker compose up -d
* [袖手GPT](https://ai.handsfree.work/) ChatGPT国内可用无需FQ每日免费额度 * [袖手GPT](https://ai.handsfree.work/) ChatGPT国内可用无需FQ每日免费额度
* [fast-crud](https://gitee.com/fast-crud/fast-crud/) 基于vue3的crud快速开发框架 * [fast-crud](https://gitee.com/fast-crud/fast-crud/) 基于vue3的crud快速开发框架
* [dev-sidecar](https://github.com/docmirror/dev-sidecar/) 直连访问github工具无需FQ解决github无法访问的问题 * [dev-sidecar](https://github.com/docmirror/dev-sidecar/) 直连访问github工具无需FQ解决github无法访问的问题
## 十二、版本更新日志
https://github.com/certd/certd/blob/v2/CHANGELOG.md

View File

@@ -1,6 +1,5 @@
import http from 'axios' import http from 'axios'
import fs from 'fs' import fs from 'fs'
//读取 packages/core/pipline/package.json的版本号 //读取 packages/core/pipline/package.json的版本号
import {default as packageJson} from './packages/core/pipeline/package.json' assert { type: "json" }; import {default as packageJson} from './packages/core/pipeline/package.json' assert { type: "json" };

View File

@@ -9,5 +9,5 @@
} }
}, },
"npmClient": "pnpm", "npmClient": "pnpm",
"version": "1.21.0" "version": "1.21.2"
} }

View File

@@ -14,9 +14,10 @@
"i-all": "lerna link && lerna exec npm install ", "i-all": "lerna link && lerna exec npm install ",
"publish": "npm run prepublishOnly1 && lerna publish --conventional-commits && npm run afterpublishOnly && npm run deploy1", "publish": "npm run prepublishOnly1 && lerna publish --conventional-commits && npm run afterpublishOnly && npm run deploy1",
"afterpublishOnly": "", "afterpublishOnly": "",
"prepublishOnly1": "npm run before-build && lerna run build ", "prepublishOnly1": "npm run check && npm run before-build && lerna run build ",
"before-build": "cd ./packages/core/acme-client && time /t >build.md && git add ./build.md && git commit -m \"build: prepare to build\"", "before-build": "cd ./packages/core/acme-client && time /t >build.md && git add ./build.md && git commit -m \"build: prepare to build\"",
"deploy1": "node --experimental-json-modules deploy.js " "deploy1": "node --experimental-json-modules deploy.js ",
"check": "node --experimental-json-modules publish-check.js"
}, },
"license": "AGPL-3.0", "license": "AGPL-3.0",
"dependencies": { "dependencies": {

View File

@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.21.2](https://github.com/publishlab/node-acme-client/compare/v1.21.1...v1.21.2) (2024-07-08)
**Note:** Version bump only for package @certd/acme-client
## [1.21.1](https://github.com/publishlab/node-acme-client/compare/v1.21.0...v1.21.1) (2024-07-08)
**Note:** Version bump only for package @certd/acme-client
# [1.21.0](https://github.com/publishlab/node-acme-client/compare/v1.20.17...v1.21.0) (2024-07-03) # [1.21.0](https://github.com/publishlab/node-acme-client/compare/v1.20.17...v1.21.0) (2024-07-03)
### Features ### Features

View File

@@ -1 +1 @@
01:14 15:57

View File

@@ -3,7 +3,7 @@
"description": "Simple and unopinionated ACME client", "description": "Simple and unopinionated ACME client",
"private": false, "private": false,
"author": "nmorsman", "author": "nmorsman",
"version": "1.21.0", "version": "1.21.2",
"main": "src/index.js", "main": "src/index.js",
"types": "types/index.d.ts", "types": "types/index.d.ts",
"license": "MIT", "license": "MIT",

View File

@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.21.2](https://github.com/certd/certd/compare/v1.21.1...v1.21.2) (2024-07-08)
**Note:** Version bump only for package @certd/pipeline
## [1.21.1](https://github.com/certd/certd/compare/v1.21.0...v1.21.1) (2024-07-08)
**Note:** Version bump only for package @certd/pipeline
# [1.21.0](https://github.com/certd/certd/compare/v1.20.17...v1.21.0) (2024-07-03) # [1.21.0](https://github.com/certd/certd/compare/v1.20.17...v1.21.0) (2024-07-03)
**Note:** Version bump only for package @certd/pipeline **Note:** Version bump only for package @certd/pipeline

View File

@@ -1,7 +1,7 @@
{ {
"name": "@certd/pipeline", "name": "@certd/pipeline",
"private": false, "private": false,
"version": "1.21.0", "version": "1.21.2",
"main": "./src/index.ts", "main": "./src/index.ts",
"module": "./src/index.ts", "module": "./src/index.ts",
"types": "./src/index.ts", "types": "./src/index.ts",
@@ -23,7 +23,7 @@
"qs": "^6.11.2" "qs": "^6.11.2"
}, },
"devDependencies": { "devDependencies": {
"@certd/acme-client": "workspace:^1.21.0", "@certd/acme-client": "workspace:^1.21.2",
"@rollup/plugin-commonjs": "^23.0.4", "@rollup/plugin-commonjs": "^23.0.4",
"@rollup/plugin-json": "^6.0.0", "@rollup/plugin-json": "^6.0.0",
"@rollup/plugin-node-resolve": "^15.0.1", "@rollup/plugin-node-resolve": "^15.0.1",

View File

@@ -3,6 +3,18 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.21.2](https://github.com/certd/certd/compare/v1.21.1...v1.21.2) (2024-07-08)
### Performance Improvements
* 申请证书时可以选择跳过本地dns校验 ([fe91d94](https://github.com/certd/certd/commit/fe91d94090d22ed0a3ea753ba74dfaa1bf057c17))
## [1.21.1](https://github.com/certd/certd/compare/v1.21.0...v1.21.1) (2024-07-08)
### Performance Improvements
* 说明优化,默认值优化 ([970c7fd](https://github.com/certd/certd/commit/970c7fd8a0f557770e973d8462ee5684ef742810))
# [1.21.0](https://github.com/certd/certd/compare/v1.20.17...v1.21.0) (2024-07-03) # [1.21.0](https://github.com/certd/certd/compare/v1.20.17...v1.21.0) (2024-07-03)
### Features ### Features

View File

@@ -1,7 +1,7 @@
{ {
"name": "@certd/plugin-cert", "name": "@certd/plugin-cert",
"private": false, "private": false,
"version": "1.21.0", "version": "1.21.2",
"main": "./src/index.ts", "main": "./src/index.ts",
"module": "./src/index.ts", "module": "./src/index.ts",
"types": "./src/index.ts", "types": "./src/index.ts",
@@ -17,8 +17,8 @@
"preview": "vite preview" "preview": "vite preview"
}, },
"dependencies": { "dependencies": {
"@certd/acme-client": "workspace:^1.21.0", "@certd/acme-client": "workspace:^1.21.2",
"@certd/pipeline": "workspace:^1.21.0", "@certd/pipeline": "workspace:^1.21.2",
"jszip": "^3.10.1", "jszip": "^3.10.1",
"node-forge": "^0.10.0", "node-forge": "^0.10.0",
"psl": "^1.9.0" "psl": "^1.9.0"

View File

@@ -2,7 +2,7 @@ import { IsAccess, AccessInput } from "@certd/pipeline";
@IsAccess({ @IsAccess({
name: "eab", name: "eab",
title: "EABAccess", title: "EAB授权",
desc: "ZeroSSL证书申请需要EAB授权", desc: "ZeroSSL证书申请需要EAB授权",
}) })
export class EabAccess { export class EabAccess {

View File

@@ -18,12 +18,20 @@ export class AcmeService {
userContext: IContext; userContext: IContext;
logger: Logger; logger: Logger;
sslProvider: SSLProvider; sslProvider: SSLProvider;
skipLocalVerify = true;
eab?: ClientExternalAccountBindingOptions; eab?: ClientExternalAccountBindingOptions;
constructor(options: { userContext: IContext; logger: Logger; sslProvider: SSLProvider; eab?: ClientExternalAccountBindingOptions }) { constructor(options: {
userContext: IContext;
logger: Logger;
sslProvider: SSLProvider;
eab?: ClientExternalAccountBindingOptions;
skipLocalVerify?: boolean;
}) {
this.userContext = options.userContext; this.userContext = options.userContext;
this.logger = options.logger; this.logger = options.logger;
this.sslProvider = options.sslProvider || "letsencrypt"; this.sslProvider = options.sslProvider || "letsencrypt";
this.eab = options.eab; this.eab = options.eab;
this.skipLocalVerify = options.skipLocalVerify ?? false;
acme.setLogger((text: string) => { acme.setLogger((text: string) => {
this.logger.info(text); this.logger.info(text);
}); });
@@ -192,7 +200,7 @@ export class AcmeService {
csr, csr,
email: email, email: email,
termsOfServiceAgreed: true, termsOfServiceAgreed: true,
skipChallengeVerification: false, skipChallengeVerification: this.skipLocalVerify,
challengePriority: ["dns-01"], challengePriority: ["dns-01"],
challengeCreateFn: async (authz: acme.Authorization, challenge: Challenge, keyAuthorization: string): Promise<any> => { challengeCreateFn: async (authz: acme.Authorization, challenge: Challenge, keyAuthorization: string): Promise<any> => {
return await this.challengeCreateFn(authz, challenge, keyAuthorization, dnsProvider); return await this.challengeCreateFn(authz, challenge, keyAuthorization, dnsProvider);

View File

@@ -38,10 +38,10 @@ export class CertApplyPlugin extends AbstractTaskPlugin {
span: 24, span: 24,
}, },
helper: helper:
"支持通配符域名,例如: *.foo.com、foo.com、*.test.handsfree.work\n" + "1、支持通配符域名,例如: *.foo.com、foo.com、*.test.handsfree.work\n" +
"支持多个域名、多个子域名、多个通配符域名打到一个证书上域名必须是在同一个DNS提供商解析\n" + "2、支持多个域名、多个子域名、多个通配符域名打到一个证书上域名必须是在同一个DNS提供商解析\n" +
"多级子域名要分成多个域名输入(*.foo.com的证书不能用于xxx.yyy.foo.com、foo.com\n" + "3、多级子域名要分成多个域名输入(*.foo.com的证书不能用于xxx.yyy.foo.com、foo.com\n" +
"输入一个回车之后,再输入下一个", "4、输入一个回车之后,再输入下一个",
}) })
domains!: string; domains!: string;
@@ -58,7 +58,7 @@ export class CertApplyPlugin extends AbstractTaskPlugin {
@TaskInput({ @TaskInput({
title: "证书提供商", title: "证书提供商",
value: "letsencrypt", default: "letsencrypt",
component: { component: {
name: "a-select", name: "a-select",
vModel: "value", vModel: "value",
@@ -109,6 +109,17 @@ export class CertApplyPlugin extends AbstractTaskPlugin {
}) })
dnsProviderAccess!: string; dnsProviderAccess!: string;
@TaskInput({
title: "跳过本地校验DNS",
default: false,
component: {
name: "a-switch",
vModel: "checked",
},
helper: "如果重试多次出现Authorization not found TXT record导致无法申请成功请尝试开启此选项",
})
skipLocalVerify = false;
@TaskInput({ @TaskInput({
title: "更新天数", title: "更新天数",
component: { component: {
@@ -165,7 +176,13 @@ export class CertApplyPlugin extends AbstractTaskPlugin {
if (this.eabAccessId) { if (this.eabAccessId) {
eab = await this.ctx.accessService.getById(this.eabAccessId); eab = await this.ctx.accessService.getById(this.eabAccessId);
} }
this.acme = new AcmeService({ userContext: this.userContext, logger: this.logger, sslProvider: this.sslProvider, eab }); this.acme = new AcmeService({
userContext: this.userContext,
logger: this.logger,
sslProvider: this.sslProvider,
eab,
skipLocalVerify: this.skipLocalVerify,
});
} }
async execute(): Promise<void> { async execute(): Promise<void> {

View File

@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.21.2](https://github.com/certd/certd/compare/v1.21.1...v1.21.2) (2024-07-08)
**Note:** Version bump only for package @certd/plugin-util
## [1.21.1](https://github.com/certd/certd/compare/v1.21.0...v1.21.1) (2024-07-08)
**Note:** Version bump only for package @certd/plugin-util
# [1.21.0](https://github.com/certd/certd/compare/v1.20.17...v1.21.0) (2024-07-03) # [1.21.0](https://github.com/certd/certd/compare/v1.20.17...v1.21.0) (2024-07-03)
**Note:** Version bump only for package @certd/plugin-util **Note:** Version bump only for package @certd/plugin-util

View File

@@ -1,7 +1,7 @@
{ {
"name": "@certd/plugin-util", "name": "@certd/plugin-util",
"private": false, "private": false,
"version": "1.21.0", "version": "1.21.2",
"main": "./src/index.ts", "main": "./src/index.ts",
"module": "./src/index.ts", "module": "./src/index.ts",
"types": "./src/index.ts", "types": "./src/index.ts",
@@ -21,7 +21,7 @@
"shelljs": "^0.8.5" "shelljs": "^0.8.5"
}, },
"devDependencies": { "devDependencies": {
"@certd/pipeline": "workspace:^1.21.0", "@certd/pipeline": "workspace:^1.21.2",
"@rollup/plugin-commonjs": "^23.0.4", "@rollup/plugin-commonjs": "^23.0.4",
"@rollup/plugin-json": "^6.0.0", "@rollup/plugin-json": "^6.0.0",
"@rollup/plugin-node-resolve": "^15.0.1", "@rollup/plugin-node-resolve": "^15.0.1",

View File

@@ -3,6 +3,16 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.21.2](https://github.com/certd/certd/compare/v1.21.1...v1.21.2) (2024-07-08)
**Note:** Version bump only for package @certd/ui-client
## [1.21.1](https://github.com/certd/certd/compare/v1.21.0...v1.21.1) (2024-07-08)
### Performance Improvements
* 说明优化,默认值优化 ([970c7fd](https://github.com/certd/certd/commit/970c7fd8a0f557770e973d8462ee5684ef742810))
# [1.21.0](https://github.com/certd/certd/compare/v1.20.17...v1.21.0) (2024-07-03) # [1.21.0](https://github.com/certd/certd/compare/v1.20.17...v1.21.0) (2024-07-03)
**Note:** Version bump only for package @certd/ui-client **Note:** Version bump only for package @certd/ui-client

View File

@@ -1,6 +1,6 @@
{ {
"name": "@certd/ui-client", "name": "@certd/ui-client",
"version": "1.21.0", "version": "1.21.2",
"private": true, "private": true,
"scripts": { "scripts": {
"dev": "vite --open", "dev": "vite --open",
@@ -59,7 +59,7 @@
"vuedraggable": "^2.24.3" "vuedraggable": "^2.24.3"
}, },
"devDependencies": { "devDependencies": {
"@certd/pipeline": "^1.21.0", "@certd/pipeline": "^1.21.2",
"@rollup/plugin-commonjs": "^25.0.7", "@rollup/plugin-commonjs": "^25.0.7",
"@rollup/plugin-node-resolve": "^15.2.3", "@rollup/plugin-node-resolve": "^15.2.3",
"@types/chai": "^4.3.12", "@types/chai": "^4.3.12",

View File

@@ -5,7 +5,7 @@
<fs-icon class="cd-icon-button" icon="ion:close-circle-outline" @click="clear"></fs-icon> <fs-icon class="cd-icon-button" icon="ion:close-circle-outline" @click="clear"></fs-icon>
</span> </span>
<span v-else class="mlr-5 gray">请选择</span> <span v-else class="mlr-5 gray">请选择</span>
<a-button @click="chooseForm.open">选择</a-button> <a-button class="ml-5" @click="chooseForm.open">选择</a-button>
<a-form-item-rest v-if="chooseForm.show"> <a-form-item-rest v-if="chooseForm.show">
<a-modal v-model:open="chooseForm.show" title="选择授权提供者" width="700px" @ok="chooseForm.ok"> <a-modal v-model:open="chooseForm.show" title="选择授权提供者" width="700px" @ok="chooseForm.ok">
<div style="height: 400px; position: relative"> <div style="height: 400px; position: relative">
@@ -46,9 +46,9 @@ export default defineComponent({
} }
} }
function clear(){ function clear() {
selectedId.value = ""; selectedId.value = "";
target.value = null target.value = null;
ctx.emit("update:modelValue", selectedId.value); ctx.emit("update:modelValue", selectedId.value);
} }
@@ -99,7 +99,6 @@ export default defineComponent({
} }
}); });
return { return {
clear, clear,
target, target,

View File

@@ -97,7 +97,6 @@ async function changePassword() {
const formOptions = buildFormOptions(passwordFormOptions); const formOptions = buildFormOptions(passwordFormOptions);
formOptions.newInstance = true; //新实例打开 formOptions.newInstance = true; //新实例打开
passwordFormRef.value = await openDialog(formOptions); passwordFormRef.value = await openDialog(formOptions);
debugger;
console.log(passwordFormRef.value); console.log(passwordFormRef.value);
} }
</script> </script>

View File

@@ -1,7 +1,7 @@
import { compute } from "@fast-crud/fast-crud"; import { compute, CreateCrudOptionsProps, CreateCrudOptionsRet } from "@fast-crud/fast-crud";
import { Dicts } from "./dicts"; import { Dicts } from "./dicts";
export default function () { export default function (): CreateCrudOptionsRet {
return { return {
crudOptions: { crudOptions: {
form: { form: {
@@ -12,7 +12,7 @@ export default function () {
columns: { columns: {
domains: { domains: {
title: "域名", title: "域名",
type: ["dict-select"], type: "dict-select",
search: { search: {
show: true, show: true,
component: { component: {
@@ -58,6 +58,30 @@ export default function () {
rules: [{ required: true, type: "email", message: "请填写邮箱" }] rules: [{ required: true, type: "email", message: "请填写邮箱" }]
} }
}, },
blank: {
title: "占位",
type: "text",
form: {
blank: true
}
},
sslProvider: {
title: "证书提供商",
type: "dict-select",
dict: Dicts.sslProviderDict
},
eabAccess: {
title: "EAB授权",
type: "dict-select",
form: {
component: {
name: "PiAccessSelector",
type: "eab",
vModel: "modelValue"
},
helper: "如果是ZeroSSL需要配置EAB授权https://app.zerossl.com/developer 生成 'EAB' "
}
},
dnsProviderType: { dnsProviderType: {
title: "DNS提供商", title: "DNS提供商",
type: "dict-select", type: "dict-select",

View File

@@ -1,7 +1,12 @@
import { dict } from "@fast-crud/fast-crud"; import { dict } from "@fast-crud/fast-crud";
export const Dicts = { export const Dicts = {
certIssuerDict: dict({ data: [{ value: "letencrypt", label: "LetEncrypt" }] }), sslProviderDict: dict({
data: [
{ value: "letsencrypt", label: "Lets Encrypt" },
{ value: "zerossl", label: "ZeroSSL" }
]
}),
challengeTypeDict: dict({ data: [{ value: "dns", label: "DNS校验" }] }), challengeTypeDict: dict({ data: [{ value: "dns", label: "DNS校验" }] }),
dnsProviderTypeDict: dict({ dnsProviderTypeDict: dict({
url: "pi/dnsProvider/dnsProviderTypeDict" url: "pi/dnsProvider/dnsProviderTypeDict"

View File

@@ -9,7 +9,7 @@ import { ref } from "vue";
import _ from "lodash-es"; import _ from "lodash-es";
export default { export default {
name: "PiCertdForm", name: "PiCertdForm",
setup(props:any, ctx:any) { setup(props: any, ctx: any) {
// 自定义表单配置 // 自定义表单配置
const { buildFormOptions } = useColumns(); const { buildFormOptions } = useColumns();
//使用crudOptions结构来构建自定义表单配置 //使用crudOptions结构来构建自定义表单配置
@@ -18,7 +18,7 @@ export default {
const formOptions = buildFormOptions( const formOptions = buildFormOptions(
_.merge(crudOptions, { _.merge(crudOptions, {
form: { form: {
doSubmit({ form }:any) { doSubmit({ form }: any) {
// 创建certd 的pipeline // 创建certd 的pipeline
doSubmitRef.value({ form }); doSubmitRef.value({ form });
} }
@@ -29,7 +29,7 @@ export default {
const formWrapperRef = ref(); const formWrapperRef = ref();
const formWrapperOptions = ref(); const formWrapperOptions = ref();
formWrapperOptions.value = formOptions; formWrapperOptions.value = formOptions;
function open(doSubmit:any) { function open(doSubmit: any) {
doSubmitRef.value = doSubmit; doSubmitRef.value = doSubmit;
formWrapperRef.value.open(formWrapperOptions.value); formWrapperRef.value.open(formWrapperOptions.value);
} }

View File

@@ -7,6 +7,11 @@
<template #actionbar-right> <template #actionbar-right>
<!-- <span style="margin-left: 10px">出现<a-tag>Promise rejected attempt #18,retrying in 10000ms:No TXT recordsfound for name</a-tag>属于正常现象多重试几次</span>--> <!-- <span style="margin-left: 10px">出现<a-tag>Promise rejected attempt #18,retrying in 10000ms:No TXT recordsfound for name</a-tag>属于正常现象多重试几次</span>-->
</template> </template>
<template #form-bottom>
<div>
申请证书
</div>
</template>
<pi-certd-form ref="certdFormRef"></pi-certd-form> <pi-certd-form ref="certdFormRef"></pi-certd-form>
</fs-crud> </fs-crud>
</fs-page> </fs-page>

View File

@@ -64,11 +64,11 @@
name: 'a-select', name: 'a-select',
vModel: 'value', vModel: 'value',
options: [ options: [
{ value: 0, label: '正常运行' }, { value: 0, label: '正常运行(证书申请任务请选择它)' },
{ value: 1, label: '成功后跳过' } { value: 1, label: '成功后跳过(其他任务请选择它)' }
] ]
}, },
helper:'该任务运行成功一次之后下次运行是否跳过,证书申请任务务必选择正常运行', helper: '该任务运行成功一次之后下次运行是否跳过,保持默认即可',
rules: [{ required: true, message: '此项必填' }] rules: [{ required: true, message: '此项必填' }]
}" }"
:get-context-fn="blankFn" :get-context-fn="blankFn"
@@ -90,10 +90,10 @@ import { message, Modal } from "ant-design-vue";
import { computed, inject, Ref, ref } from "vue"; import { computed, inject, Ref, ref } from "vue";
import _ from "lodash-es"; import _ from "lodash-es";
import { nanoid } from "nanoid"; import { nanoid } from "nanoid";
import {CopyOutlined} from "@ant-design/icons-vue"; import { CopyOutlined } from "@ant-design/icons-vue";
export default { export default {
name: "PiStepForm", name: "PiStepForm",
components:{CopyOutlined}, components: { CopyOutlined },
props: { props: {
editMode: { editMode: {
type: Boolean, type: Boolean,
@@ -173,7 +173,7 @@ export default {
stepDrawerShow(); stepDrawerShow();
}; };
const stepAdd = (emit: any,stepDef:any) => { const stepAdd = (emit: any, stepDef: any) => {
mode.value = "add"; mode.value = "add";
const step: any = { const step: any = {
id: nanoid(), id: nanoid(),
@@ -183,7 +183,7 @@ export default {
input: {}, input: {},
status: null status: null
}; };
_.merge(step,stepDef) _.merge(step, stepDef);
stepOpen(step, emit); stepOpen(step, emit);
}; };
@@ -222,6 +222,10 @@ export default {
); );
} }
} }
//设置初始值
if (input.default != null && currentStep.value.input[key] == null) {
currentStep.value.input[key] = input.default ?? input.value;
}
} }
} }

View File

@@ -3,6 +3,17 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.21.2](https://github.com/fast-crud/fast-server-js/compare/v1.21.1...v1.21.2) (2024-07-08)
**Note:** Version bump only for package @certd/ui-server
## [1.21.1](https://github.com/fast-crud/fast-server-js/compare/v1.21.0...v1.21.1) (2024-07-08)
### Performance Improvements
* 上传到主机支持设置不mkdirs ([5ba9831](https://github.com/fast-crud/fast-server-js/commit/5ba9831ed1aa6ec6057df246f1035b36b9c41d2e))
* 说明优化,默认值优化 ([970c7fd](https://github.com/fast-crud/fast-server-js/commit/970c7fd8a0f557770e973d8462ee5684ef742810))
# [1.21.0](https://github.com/fast-crud/fast-server-js/compare/v1.20.17...v1.21.0) (2024-07-03) # [1.21.0](https://github.com/fast-crud/fast-server-js/compare/v1.20.17...v1.21.0) (2024-07-03)
**Note:** Version bump only for package @certd/ui-server **Note:** Version bump only for package @certd/ui-server

View File

@@ -1,6 +1,6 @@
{ {
"name": "@certd/ui-server", "name": "@certd/ui-server",
"version": "1.21.0", "version": "1.21.2",
"description": "fast-server base midway", "description": "fast-server base midway",
"private": true, "private": true,
"scripts": { "scripts": {
@@ -24,10 +24,10 @@
"@alicloud/cs20151215": "^3.0.3", "@alicloud/cs20151215": "^3.0.3",
"@alicloud/openapi-client": "^0.4.0", "@alicloud/openapi-client": "^0.4.0",
"@alicloud/pop-core": "^1.7.10", "@alicloud/pop-core": "^1.7.10",
"@certd/acme-client": "^1.21.0", "@certd/acme-client": "^1.21.2",
"@certd/pipeline": "^1.21.0", "@certd/pipeline": "^1.21.2",
"@certd/plugin-cert": "^1.21.0", "@certd/plugin-cert": "^1.21.2",
"@certd/plugin-util": "^1.21.0", "@certd/plugin-util": "^1.21.2",
"@koa/cors": "^3.4.3", "@koa/cors": "^3.4.3",
"@midwayjs/bootstrap": "^3.15.0", "@midwayjs/bootstrap": "^3.15.0",
"@midwayjs/cache": "^3.14.0", "@midwayjs/cache": "^3.14.0",

View File

@@ -45,7 +45,7 @@ export class DeployCertToAliyunAckIngressPlugin extends AbstractTaskPlugin {
@TaskInput({ @TaskInput({
title: '大区', title: '大区',
value: 'cn-shanghai', default: 'cn-shanghai',
component: { component: {
placeholder: '集群所属大区', placeholder: '集群所属大区',
}, },
@@ -55,7 +55,7 @@ export class DeployCertToAliyunAckIngressPlugin extends AbstractTaskPlugin {
@TaskInput({ @TaskInput({
title: '命名空间', title: '命名空间',
value: 'default', default: 'default',
component: { component: {
placeholder: '命名空间', placeholder: '命名空间',
}, },
@@ -64,7 +64,7 @@ export class DeployCertToAliyunAckIngressPlugin extends AbstractTaskPlugin {
namespace!: string; namespace!: string;
@TaskInput({ @TaskInput({
title: 'ingress名称', title: 'ingress名称',
value: '', default: '',
component: { component: {
placeholder: 'ingress名称', placeholder: 'ingress名称',
}, },
@@ -74,7 +74,7 @@ export class DeployCertToAliyunAckIngressPlugin extends AbstractTaskPlugin {
ingressName!: string; ingressName!: string;
@TaskInput({ @TaskInput({
title: 'ingress类型', title: 'ingress类型',
value: 'nginx', default: 'nginx',
component: { component: {
placeholder: '暂时只支持nginx类型', placeholder: '暂时只支持nginx类型',
}, },
@@ -83,8 +83,10 @@ export class DeployCertToAliyunAckIngressPlugin extends AbstractTaskPlugin {
ingressClass!: string; ingressClass!: string;
@TaskInput({ @TaskInput({
title: '是否私网ip', title: '是否私网ip',
value: false, default: false,
component: { component: {
name: 'a-switch',
vModel: 'checked',
placeholder: '集群连接端点是否是私网ip', placeholder: '集群连接端点是否是私网ip',
}, },
helper: '如果您当前certd运行在同一个私网下可以选择是。', helper: '如果您当前certd运行在同一个私网下可以选择是。',

View File

@@ -30,7 +30,7 @@ export class UploadCertToAliyun extends AbstractTaskPlugin {
@TaskInput({ @TaskInput({
title: '大区', title: '大区',
value: 'cn-hangzhou', default: 'cn-hangzhou',
component: { component: {
name: 'a-select', name: 'a-select',
vModel: 'value', vModel: 'value',

View File

@@ -4,13 +4,13 @@ import path from 'path';
import _ from 'lodash'; import _ from 'lodash';
import { ILogger } from '@certd/pipeline'; import { ILogger } from '@certd/pipeline';
import iconv from 'iconv-lite'; import iconv from 'iconv-lite';
import {SshAccess} from "../access"; import { SshAccess } from '../access';
export class AsyncSsh2Client { export class AsyncSsh2Client {
conn: ssh2.Client; conn: ssh2.Client;
logger: ILogger; logger: ILogger;
connConf: ssh2.ConnectConfig; connConf: ssh2.ConnectConfig;
windows:boolean = false; windows = false;
encoding:string; encoding: string;
constructor(connConf: SshAccess, logger: ILogger) { constructor(connConf: SshAccess, logger: ILogger) {
this.connConf = connConf; this.connConf = connConf;
this.logger = logger; this.logger = logger;
@@ -19,7 +19,7 @@ export class AsyncSsh2Client {
} }
convert(buffer: Buffer) { convert(buffer: Buffer) {
if(this.encoding){ if (this.encoding) {
return iconv.decode(buffer, this.encoding); return iconv.decode(buffer, this.encoding);
} }
return buffer.toString(); return buffer.toString();
@@ -77,7 +77,7 @@ export class AsyncSsh2Client {
reject(err); reject(err);
return; return;
} }
let data: string = ''; let data = '';
stream stream
.on('close', (code: any, signal: any) => { .on('close', (code: any, signal: any) => {
this.logger.info(`[${this.connConf.host}][close]:code:${code}`); this.logger.info(`[${this.connConf.host}][close]:code:${code}`);
@@ -88,14 +88,16 @@ export class AsyncSsh2Client {
} }
}) })
.on('data', (ret: Buffer) => { .on('data', (ret: Buffer) => {
const out = this.convert(ret) const out = this.convert(ret);
data += out data += out;
this.logger.info(`[${this.connConf.host}][info]: ` + out.trimEnd()); this.logger.info(`[${this.connConf.host}][info]: ` + out.trimEnd());
}) })
.stderr.on('data', (ret:Buffer) => { .stderr.on('data', (ret: Buffer) => {
const err = this.convert(ret) const err = this.convert(ret);
data += err data += err;
this.logger.info(`[${this.connConf.host}][error]: ` + err.trimEnd()); this.logger.info(
`[${this.connConf.host}][error]: ` + err.trimEnd()
);
}); });
}); });
}); });
@@ -118,15 +120,15 @@ export class AsyncSsh2Client {
resolve(output); resolve(output);
}) })
.on('data', (ret: Buffer) => { .on('data', (ret: Buffer) => {
const data = this.convert(ret) const data = this.convert(ret);
this.logger.info('' + data); this.logger.info('' + data);
output.push(data); output.push(data);
}) })
.stderr.on('data', (ret:Buffer) => { .stderr.on('data', (ret: Buffer) => {
const data = this.convert(ret) const data = this.convert(ret);
output.push(data); output.push(data);
this.logger.info(`[${this.connConf.host}][error]: ` + data); this.logger.info(`[${this.connConf.host}][error]: ` + data);
}); });
stream.end(script + '\nexit\n'); stream.end(script + '\nexit\n');
}); });
}); });
@@ -153,30 +155,39 @@ export class SshClient {
} }
* @param options * @param options
*/ */
async uploadFiles(options: { connectConf: SshAccess; transports: any }) { async uploadFiles(options: {
const { connectConf, transports } = options; connectConf: SshAccess;
transports: any;
mkdirs: boolean;
}) {
const { connectConf, transports, mkdirs } = options;
await this._call({ await this._call({
connectConf, connectConf,
callable: async (conn: AsyncSsh2Client) => { callable: async (conn: AsyncSsh2Client) => {
const sftp = await conn.getSftp(); const sftp = await conn.getSftp();
this.logger.info('开始上传'); this.logger.info('开始上传');
for (const transport of transports) { for (const transport of transports) {
let filePath = path.dirname(transport.remotePath); if (mkdirs !== false) {
let mkdirCmd = `mkdir -p ${filePath} `; const filePath = path.dirname(transport.remotePath);
if(conn.windows){ let mkdirCmd = `mkdir -p ${filePath} `;
if(filePath.indexOf("/") > -1){ if (conn.windows) {
this.logger.info("--------------------------") if (filePath.indexOf('/') > -1) {
this.logger.info("请注意windows下文件目录分隔应该写成\\而不是/") this.logger.info('--------------------------');
this.logger.info("--------------------------") this.logger.info(
} '请注意windows下文件目录分隔应该写成\\而不是/'
const spec = await conn.exec(`echo %COMSPEC%`); );
if (spec.toString().trim() === '%COMSPEC%') { this.logger.info('--------------------------');
mkdirCmd = `New-Item -ItemType Directory -Path "${filePath}" -Force`; }
} else { const spec = await conn.exec('echo %COMSPEC%');
mkdirCmd = `if not exist "${filePath}" mkdir "${filePath}"`; if (spec.toString().trim() === '%COMSPEC%') {
mkdirCmd = `New-Item -ItemType Directory -Path "${filePath}" -Force`;
} else {
mkdirCmd = `if not exist "${filePath}" mkdir "${filePath}"`;
}
} }
await conn.exec(mkdirCmd);
} }
await conn.exec(mkdirCmd);
await conn.fastPut({ sftp, ...transport }); await conn.fastPut({ sftp, ...transport });
} }
this.logger.info('文件全部上传成功'); this.logger.info('文件全部上传成功');

View File

@@ -10,7 +10,7 @@ import {
import { SshClient } from '../../lib/ssh'; import { SshClient } from '../../lib/ssh';
import { CertInfo, CertReader } from '@certd/plugin-cert'; import { CertInfo, CertReader } from '@certd/plugin-cert';
import * as fs from 'fs'; import * as fs from 'fs';
import {SshAccess} from "../../access"; import { SshAccess } from '../../access';
@IsTaskPlugin({ @IsTaskPlugin({
name: 'uploadCertToHost', name: 'uploadCertToHost',
@@ -48,6 +48,7 @@ export class UploadCertToHostPlugin extends AbstractTaskPlugin {
required: true, required: true,
}) })
cert!: CertInfo; cert!: CertInfo;
@TaskInput({ @TaskInput({
title: '主机登录配置', title: '主机登录配置',
helper: 'access授权', helper: 'access授权',
@@ -59,13 +60,24 @@ export class UploadCertToHostPlugin extends AbstractTaskPlugin {
}) })
accessId!: string; accessId!: string;
@TaskInput({
title: '自动创建远程目录',
helper: '是否自动创建远程目录,如果关闭则你需要自己确保远程目录存在',
default: true,
component: {
name: 'a-switch',
vModel: 'checked',
},
})
mkdirs = true;
@TaskInput({ @TaskInput({
title: '仅复制到当前主机', title: '仅复制到当前主机',
helper: helper:
'开启后将直接复制到当前主机某个目录不上传到主机由于是docker启动实际上是复制到docker容器内的“证书保存路径”你需要事先在docker-compose.yaml中配置主机目录映射 volumes: /your_target_path:/your_target_path', '开启后将直接复制到当前主机某个目录不上传到主机由于是docker启动实际上是复制到docker容器内的“证书保存路径”你需要事先在docker-compose.yaml中配置主机目录映射 volumes: /your_target_path:/your_target_path',
default: false,
component: { component: {
name: 'a-switch', name: 'a-switch',
value: false,
vModel: 'checked', vModel: 'checked',
}, },
}) })
@@ -102,39 +114,58 @@ export class UploadCertToHostPlugin extends AbstractTaskPlugin {
this.logger.info('将证书写入本地缓存文件'); this.logger.info('将证书写入本地缓存文件');
const saveCrtPath = certReader.saveToFile('crt'); const saveCrtPath = certReader.saveToFile('crt');
const saveKeyPath = certReader.saveToFile('key'); const saveKeyPath = certReader.saveToFile('key');
this.logger.info('本地文件写入成功');
if (this.copyToThisHost) { try {
this.logger.info('复制到目标路径'); if (this.copyToThisHost) {
this.copyFile(saveCrtPath, crtPath); this.logger.info('复制到目标路径');
this.copyFile(saveKeyPath, keyPath); this.copyFile(saveCrtPath, crtPath);
this.logger.info('证书复制成功crtPath=', crtPath, ',keyPath=', keyPath); this.copyFile(saveKeyPath, keyPath);
} else { this.logger.info(
if (!accessId) { '证书复制成功crtPath=',
throw new Error('主机登录授权配置不能为空'); crtPath,
',keyPath=',
keyPath
);
} else {
if (!accessId) {
throw new Error('主机登录授权配置不能为空');
}
this.logger.info('准备上传文件到服务器');
const connectConf: SshAccess = await this.accessService.getById(
accessId
);
const sshClient = new SshClient(this.logger);
await sshClient.uploadFiles({
connectConf,
transports: [
{
localPath: saveCrtPath,
remotePath: crtPath,
},
{
localPath: saveKeyPath,
remotePath: keyPath,
},
],
mkdirs: this.mkdirs,
});
this.logger.info(
'证书上传成功crtPath=',
crtPath,
',keyPath=',
keyPath
);
} }
this.logger.info('准备上传到服务器'); } catch (e) {
const connectConf:SshAccess = await this.accessService.getById(accessId); this.logger.error(`上传失败:${e.message}`);
const sshClient = new SshClient(this.logger); throw e;
await sshClient.uploadFiles({ } finally {
connectConf, //删除临时文件
transports: [ this.logger.info('删除临时文件');
{ fs.unlinkSync(saveCrtPath);
localPath: saveCrtPath, fs.unlinkSync(saveKeyPath);
remotePath: crtPath,
},
{
localPath: saveKeyPath,
remotePath: keyPath,
},
],
});
this.logger.info('证书上传成功crtPath=', crtPath, ',keyPath=', keyPath);
} }
this.logger.info('执行完成');
//删除临时文件
fs.unlinkSync(saveCrtPath);
fs.unlinkSync(saveKeyPath);
//输出 //输出
this.hostCrtPath = crtPath; this.hostCrtPath = crtPath;
this.hostKeyPath = keyPath; this.hostKeyPath = keyPath;

View File

@@ -10,7 +10,7 @@ import { DnspodAccess } from '../access';
@IsDnsProvider({ @IsDnsProvider({
name: 'dnspod', name: 'dnspod',
title: 'dnspod(已过时)', title: 'dnspod(已过时,请尽快换成腾讯云)',
desc: '请尽快换成腾讯云类型', desc: '请尽快换成腾讯云类型',
accessType: 'dnspod', accessType: 'dnspod',
}) })

View File

@@ -24,7 +24,7 @@ import dayjs from 'dayjs';
export class DeployToClbPlugin extends AbstractTaskPlugin { export class DeployToClbPlugin extends AbstractTaskPlugin {
@TaskInput({ @TaskInput({
title: '大区', title: '大区',
value: 'ap-guangzhou', default: 'ap-guangzhou',
component: { component: {
name: 'a-select', name: 'a-select',
options: [{ value: 'ap-guangzhou' }], options: [{ value: 'ap-guangzhou' }],

13
publish-check.js Normal file
View File

@@ -0,0 +1,13 @@
import fs from 'fs'
function check(){
const gitAdd = fs.readFileSync("./node_modules/@lerna-lite/version/dist/lib/git-add.js","utf-8")
if(gitAdd.indexOf("('git', ['add', '.']") > -1){
console.log("git-add 已经修改过了")
}else{
console.error("git-add 没有修改过")
throw new Error("git-add 还没修改过")
}
}
check()

View File

@@ -2,6 +2,8 @@
本示例演示从创建证书申请任务到自动部署证书全流程 本示例演示从创建证书申请任务到自动部署证书全流程
> 申请证书->部署证书->设置定时执行->设置邮件通知
## 准备工作 ## 准备工作
1. 已部署CertD服务可官方Demo自助注册体验 https://certd.handsfree.work/ 1. 已部署CertD服务可官方Demo自助注册体验 https://certd.handsfree.work/
2. 注册一个域名支持阿里云万网、腾讯云DnsPod、华为云 2. 注册一个域名支持阿里云万网、腾讯云DnsPod、华为云