mirror of
https://github.com/certd/certd.git
synced 2026-04-04 23:10:56 +08:00
Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
031df8fc35 | ||
|
|
62419a8212 | ||
|
|
09d93af853 | ||
|
|
b6ab178de9 | ||
|
|
5a08f27d2c | ||
|
|
fe91d94090 | ||
|
|
56ab3269d2 | ||
|
|
c8243c573f | ||
|
|
0b769a1c86 | ||
|
|
a8189a974d | ||
|
|
322875d241 | ||
|
|
ed8a54a2bc | ||
|
|
5ba9831ed1 | ||
|
|
f9c9fce581 | ||
|
|
bc650a32cd | ||
|
|
c6d3e3fe5b | ||
|
|
73acc62af1 | ||
|
|
0d4491f3a0 | ||
|
|
85248044ab | ||
|
|
c532449102 | ||
|
|
970c7fd8a0 |
13
CHANGELOG.md
13
CHANGELOG.md
@@ -3,6 +3,19 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
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)
|
||||
|
||||
### Features
|
||||
|
||||
16
README.md
16
README.md
@@ -1,13 +1,15 @@
|
||||
# CertD
|
||||
|
||||
CertD 是一个免费全自动申请和部署SSL证书的工具。
|
||||
CertD 是一个免费全自动申请和自动部署更新SSL证书的工具。
|
||||
后缀D取自linux守护进程的命名风格,意为证书守护进程。
|
||||
|
||||
关键字:证书自动申请、证书自动更新、证书自动续期、证书自动续签
|
||||
|
||||
## 一、特性
|
||||
本项目不仅支持证书申请过程自动化,还可以自动化部署证书,让你的证书永不过期。
|
||||
本项目不仅支持证书申请过程自动化,还可以自动化部署更新证书,让你的证书永不过期。
|
||||
|
||||
* 全自动申请证书(支持阿里云、腾讯云、华为云、Cloudflare注册的域名)
|
||||
* 全自动部署证书(目前支持服务器上传部署、部署到阿里云、腾讯云等)
|
||||
* 全自动部署更新证书(目前支持服务器上传部署、部署到阿里云、腾讯云等)
|
||||
* 支持通配符域名
|
||||
* 支持多个域名打到一个证书上
|
||||
* 邮件通知
|
||||
@@ -108,8 +110,8 @@ http://your_server_ip:7001
|
||||
* http-01: 在网站根目录下放置一份txt文件
|
||||
* dns-01: 需要给域名添加txt解析记录,通配符域名只能用这种方式
|
||||
* 证书续期:
|
||||
* 实际上acme并没有续期概念。
|
||||
* 我们所说的续期,其实就是按照全套流程重新申请一份新证书。
|
||||
* 实际上没有办法不改变证书文件本身情况下直接续期或者续签。
|
||||
* 我们所说的续期,其实就是按照全套流程重新申请一份新证书,然后重新部署上去。
|
||||
* 免费证书过期时间90天,以后可能还会缩短,所以自动化部署必不可少
|
||||
* 设置每天自动运行,当证书过期前20天,会自动重新申请证书并部署
|
||||
|
||||
@@ -172,3 +174,7 @@ docker compose up -d
|
||||
* [袖手GPT](https://ai.handsfree.work/) ChatGPT,国内可用,无需FQ,每日免费额度
|
||||
* [fast-crud](https://gitee.com/fast-crud/fast-crud/) 基于vue3的crud快速开发框架
|
||||
* [dev-sidecar](https://github.com/docmirror/dev-sidecar/) 直连访问github工具,无需FQ,解决github无法访问的问题
|
||||
|
||||
|
||||
## 十二、版本更新日志
|
||||
https://github.com/certd/certd/blob/v2/CHANGELOG.md
|
||||
@@ -1,6 +1,5 @@
|
||||
import http from 'axios'
|
||||
import fs from 'fs'
|
||||
|
||||
//读取 packages/core/pipline/package.json的版本号
|
||||
import {default as packageJson} from './packages/core/pipeline/package.json' assert { type: "json" };
|
||||
|
||||
|
||||
@@ -9,5 +9,5 @@
|
||||
}
|
||||
},
|
||||
"npmClient": "pnpm",
|
||||
"version": "1.21.0"
|
||||
"version": "1.21.2"
|
||||
}
|
||||
|
||||
@@ -14,9 +14,10 @@
|
||||
"i-all": "lerna link && lerna exec npm install ",
|
||||
"publish": "npm run prepublishOnly1 && lerna publish --conventional-commits && npm run afterpublishOnly && npm run deploy1",
|
||||
"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\"",
|
||||
"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",
|
||||
"dependencies": {
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
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)
|
||||
|
||||
### Features
|
||||
|
||||
@@ -1 +1 @@
|
||||
01:14
|
||||
15:57
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"description": "Simple and unopinionated ACME client",
|
||||
"private": false,
|
||||
"author": "nmorsman",
|
||||
"version": "1.21.0",
|
||||
"version": "1.21.2",
|
||||
"main": "src/index.js",
|
||||
"types": "types/index.d.ts",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
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)
|
||||
|
||||
**Note:** Version bump only for package @certd/pipeline
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/pipeline",
|
||||
"private": false,
|
||||
"version": "1.21.0",
|
||||
"version": "1.21.2",
|
||||
"main": "./src/index.ts",
|
||||
"module": "./src/index.ts",
|
||||
"types": "./src/index.ts",
|
||||
@@ -23,7 +23,7 @@
|
||||
"qs": "^6.11.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@certd/acme-client": "workspace:^1.21.0",
|
||||
"@certd/acme-client": "workspace:^1.21.2",
|
||||
"@rollup/plugin-commonjs": "^23.0.4",
|
||||
"@rollup/plugin-json": "^6.0.0",
|
||||
"@rollup/plugin-node-resolve": "^15.0.1",
|
||||
|
||||
@@ -3,6 +3,18 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
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)
|
||||
|
||||
### Features
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/plugin-cert",
|
||||
"private": false,
|
||||
"version": "1.21.0",
|
||||
"version": "1.21.2",
|
||||
"main": "./src/index.ts",
|
||||
"module": "./src/index.ts",
|
||||
"types": "./src/index.ts",
|
||||
@@ -17,8 +17,8 @@
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@certd/acme-client": "workspace:^1.21.0",
|
||||
"@certd/pipeline": "workspace:^1.21.0",
|
||||
"@certd/acme-client": "workspace:^1.21.2",
|
||||
"@certd/pipeline": "workspace:^1.21.2",
|
||||
"jszip": "^3.10.1",
|
||||
"node-forge": "^0.10.0",
|
||||
"psl": "^1.9.0"
|
||||
|
||||
@@ -2,7 +2,7 @@ import { IsAccess, AccessInput } from "@certd/pipeline";
|
||||
|
||||
@IsAccess({
|
||||
name: "eab",
|
||||
title: "EABAccess",
|
||||
title: "EAB授权",
|
||||
desc: "ZeroSSL证书申请需要EAB授权",
|
||||
})
|
||||
export class EabAccess {
|
||||
|
||||
@@ -18,12 +18,20 @@ export class AcmeService {
|
||||
userContext: IContext;
|
||||
logger: Logger;
|
||||
sslProvider: SSLProvider;
|
||||
skipLocalVerify = true;
|
||||
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.logger = options.logger;
|
||||
this.sslProvider = options.sslProvider || "letsencrypt";
|
||||
this.eab = options.eab;
|
||||
this.skipLocalVerify = options.skipLocalVerify ?? false;
|
||||
acme.setLogger((text: string) => {
|
||||
this.logger.info(text);
|
||||
});
|
||||
@@ -192,7 +200,7 @@ export class AcmeService {
|
||||
csr,
|
||||
email: email,
|
||||
termsOfServiceAgreed: true,
|
||||
skipChallengeVerification: false,
|
||||
skipChallengeVerification: this.skipLocalVerify,
|
||||
challengePriority: ["dns-01"],
|
||||
challengeCreateFn: async (authz: acme.Authorization, challenge: Challenge, keyAuthorization: string): Promise<any> => {
|
||||
return await this.challengeCreateFn(authz, challenge, keyAuthorization, dnsProvider);
|
||||
|
||||
@@ -38,10 +38,10 @@ export class CertApplyPlugin extends AbstractTaskPlugin {
|
||||
span: 24,
|
||||
},
|
||||
helper:
|
||||
"支持通配符域名,例如: *.foo.com、foo.com、*.test.handsfree.work\n" +
|
||||
"支持多个域名、多个子域名、多个通配符域名打到一个证书上(域名必须是在同一个DNS提供商解析)\n" +
|
||||
"多级子域名要分成多个域名输入(*.foo.com的证书不能用于xxx.yyy.foo.com、foo.com)\n" +
|
||||
"输入一个回车之后,再输入下一个",
|
||||
"1、支持通配符域名,例如: *.foo.com、foo.com、*.test.handsfree.work\n" +
|
||||
"2、支持多个域名、多个子域名、多个通配符域名打到一个证书上(域名必须是在同一个DNS提供商解析)\n" +
|
||||
"3、多级子域名要分成多个域名输入(*.foo.com的证书不能用于xxx.yyy.foo.com、foo.com)\n" +
|
||||
"4、输入一个回车之后,再输入下一个",
|
||||
})
|
||||
domains!: string;
|
||||
|
||||
@@ -58,7 +58,7 @@ export class CertApplyPlugin extends AbstractTaskPlugin {
|
||||
|
||||
@TaskInput({
|
||||
title: "证书提供商",
|
||||
value: "letsencrypt",
|
||||
default: "letsencrypt",
|
||||
component: {
|
||||
name: "a-select",
|
||||
vModel: "value",
|
||||
@@ -109,6 +109,17 @@ export class CertApplyPlugin extends AbstractTaskPlugin {
|
||||
})
|
||||
dnsProviderAccess!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: "跳过本地校验DNS",
|
||||
default: false,
|
||||
component: {
|
||||
name: "a-switch",
|
||||
vModel: "checked",
|
||||
},
|
||||
helper: "如果重试多次出现Authorization not found TXT record,导致无法申请成功,请尝试开启此选项",
|
||||
})
|
||||
skipLocalVerify = false;
|
||||
|
||||
@TaskInput({
|
||||
title: "更新天数",
|
||||
component: {
|
||||
@@ -165,7 +176,13 @@ export class CertApplyPlugin extends AbstractTaskPlugin {
|
||||
if (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> {
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
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)
|
||||
|
||||
**Note:** Version bump only for package @certd/plugin-util
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/plugin-util",
|
||||
"private": false,
|
||||
"version": "1.21.0",
|
||||
"version": "1.21.2",
|
||||
"main": "./src/index.ts",
|
||||
"module": "./src/index.ts",
|
||||
"types": "./src/index.ts",
|
||||
@@ -21,7 +21,7 @@
|
||||
"shelljs": "^0.8.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@certd/pipeline": "workspace:^1.21.0",
|
||||
"@certd/pipeline": "workspace:^1.21.2",
|
||||
"@rollup/plugin-commonjs": "^23.0.4",
|
||||
"@rollup/plugin-json": "^6.0.0",
|
||||
"@rollup/plugin-node-resolve": "^15.0.1",
|
||||
|
||||
@@ -3,6 +3,16 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
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)
|
||||
|
||||
**Note:** Version bump only for package @certd/ui-client
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@certd/ui-client",
|
||||
"version": "1.21.0",
|
||||
"version": "1.21.2",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "vite --open",
|
||||
@@ -59,7 +59,7 @@
|
||||
"vuedraggable": "^2.24.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@certd/pipeline": "^1.21.0",
|
||||
"@certd/pipeline": "^1.21.2",
|
||||
"@rollup/plugin-commonjs": "^25.0.7",
|
||||
"@rollup/plugin-node-resolve": "^15.2.3",
|
||||
"@types/chai": "^4.3.12",
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<fs-icon class="cd-icon-button" icon="ion:close-circle-outline" @click="clear"></fs-icon>
|
||||
</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-modal v-model:open="chooseForm.show" title="选择授权提供者" width="700px" @ok="chooseForm.ok">
|
||||
<div style="height: 400px; position: relative">
|
||||
@@ -46,9 +46,9 @@ export default defineComponent({
|
||||
}
|
||||
}
|
||||
|
||||
function clear(){
|
||||
function clear() {
|
||||
selectedId.value = "";
|
||||
target.value = null
|
||||
target.value = null;
|
||||
ctx.emit("update:modelValue", selectedId.value);
|
||||
}
|
||||
|
||||
@@ -99,7 +99,6 @@ export default defineComponent({
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
return {
|
||||
clear,
|
||||
target,
|
||||
|
||||
@@ -97,7 +97,6 @@ async function changePassword() {
|
||||
const formOptions = buildFormOptions(passwordFormOptions);
|
||||
formOptions.newInstance = true; //新实例打开
|
||||
passwordFormRef.value = await openDialog(formOptions);
|
||||
debugger;
|
||||
console.log(passwordFormRef.value);
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { compute } from "@fast-crud/fast-crud";
|
||||
import { compute, CreateCrudOptionsProps, CreateCrudOptionsRet } from "@fast-crud/fast-crud";
|
||||
import { Dicts } from "./dicts";
|
||||
|
||||
export default function () {
|
||||
export default function (): CreateCrudOptionsRet {
|
||||
return {
|
||||
crudOptions: {
|
||||
form: {
|
||||
@@ -12,7 +12,7 @@ export default function () {
|
||||
columns: {
|
||||
domains: {
|
||||
title: "域名",
|
||||
type: ["dict-select"],
|
||||
type: "dict-select",
|
||||
search: {
|
||||
show: true,
|
||||
component: {
|
||||
@@ -58,6 +58,30 @@ export default function () {
|
||||
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: {
|
||||
title: "DNS提供商",
|
||||
type: "dict-select",
|
||||
@@ -1,7 +1,12 @@
|
||||
import { dict } from "@fast-crud/fast-crud";
|
||||
|
||||
export const Dicts = {
|
||||
certIssuerDict: dict({ data: [{ value: "letencrypt", label: "LetEncrypt" }] }),
|
||||
sslProviderDict: dict({
|
||||
data: [
|
||||
{ value: "letsencrypt", label: "Let‘s Encrypt" },
|
||||
{ value: "zerossl", label: "ZeroSSL" }
|
||||
]
|
||||
}),
|
||||
challengeTypeDict: dict({ data: [{ value: "dns", label: "DNS校验" }] }),
|
||||
dnsProviderTypeDict: dict({
|
||||
url: "pi/dnsProvider/dnsProviderTypeDict"
|
||||
|
||||
@@ -9,7 +9,7 @@ import { ref } from "vue";
|
||||
import _ from "lodash-es";
|
||||
export default {
|
||||
name: "PiCertdForm",
|
||||
setup(props:any, ctx:any) {
|
||||
setup(props: any, ctx: any) {
|
||||
// 自定义表单配置
|
||||
const { buildFormOptions } = useColumns();
|
||||
//使用crudOptions结构来构建自定义表单配置
|
||||
@@ -18,7 +18,7 @@ export default {
|
||||
const formOptions = buildFormOptions(
|
||||
_.merge(crudOptions, {
|
||||
form: {
|
||||
doSubmit({ form }:any) {
|
||||
doSubmit({ form }: any) {
|
||||
// 创建certd 的pipeline
|
||||
doSubmitRef.value({ form });
|
||||
}
|
||||
@@ -29,7 +29,7 @@ export default {
|
||||
const formWrapperRef = ref();
|
||||
const formWrapperOptions = ref();
|
||||
formWrapperOptions.value = formOptions;
|
||||
function open(doSubmit:any) {
|
||||
function open(doSubmit: any) {
|
||||
doSubmitRef.value = doSubmit;
|
||||
formWrapperRef.value.open(formWrapperOptions.value);
|
||||
}
|
||||
|
||||
@@ -7,6 +7,11 @@
|
||||
<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>-->
|
||||
</template>
|
||||
<template #form-bottom>
|
||||
<div>
|
||||
申请证书
|
||||
</div>
|
||||
</template>
|
||||
<pi-certd-form ref="certdFormRef"></pi-certd-form>
|
||||
</fs-crud>
|
||||
</fs-page>
|
||||
|
||||
@@ -64,11 +64,11 @@
|
||||
name: 'a-select',
|
||||
vModel: 'value',
|
||||
options: [
|
||||
{ value: 0, label: '正常运行' },
|
||||
{ value: 1, label: '成功后跳过' }
|
||||
{ value: 0, label: '正常运行(证书申请任务请选择它)' },
|
||||
{ value: 1, label: '成功后跳过(其他任务请选择它)' }
|
||||
]
|
||||
},
|
||||
helper:'该任务运行成功一次之后下次运行是否跳过,证书申请任务务必选择正常运行',
|
||||
helper: '该任务运行成功一次之后下次运行是否跳过,保持默认即可',
|
||||
rules: [{ required: true, message: '此项必填' }]
|
||||
}"
|
||||
:get-context-fn="blankFn"
|
||||
@@ -90,10 +90,10 @@ import { message, Modal } from "ant-design-vue";
|
||||
import { computed, inject, Ref, ref } from "vue";
|
||||
import _ from "lodash-es";
|
||||
import { nanoid } from "nanoid";
|
||||
import {CopyOutlined} from "@ant-design/icons-vue";
|
||||
import { CopyOutlined } from "@ant-design/icons-vue";
|
||||
export default {
|
||||
name: "PiStepForm",
|
||||
components:{CopyOutlined},
|
||||
components: { CopyOutlined },
|
||||
props: {
|
||||
editMode: {
|
||||
type: Boolean,
|
||||
@@ -173,7 +173,7 @@ export default {
|
||||
stepDrawerShow();
|
||||
};
|
||||
|
||||
const stepAdd = (emit: any,stepDef:any) => {
|
||||
const stepAdd = (emit: any, stepDef: any) => {
|
||||
mode.value = "add";
|
||||
const step: any = {
|
||||
id: nanoid(),
|
||||
@@ -183,7 +183,7 @@ export default {
|
||||
input: {},
|
||||
status: null
|
||||
};
|
||||
_.merge(step,stepDef)
|
||||
_.merge(step, stepDef);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,17 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
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)
|
||||
|
||||
**Note:** Version bump only for package @certd/ui-server
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@certd/ui-server",
|
||||
"version": "1.21.0",
|
||||
"version": "1.21.2",
|
||||
"description": "fast-server base midway",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
@@ -24,10 +24,10 @@
|
||||
"@alicloud/cs20151215": "^3.0.3",
|
||||
"@alicloud/openapi-client": "^0.4.0",
|
||||
"@alicloud/pop-core": "^1.7.10",
|
||||
"@certd/acme-client": "^1.21.0",
|
||||
"@certd/pipeline": "^1.21.0",
|
||||
"@certd/plugin-cert": "^1.21.0",
|
||||
"@certd/plugin-util": "^1.21.0",
|
||||
"@certd/acme-client": "^1.21.2",
|
||||
"@certd/pipeline": "^1.21.2",
|
||||
"@certd/plugin-cert": "^1.21.2",
|
||||
"@certd/plugin-util": "^1.21.2",
|
||||
"@koa/cors": "^3.4.3",
|
||||
"@midwayjs/bootstrap": "^3.15.0",
|
||||
"@midwayjs/cache": "^3.14.0",
|
||||
|
||||
@@ -45,7 +45,7 @@ export class DeployCertToAliyunAckIngressPlugin extends AbstractTaskPlugin {
|
||||
|
||||
@TaskInput({
|
||||
title: '大区',
|
||||
value: 'cn-shanghai',
|
||||
default: 'cn-shanghai',
|
||||
component: {
|
||||
placeholder: '集群所属大区',
|
||||
},
|
||||
@@ -55,7 +55,7 @@ export class DeployCertToAliyunAckIngressPlugin extends AbstractTaskPlugin {
|
||||
|
||||
@TaskInput({
|
||||
title: '命名空间',
|
||||
value: 'default',
|
||||
default: 'default',
|
||||
component: {
|
||||
placeholder: '命名空间',
|
||||
},
|
||||
@@ -64,7 +64,7 @@ export class DeployCertToAliyunAckIngressPlugin extends AbstractTaskPlugin {
|
||||
namespace!: string;
|
||||
@TaskInput({
|
||||
title: 'ingress名称',
|
||||
value: '',
|
||||
default: '',
|
||||
component: {
|
||||
placeholder: 'ingress名称',
|
||||
},
|
||||
@@ -74,7 +74,7 @@ export class DeployCertToAliyunAckIngressPlugin extends AbstractTaskPlugin {
|
||||
ingressName!: string;
|
||||
@TaskInput({
|
||||
title: 'ingress类型',
|
||||
value: 'nginx',
|
||||
default: 'nginx',
|
||||
component: {
|
||||
placeholder: '暂时只支持nginx类型',
|
||||
},
|
||||
@@ -83,8 +83,10 @@ export class DeployCertToAliyunAckIngressPlugin extends AbstractTaskPlugin {
|
||||
ingressClass!: string;
|
||||
@TaskInput({
|
||||
title: '是否私网ip',
|
||||
value: false,
|
||||
default: false,
|
||||
component: {
|
||||
name: 'a-switch',
|
||||
vModel: 'checked',
|
||||
placeholder: '集群连接端点是否是私网ip',
|
||||
},
|
||||
helper: '如果您当前certd运行在同一个私网下,可以选择是。',
|
||||
|
||||
@@ -30,7 +30,7 @@ export class UploadCertToAliyun extends AbstractTaskPlugin {
|
||||
|
||||
@TaskInput({
|
||||
title: '大区',
|
||||
value: 'cn-hangzhou',
|
||||
default: 'cn-hangzhou',
|
||||
component: {
|
||||
name: 'a-select',
|
||||
vModel: 'value',
|
||||
|
||||
@@ -4,13 +4,13 @@ import path from 'path';
|
||||
import _ from 'lodash';
|
||||
import { ILogger } from '@certd/pipeline';
|
||||
import iconv from 'iconv-lite';
|
||||
import {SshAccess} from "../access";
|
||||
import { SshAccess } from '../access';
|
||||
export class AsyncSsh2Client {
|
||||
conn: ssh2.Client;
|
||||
logger: ILogger;
|
||||
connConf: ssh2.ConnectConfig;
|
||||
windows:boolean = false;
|
||||
encoding:string;
|
||||
windows = false;
|
||||
encoding: string;
|
||||
constructor(connConf: SshAccess, logger: ILogger) {
|
||||
this.connConf = connConf;
|
||||
this.logger = logger;
|
||||
@@ -19,7 +19,7 @@ export class AsyncSsh2Client {
|
||||
}
|
||||
|
||||
convert(buffer: Buffer) {
|
||||
if(this.encoding){
|
||||
if (this.encoding) {
|
||||
return iconv.decode(buffer, this.encoding);
|
||||
}
|
||||
return buffer.toString();
|
||||
@@ -77,7 +77,7 @@ export class AsyncSsh2Client {
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
let data: string = '';
|
||||
let data = '';
|
||||
stream
|
||||
.on('close', (code: any, signal: any) => {
|
||||
this.logger.info(`[${this.connConf.host}][close]:code:${code}`);
|
||||
@@ -88,14 +88,16 @@ export class AsyncSsh2Client {
|
||||
}
|
||||
})
|
||||
.on('data', (ret: Buffer) => {
|
||||
const out = this.convert(ret)
|
||||
data += out
|
||||
const out = this.convert(ret);
|
||||
data += out;
|
||||
this.logger.info(`[${this.connConf.host}][info]: ` + out.trimEnd());
|
||||
})
|
||||
.stderr.on('data', (ret:Buffer) => {
|
||||
const err = this.convert(ret)
|
||||
data += err
|
||||
this.logger.info(`[${this.connConf.host}][error]: ` + err.trimEnd());
|
||||
.stderr.on('data', (ret: Buffer) => {
|
||||
const err = this.convert(ret);
|
||||
data += err;
|
||||
this.logger.info(
|
||||
`[${this.connConf.host}][error]: ` + err.trimEnd()
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -118,15 +120,15 @@ export class AsyncSsh2Client {
|
||||
resolve(output);
|
||||
})
|
||||
.on('data', (ret: Buffer) => {
|
||||
const data = this.convert(ret)
|
||||
const data = this.convert(ret);
|
||||
this.logger.info('' + data);
|
||||
output.push(data);
|
||||
})
|
||||
.stderr.on('data', (ret:Buffer) => {
|
||||
const data = this.convert(ret)
|
||||
.stderr.on('data', (ret: Buffer) => {
|
||||
const data = this.convert(ret);
|
||||
output.push(data);
|
||||
this.logger.info(`[${this.connConf.host}][error]: ` + data);
|
||||
});
|
||||
});
|
||||
stream.end(script + '\nexit\n');
|
||||
});
|
||||
});
|
||||
@@ -153,30 +155,39 @@ export class SshClient {
|
||||
}
|
||||
* @param options
|
||||
*/
|
||||
async uploadFiles(options: { connectConf: SshAccess; transports: any }) {
|
||||
const { connectConf, transports } = options;
|
||||
async uploadFiles(options: {
|
||||
connectConf: SshAccess;
|
||||
transports: any;
|
||||
mkdirs: boolean;
|
||||
}) {
|
||||
const { connectConf, transports, mkdirs } = options;
|
||||
await this._call({
|
||||
connectConf,
|
||||
callable: async (conn: AsyncSsh2Client) => {
|
||||
const sftp = await conn.getSftp();
|
||||
this.logger.info('开始上传');
|
||||
for (const transport of transports) {
|
||||
let filePath = path.dirname(transport.remotePath);
|
||||
let mkdirCmd = `mkdir -p ${filePath} `;
|
||||
if(conn.windows){
|
||||
if(filePath.indexOf("/") > -1){
|
||||
this.logger.info("--------------------------")
|
||||
this.logger.info("请注意:windows下,文件目录分隔应该写成\\而不是/")
|
||||
this.logger.info("--------------------------")
|
||||
}
|
||||
const spec = await conn.exec(`echo %COMSPEC%`);
|
||||
if (spec.toString().trim() === '%COMSPEC%') {
|
||||
mkdirCmd = `New-Item -ItemType Directory -Path "${filePath}" -Force`;
|
||||
} else {
|
||||
mkdirCmd = `if not exist "${filePath}" mkdir "${filePath}"`;
|
||||
if (mkdirs !== false) {
|
||||
const filePath = path.dirname(transport.remotePath);
|
||||
let mkdirCmd = `mkdir -p ${filePath} `;
|
||||
if (conn.windows) {
|
||||
if (filePath.indexOf('/') > -1) {
|
||||
this.logger.info('--------------------------');
|
||||
this.logger.info(
|
||||
'请注意:windows下,文件目录分隔应该写成\\而不是/'
|
||||
);
|
||||
this.logger.info('--------------------------');
|
||||
}
|
||||
const spec = await conn.exec('echo %COMSPEC%');
|
||||
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 });
|
||||
}
|
||||
this.logger.info('文件全部上传成功');
|
||||
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
import { SshClient } from '../../lib/ssh';
|
||||
import { CertInfo, CertReader } from '@certd/plugin-cert';
|
||||
import * as fs from 'fs';
|
||||
import {SshAccess} from "../../access";
|
||||
import { SshAccess } from '../../access';
|
||||
|
||||
@IsTaskPlugin({
|
||||
name: 'uploadCertToHost',
|
||||
@@ -48,6 +48,7 @@ export class UploadCertToHostPlugin extends AbstractTaskPlugin {
|
||||
required: true,
|
||||
})
|
||||
cert!: CertInfo;
|
||||
|
||||
@TaskInput({
|
||||
title: '主机登录配置',
|
||||
helper: 'access授权',
|
||||
@@ -59,13 +60,24 @@ export class UploadCertToHostPlugin extends AbstractTaskPlugin {
|
||||
})
|
||||
accessId!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: '自动创建远程目录',
|
||||
helper: '是否自动创建远程目录,如果关闭则你需要自己确保远程目录存在',
|
||||
default: true,
|
||||
component: {
|
||||
name: 'a-switch',
|
||||
vModel: 'checked',
|
||||
},
|
||||
})
|
||||
mkdirs = true;
|
||||
|
||||
@TaskInput({
|
||||
title: '仅复制到当前主机',
|
||||
helper:
|
||||
'开启后,将直接复制到当前主机某个目录,不上传到主机,由于是docker启动,实际上是复制到docker容器内的“证书保存路径”,你需要事先在docker-compose.yaml中配置主机目录映射: volumes: /your_target_path:/your_target_path',
|
||||
default: false,
|
||||
component: {
|
||||
name: 'a-switch',
|
||||
value: false,
|
||||
vModel: 'checked',
|
||||
},
|
||||
})
|
||||
@@ -102,39 +114,58 @@ export class UploadCertToHostPlugin extends AbstractTaskPlugin {
|
||||
this.logger.info('将证书写入本地缓存文件');
|
||||
const saveCrtPath = certReader.saveToFile('crt');
|
||||
const saveKeyPath = certReader.saveToFile('key');
|
||||
|
||||
if (this.copyToThisHost) {
|
||||
this.logger.info('复制到目标路径');
|
||||
this.copyFile(saveCrtPath, crtPath);
|
||||
this.copyFile(saveKeyPath, keyPath);
|
||||
this.logger.info('证书复制成功:crtPath=', crtPath, ',keyPath=', keyPath);
|
||||
} else {
|
||||
if (!accessId) {
|
||||
throw new Error('主机登录授权配置不能为空');
|
||||
this.logger.info('本地文件写入成功');
|
||||
try {
|
||||
if (this.copyToThisHost) {
|
||||
this.logger.info('复制到目标路径');
|
||||
this.copyFile(saveCrtPath, crtPath);
|
||||
this.copyFile(saveKeyPath, keyPath);
|
||||
this.logger.info(
|
||||
'证书复制成功:crtPath=',
|
||||
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('准备上传到服务器');
|
||||
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,
|
||||
},
|
||||
],
|
||||
});
|
||||
this.logger.info('证书上传成功:crtPath=', crtPath, ',keyPath=', keyPath);
|
||||
} catch (e) {
|
||||
this.logger.error(`上传失败:${e.message}`);
|
||||
throw e;
|
||||
} finally {
|
||||
//删除临时文件
|
||||
this.logger.info('删除临时文件');
|
||||
fs.unlinkSync(saveCrtPath);
|
||||
fs.unlinkSync(saveKeyPath);
|
||||
}
|
||||
|
||||
//删除临时文件
|
||||
fs.unlinkSync(saveCrtPath);
|
||||
fs.unlinkSync(saveKeyPath);
|
||||
|
||||
this.logger.info('执行完成');
|
||||
//输出
|
||||
this.hostCrtPath = crtPath;
|
||||
this.hostKeyPath = keyPath;
|
||||
|
||||
@@ -10,7 +10,7 @@ import { DnspodAccess } from '../access';
|
||||
|
||||
@IsDnsProvider({
|
||||
name: 'dnspod',
|
||||
title: 'dnspod(已过时)',
|
||||
title: 'dnspod(已过时,请尽快换成腾讯云)',
|
||||
desc: '请尽快换成腾讯云类型',
|
||||
accessType: 'dnspod',
|
||||
})
|
||||
|
||||
@@ -24,7 +24,7 @@ import dayjs from 'dayjs';
|
||||
export class DeployToClbPlugin extends AbstractTaskPlugin {
|
||||
@TaskInput({
|
||||
title: '大区',
|
||||
value: 'ap-guangzhou',
|
||||
default: 'ap-guangzhou',
|
||||
component: {
|
||||
name: 'a-select',
|
||||
options: [{ value: 'ap-guangzhou' }],
|
||||
|
||||
13
publish-check.js
Normal file
13
publish-check.js
Normal 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()
|
||||
Reference in New Issue
Block a user