Compare commits
81 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1d8515bce0 | ||
|
|
c747ffee5a | ||
|
|
7d601b45a2 | ||
|
|
8be886daf6 | ||
|
|
d471d2416d | ||
|
|
f4c00ee0b6 | ||
|
|
009c131819 | ||
|
|
b6722897a0 | ||
|
|
1b46278f86 | ||
|
|
1274f56da8 | ||
|
|
0f572f4cb3 | ||
|
|
cbe3498125 | ||
|
|
e6ab0b6864 | ||
|
|
5b3931ecb7 | ||
|
|
ddd70ab8ce | ||
|
|
ba4cc234ae | ||
|
|
3563a4cc36 | ||
|
|
0526734ca1 | ||
|
|
f4f8d45a8e | ||
|
|
b3153eed64 | ||
|
|
ba11febad6 | ||
|
|
0cea8db0f9 | ||
|
|
8b7572a9e5 | ||
|
|
dd20af4ba0 | ||
|
|
222ef2f850 | ||
|
|
b1117ed54a | ||
|
|
7ad4b55ee0 | ||
|
|
396dc34a84 | ||
|
|
9b4a31fa6a | ||
|
|
8c7f976ef5 | ||
|
|
01f61d3c73 | ||
|
|
69b4bcbd09 | ||
|
|
bb397fb8d0 | ||
|
|
17ecf05215 | ||
|
|
e340b3e6fa | ||
|
|
4ab8677173 | ||
|
|
343d803d8e | ||
|
|
c643d7edc3 | ||
|
|
a4b37d01ab | ||
|
|
a59eb0c4c7 | ||
|
|
2dcc3206e1 | ||
|
|
dc9040a68e | ||
|
|
5160b9fbd6 | ||
|
|
a2af45e1c7 | ||
|
|
0165ccbaac | ||
|
|
b817cb4a1b | ||
|
|
584378a32b | ||
|
|
6d9ef26eca | ||
|
|
1bc170b069 | ||
|
|
babd5897ae | ||
|
|
63ec5b5519 | ||
|
|
e5e468a463 | ||
|
|
ee65c9f47d | ||
|
|
f92935d93f | ||
|
|
d282045683 | ||
|
|
129bf53edc | ||
|
|
6113c388b7 | ||
|
|
764326ab16 | ||
|
|
262ad0b51c | ||
|
|
8cc2b64066 | ||
|
|
ceb4b76cdb | ||
|
|
80af1fa9e6 | ||
|
|
844fd4358c | ||
|
|
79b41954f9 | ||
|
|
5a4a7814e1 | ||
|
|
c4630aaf7b | ||
|
|
d35ad50254 | ||
|
|
b1cc6f2a9c | ||
|
|
0d94329940 | ||
|
|
04150e1c0a | ||
|
|
385757b54b | ||
|
|
ccfe922c30 | ||
|
|
b3e0546f78 | ||
|
|
aaaf8d7db3 | ||
|
|
b1b2cd088b | ||
|
|
d1ea61debc | ||
|
|
12cebea29e | ||
|
|
81a3fdbc29 | ||
|
|
fea4669d82 | ||
|
|
241f9ed383 | ||
|
|
3d06ce444c |
79
.github/workflows/build-image-for-test.yml
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
name: build-image-for-test
|
||||
on:
|
||||
push:
|
||||
branches: ['v2-dev']
|
||||
paths:
|
||||
- "build-dev.trigger"
|
||||
|
||||
# schedule:
|
||||
# - # 国际时间 19:17 执行,北京时间3:17 ↙↙↙ 改成你想要每天自动执行的时间
|
||||
# - cron: '17 19 * * *'
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build-certd-image:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: v2-dev
|
||||
|
||||
- name: get_certd_version
|
||||
id: get_certd_version
|
||||
uses: actions/github-script@v6
|
||||
with:
|
||||
result-encoding: string
|
||||
script: |
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const pnpmWorkspace = "./pnpm-workspace.yaml";
|
||||
fs.unlinkSync(pnpmWorkspace)
|
||||
const jsonFilePath = "./packages/ui/certd-server/package.json";
|
||||
const jsonContent = fs.readFileSync(jsonFilePath, 'utf-8');
|
||||
const pkg = JSON.parse(jsonContent)
|
||||
console.log("certd_version:",pkg.version);
|
||||
return pkg.version
|
||||
# - name: Use Node.js
|
||||
# uses: actions/setup-node@v4
|
||||
# with:
|
||||
# node-version: 18
|
||||
# cache: 'npm'
|
||||
# working-directory: ./packages/ui/certd-client
|
||||
- run: |
|
||||
npm install -g pnpm@8.15.7
|
||||
pnpm install
|
||||
npm run build
|
||||
working-directory: ./packages/ui/certd-client
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to aliyun container Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: registry.cn-shenzhen.aliyuncs.com
|
||||
username: ${{ secrets.aliyun_cs_username }}
|
||||
password: ${{ secrets.aliyun_cs_password }}
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.dockerhub_username }}
|
||||
password: ${{ secrets.dockerhub_password }}
|
||||
|
||||
- name: Build default platforms
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
context: ./packages/ui/
|
||||
tags: |
|
||||
registry.cn-shenzhen.aliyuncs.com/handsfree/certd-dev:latest
|
||||
greper/certd-dev:latest
|
||||
|
||||
1
.github/workflows/build-image.yml
vendored
@@ -19,6 +19,7 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
lfs: true
|
||||
|
||||
- name: get_certd_version
|
||||
id: get_certd_version
|
||||
|
||||
1
.github/workflows/deploy-demo.yml
vendored
@@ -23,6 +23,7 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: v2-dev
|
||||
- name: get_certd_version
|
||||
id: get_certd_version
|
||||
uses: actions/github-script@v6
|
||||
|
||||
1
.github/workflows/sync-to-gitee-dev.yml
vendored
@@ -16,6 +16,7 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
lfs: true
|
||||
- name: Set git user # 2. 给git命令设置用户名和邮箱,↙↙↙ 改成你的name和email
|
||||
run: |
|
||||
git config --global user.name "xiaojunnuo"
|
||||
|
||||
1
.github/workflows/sync-to-gitee.yml
vendored
@@ -16,6 +16,7 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
lfs: true
|
||||
- name: Set git user # 2. 给git命令设置用户名和邮箱,↙↙↙ 改成你的name和email
|
||||
run: |
|
||||
git config --global user.name "xiaojunnuo"
|
||||
|
||||
40
CHANGELOG.md
@@ -3,6 +3,46 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.27.1](https://github.com/certd/certd/compare/v1.27.0...v1.27.1) (2024-11-04)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复头像没有更新的bug ([9b4a31f](https://github.com/certd/certd/commit/9b4a31fa6a32b9cab2e22bd141cf96ca29120445))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 禁止页面缓存,点击tab页签可以刷新数据 ([7ad4b55](https://github.com/certd/certd/commit/7ad4b55ee000c1dd0747832b11107f32b0ffb889))
|
||||
* 优化时间选择器,自动填写分钟和秒钟 ([396dc34](https://github.com/certd/certd/commit/396dc34a841c7d016b033736afdba8366fb2d211))
|
||||
* cname 域名映射记录可读性优化 ([b1117ed](https://github.com/certd/certd/commit/b1117ed54a3ef015752999324ff72b821ef5e4b9))
|
||||
|
||||
# [1.27.0](https://github.com/certd/certd/compare/v1.26.16...v1.27.0) (2024-10-31)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复历史记录不能按名称查询的bug ([6113c38](https://github.com/certd/certd/commit/6113c388b7fc58b11ca19ff05cc1286d096c8d28))
|
||||
* pfx兼容windows server 2016 ([e5e468a](https://github.com/certd/certd/commit/e5e468a463f66d02f235de54b7c1e09ace5f1cb1))
|
||||
|
||||
### Features
|
||||
|
||||
* 首页全新改版 ([63ec5b5](https://github.com/certd/certd/commit/63ec5b5519c760a3330569c0da6dac157302a330))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 管理控制台数据统计 ([babd589](https://github.com/certd/certd/commit/babd5897ae013ff7c04ebfcbfac8a00d84dd627c))
|
||||
* 增加向导 ([6d9ef26](https://github.com/certd/certd/commit/6d9ef26ecab71d752c2c55d75aed4fb5f6c05a39))
|
||||
* lego 升级到 4.19.2 ([129bf53](https://github.com/certd/certd/commit/129bf53edc9bbb001fe49fbd7e239bd1d09cc128))
|
||||
|
||||
## [1.26.16](https://github.com/certd/certd/compare/v1.26.15...v1.26.16) (2024-10-30)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复lego No help topic for 错误 ([aaaf8d7](https://github.com/certd/certd/commit/aaaf8d7db34896cf8f2ff8f12eec1ab0cae58f0f))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 支持白山云cdn部署 ([b1b2cd0](https://github.com/certd/certd/commit/b1b2cd088b684eda764962abd61754c26a204d1c))
|
||||
* 支持华为云cdn ([81a3fdb](https://github.com/certd/certd/commit/81a3fdbc29b71f380762008cc151493ec97458f9))
|
||||
|
||||
## [1.26.15](https://github.com/certd/certd/compare/v1.26.14...v1.26.15) (2024-10-28)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
40
README.md
@@ -5,7 +5,6 @@ Certd 是一个免费全自动申请和自动部署更新SSL证书的管理系
|
||||
|
||||
关键字:证书自动申请、证书自动更新、证书自动续期、证书自动续签、证书管理工具
|
||||
|
||||
|
||||
## 一、特性
|
||||
本项目不仅支持证书申请过程自动化,还可以自动化部署更新证书,让你的证书永不过期。
|
||||
|
||||
@@ -13,7 +12,7 @@ Certd 是一个免费全自动申请和自动部署更新SSL证书的管理系
|
||||
* 全自动部署更新证书(目前支持部署到主机、部署到阿里云、腾讯云等,目前已支持30+部署插件)
|
||||
* 支持通配符域名/泛域名,支持多个域名打到一个证书上
|
||||
* 邮件通知
|
||||
* 私有化部署,保障数据安全
|
||||
* 私有化部署,数据保存本地,镜像由Github Actions构建,过程公开透明
|
||||
* 支持sqlite,postgresql数据库
|
||||
|
||||
|
||||
@@ -28,25 +27,34 @@ https://certd.handsfree.work/
|
||||
> 注意数据将不定期清理,不定期停止定时任务,生产使用请自行部署
|
||||
> 包含敏感信息,务必自己本地部署进行生产使用
|
||||
|
||||

|
||||
|
||||
## 三、使用教程
|
||||
|
||||
更多教程请访问文档网站 [certd.docmirror.cn](https://certd.docmirror.cn/)
|
||||
仅需3步,让你的证书永不过期
|
||||
|
||||
### 1. 创建证书流水线
|
||||

|
||||
|
||||
本案例演示,如何配置自动申请证书,并部署到阿里云CDN,然后快要到期前自动更新证书并重新部署
|
||||
> 添加成功后,就可以直接运行流水线申请证书了
|
||||
|
||||
### 2. 添加部署任务
|
||||
当然我们一般需要把证书部署到应用上,certd支持海量的部署插件,您可以根据自身实际情况进行选择,比如部署到Nginx、阿里云、腾讯云、K8S、CDN、宝塔、1Panel等等
|
||||
|
||||
此处演示部署证书到主机的nginx上
|
||||

|
||||
|
||||
### 3. 定时运行
|
||||

|
||||
|
||||

|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
|
||||
-------> [点我查看详细使用步骤演示](./step.md) <--------
|
||||
↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
|
||||
|
||||
当前支持的部署插件列表
|
||||

|
||||
更多教程请访问文档网站 [certd.docmirror.cn](https://certd.docmirror.cn/)
|
||||
|
||||
|
||||
|
||||
## 四、私有化部署
|
||||
|
||||
@@ -54,10 +62,10 @@ https://certd.handsfree.work/
|
||||
|
||||
您可以根据实际情况从如下方式中选择一种方式进行私有化部署:
|
||||
|
||||
1. [宝塔面板方式部署](./install/baota/)
|
||||
2. [1Panel面板方式部署](./install/1panel/)
|
||||
2. [Docker方式部署](./install/docker/)
|
||||
3. [源码方式部署](./install/source/)
|
||||
1. [宝塔面板方式部署](https://certd.docmirror.cn/guide/install/docker/)
|
||||
2. [1Panel面板方式部署](https://certd.docmirror.cn/guide/install/1panel/)
|
||||
3. [Docker方式部署](https://certd.docmirror.cn/guide/install/docker/)
|
||||
4. [源码方式部署](https://certd.docmirror.cn/guide/install/source/)
|
||||
|
||||
#### Docker镜像说明:
|
||||
* 国内镜像地址:
|
||||
@@ -164,7 +172,7 @@ https://afdian.com/a/greper
|
||||
|
||||
## 十二、 开源许可
|
||||
* 本项目遵循 GNU Affero General Public License(AGPL)开源协议。
|
||||
* 允许个人和公司使用、复制、修改和分发本项目,禁止任何形式的商业用途
|
||||
* 允许个人和公司内部自由使用、复制、修改和分发本项目,未获得商业授权情况下禁止任何形式的商业用途
|
||||
* 未获得商业授权情况下,禁止任何对logo、版权信息及授权许可相关代码的修改。
|
||||
* 如需商业授权,请联系作者。
|
||||
|
||||
|
||||
1
build-dev.trigger
Normal file
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -1 +1 @@
|
||||
02:56
|
||||
2
|
||||
|
||||
@@ -17,25 +17,22 @@ services:
|
||||
# ↓↓↓↓ ---------------------------------------------------------- 如果出现getaddrinfo ENOTFOUND等错误,可以尝试修改或注释dns配置
|
||||
- 223.5.5.5
|
||||
- 223.6.6.6
|
||||
# ↓↓↓↓ ---------------------------------------------------------- 如果你服务器在腾讯云,可以用这个dns地址
|
||||
# - 119.29.29.29
|
||||
# - 182.254.116.116
|
||||
# ↓↓↓↓ ---------------------------------------------------------- 如果你服务器部署在国外,可以用8.8.8.8替换上面的dns
|
||||
# - 8.8.8.8
|
||||
# - 8.8.4.4
|
||||
# - 8.8.8.8
|
||||
# - 8.8.4.4
|
||||
# extra_hosts:
|
||||
# ↓↓↓↓ ---------------------------------------------------------- 这里可以配置自定义hosts,外网域名可以指向本地局域网ip地址
|
||||
# - "localdomain.comm:192.168.1.3"
|
||||
environment: # 环境变量
|
||||
environment:
|
||||
- TZ=Asia/Shanghai
|
||||
# 设置环境变量即可自定义certd配置
|
||||
# 配置项见: packages/ui/certd-server/src/config/config.default.ts
|
||||
# 配置规则: certd_ + 配置项, 点号用_代替
|
||||
# ↓↓↓↓ ----------------------------- 如果忘记管理员密码,可以设置为true,重启之后,管理员密码将改成123456,然后请及时修改回false
|
||||
- certd_system_resetAdminPasswd=false
|
||||
# ↓↓↓↓ -------------------------------- 默认同时启动https,https访问地址https://your.domain:7002
|
||||
#- certd_https_key=./data/ssl/cert.key
|
||||
#- certd_https_cert=./data/ssl/cert.crt
|
||||
#- certd_https_enabled=true
|
||||
#- certd_https_port=7002
|
||||
-
|
||||
# ↓↓↓↓ ------------------------------- 使用postgresql数据库
|
||||
# - certd_flyway_scriptDir=./db/migration-pg # 升级脚本目录
|
||||
# - certd_typeorm_dataSource_default_type=postgres # 数据库类型
|
||||
|
||||
@@ -98,6 +98,8 @@ export default defineConfig({
|
||||
{ text: "忘记密码", link: "/guide/use/forgotpasswd/" },
|
||||
{ text: "数据备份", link: "/guide/use/backup/" },
|
||||
{ text: "Certd本身的证书更新", link: "/guide/use/https/index.md" },
|
||||
{ text: "js脚本插件使用", link: "/guide/use/custom-script/index.md" },
|
||||
{ text: "邮箱配置", link: "/guide/use/email/index.md" },
|
||||
{ text: "如何贡献代码", link: "/guide/development/index.md" },
|
||||
]
|
||||
},
|
||||
|
||||
@@ -7,13 +7,13 @@
|
||||
```shell
|
||||
|
||||
# 克隆代码
|
||||
git clone https://github.com/certd/certd
|
||||
git clone https://github.com/certd/certd --depth=1
|
||||
|
||||
#进入项目目录
|
||||
cd certd
|
||||
|
||||
# 切换到最新版本代码
|
||||
git checkout v1.26.7 # 这里换成最新版本号
|
||||
# 切换到最新版本代码【如果v2分支无法编译,请尝试切换到最新版tag】
|
||||
# git checkout v1.27.0 # 这里换成最新版本号
|
||||
|
||||
```
|
||||
|
||||
|
||||
@@ -28,3 +28,7 @@ Certd 是一款开源、免费、全自动申请和部署更新SSL证书的工
|
||||
* 免费证书过期时间90天,以后可能还会缩短,所以自动化部署必不可少
|
||||
* 设置每天自动运行,当证书过期前20天,会自动重新申请证书并部署
|
||||
|
||||
## 三、证书颁发机构对比
|
||||
* Let's Encrypt:申请最简单。
|
||||
* Google: 大厂光环,兼容性好,需要翻墙获取EAB。
|
||||
* ZeroSSL: 有数量限制,获取EAB无需翻墙。
|
||||
80
docs/guide/use/custom-script/index.md
Normal file
@@ -0,0 +1,80 @@
|
||||
# 自定义脚本插件
|
||||
|
||||
## 1. 介绍
|
||||
|
||||
自定义脚本插件是一个通用的插件,可以通过编写脚本来实现各种功能,例如:调用第三方API、执行系统命令、发送邮件等。
|
||||
|
||||
## 2. 使用示例
|
||||
```js
|
||||
const certPem = ctx.self.cert.crt
|
||||
const certKey = ctx.self.cert.key
|
||||
|
||||
//axios发起http请求上传证书
|
||||
const res = await ctx.http.request({
|
||||
url:"your_cert_deploy_url",
|
||||
method:"post",
|
||||
data:{
|
||||
crt : certPem,
|
||||
key : certKey
|
||||
}
|
||||
})
|
||||
ctx.logger.info("上传成功",res.data)
|
||||
|
||||
|
||||
```
|
||||
## 3. API
|
||||
下面是`ctx`对象的`typescript`类型定义
|
||||
|
||||
```ts
|
||||
|
||||
type ctx = {
|
||||
CertReader: typeof CertReader;
|
||||
self: CustomScriptPlugin;
|
||||
//流水线定义
|
||||
pipeline: Pipeline;
|
||||
//步骤定义
|
||||
step: Step;
|
||||
//日志
|
||||
logger: Logger;
|
||||
//当前步骤输入参数跟上一次执行比较是否有变化
|
||||
inputChanged: boolean;
|
||||
//授权获取服务
|
||||
accessService: IAccessService;
|
||||
//邮件服务
|
||||
emailService: IEmailService;
|
||||
//cname记录服务
|
||||
cnameProxyService: ICnameProxyService;
|
||||
//插件配置服务
|
||||
pluginConfigService: IPluginConfigService;
|
||||
//流水线上下文
|
||||
pipelineContext: IContext;
|
||||
//用户上下文
|
||||
userContext: IContext;
|
||||
//http请求客户端
|
||||
http: HttpClient; // http.request(AxiosConfig)
|
||||
//文件存储
|
||||
fileStore: FileStore;
|
||||
//上一次执行结果状态
|
||||
lastStatus?: Runnable;
|
||||
//用户取消信号
|
||||
signal: AbortSignal;
|
||||
//工具类
|
||||
utils: typeof utils;
|
||||
//用户信息
|
||||
user: UserInfo;
|
||||
}
|
||||
|
||||
type CertInfo = {
|
||||
crt:string; //fullchain证书,即 cert.pem, cert.crt
|
||||
key:string; // 私钥
|
||||
ic: string; //中间证书
|
||||
pfx: string;//PFX证书,base64编码
|
||||
der: string;//DER证书,base64编码
|
||||
}
|
||||
|
||||
type CustomScriptPlugin = {
|
||||
//可以获取证书
|
||||
cert: CertInfo
|
||||
}
|
||||
|
||||
```
|
||||
BIN
docs/guide/use/email/images/qq-0.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
docs/guide/use/email/images/qq-1.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
docs/guide/use/email/images/qq-11.png
Normal file
|
After Width: | Height: | Size: 44 KiB |
BIN
docs/guide/use/email/images/qq-2.png
Normal file
|
After Width: | Height: | Size: 70 KiB |
BIN
docs/guide/use/email/images/qq-3.png
Normal file
|
After Width: | Height: | Size: 56 KiB |
23
docs/guide/use/email/index.md
Normal file
@@ -0,0 +1,23 @@
|
||||
# 邮箱配置
|
||||
|
||||
|
||||
## 腾讯企业邮箱配置
|
||||
1. 开启smtp
|
||||

|
||||
2. 获取授权码作为密码
|
||||

|
||||

|
||||
3. 填写域名、端口和密码
|
||||

|
||||
|
||||
## QQ邮箱配置
|
||||
1. smtp配置
|
||||
```yaml
|
||||
smtp域名: smtp.qq.com
|
||||
smtp端口: 465
|
||||
密码: 授权码,获取方式见下方
|
||||
是否SSL: 是
|
||||
```
|
||||
|
||||
2. 获取授权码
|
||||

|
||||
@@ -4,7 +4,10 @@
|
||||
|
||||
## windows开启OpenSSH Server
|
||||
### 1. 安装OpenSSH Server
|
||||
请前往Microsoft官方文档查看如何开启openSSH
|
||||
|
||||
* 下载安装包安装: https://github.com/PowerShell/Win32-OpenSSH/releases OpenSSH-Win64-vxx.xx.x.msi
|
||||
|
||||
* 前往Microsoft官方文档查看如何开启openSSH,以及其他设置
|
||||
https://learn.microsoft.com/zh-cn/windows-server/administration/openssh/openssh_install_firstuse?tabs=gui#install-openssh-for-windows
|
||||
|
||||
### 2. 启动OpenSSH Server服务
|
||||
|
||||
BIN
docs/images/start/home.png
Normal file
|
After Width: | Height: | Size: 163 KiB |
@@ -28,7 +28,7 @@ features:
|
||||
- title: 多域名、泛域名打到一个证书上
|
||||
details: 支持通配符域名/泛域名,支持多个域名打到一个证书上
|
||||
- title: 多证书格式支持
|
||||
details: 支持pem、pfx、der等多种证书格式,支持Google、Letsencrypt、ZeroSSL证书颁发机构
|
||||
details: 支持pem、pfx、der、jks等多种证书格式,支持Google、Letsencrypt、ZeroSSL证书颁发机构
|
||||
- title: 支持私有化部署
|
||||
details: 保障数据安全
|
||||
- title: 多数据库支持
|
||||
|
||||
@@ -9,5 +9,5 @@
|
||||
}
|
||||
},
|
||||
"npmClient": "pnpm",
|
||||
"version": "1.26.15"
|
||||
"version": "1.27.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.27.1](https://github.com/publishlab/node-acme-client/compare/v1.27.0...v1.27.1) (2024-11-04)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
# [1.27.0](https://github.com/publishlab/node-acme-client/compare/v1.26.16...v1.27.0) (2024-10-31)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
## [1.26.16](https://github.com/publishlab/node-acme-client/compare/v1.26.15...v1.26.16) (2024-10-30)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
## [1.26.15](https://github.com/publishlab/node-acme-client/compare/v1.26.14...v1.26.15) (2024-10-28)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"description": "Simple and unopinionated ACME client",
|
||||
"private": false,
|
||||
"author": "nmorsman",
|
||||
"version": "1.26.15",
|
||||
"version": "1.27.1",
|
||||
"main": "src/index.js",
|
||||
"types": "types/index.d.ts",
|
||||
"license": "MIT",
|
||||
@@ -60,5 +60,5 @@
|
||||
"bugs": {
|
||||
"url": "https://github.com/publishlab/node-acme-client/issues"
|
||||
},
|
||||
"gitHead": "1656e912963c1efaa1477e8ded8e959db7d5aceb"
|
||||
"gitHead": "c643d7edc3721a6d2ac701a35ef600f6b6ff4b34"
|
||||
}
|
||||
|
||||
@@ -42,19 +42,26 @@ function setGlobalProxy(opts) {
|
||||
}
|
||||
|
||||
class HttpError extends Error {
|
||||
// eslint-disable-next-line constructor-super
|
||||
constructor(error) {
|
||||
super(error || error.message);
|
||||
if (!error) {
|
||||
return;
|
||||
}
|
||||
super(error.message);
|
||||
|
||||
if (error.message.indexOf('ssl3_get_record:wrong version number') >= 0) {
|
||||
this.message = 'http协议错误,服务端要求http协议,请检查是否使用了https请求';
|
||||
this.message = error.message;
|
||||
const { message } = error;
|
||||
if (message && typeof message === 'string') {
|
||||
if (message.indexOf && message.indexOf('ssl3_get_record:wrong version number') >= 0) {
|
||||
this.message = `${message}(http协议错误,服务端要求http协议,请检查是否使用了https请求)`;
|
||||
}
|
||||
else if (message.indexOf('getaddrinfo EAI_AGAIN')) {
|
||||
this.message = `${message}(无法解析域名,请检查网络连接或dns配置)`;
|
||||
}
|
||||
}
|
||||
|
||||
this.name = error.name;
|
||||
this.code = error.code;
|
||||
this.cause = error.cause;
|
||||
|
||||
if (error.response) {
|
||||
this.status = error.response.status;
|
||||
@@ -62,6 +69,9 @@ class HttpError extends Error {
|
||||
this.response = {
|
||||
data: error.response.data,
|
||||
};
|
||||
if (!this.message) {
|
||||
this.message = this.statusText;
|
||||
}
|
||||
}
|
||||
|
||||
let url = '';
|
||||
@@ -73,12 +83,18 @@ class HttpError extends Error {
|
||||
params: error.config.params,
|
||||
data: error.config.data,
|
||||
};
|
||||
url = error.config.baseURL + error.config.url;
|
||||
url = (error.config.baseURL || '') + error.config.url;
|
||||
}
|
||||
if (url) {
|
||||
this.message = `${this.message}:${url}`;
|
||||
}
|
||||
|
||||
// const { stack, cause } = error;
|
||||
delete this.cause;
|
||||
delete this.stack;
|
||||
// this.cause = cause;
|
||||
// this.stack = stack;
|
||||
delete error.stack;
|
||||
delete error.cause;
|
||||
delete error.response;
|
||||
delete error.config;
|
||||
delete error.request;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
const { readCsrDomains } = require('./crypto');
|
||||
const { log } = require('./logger');
|
||||
const { wait } = require('./wait');
|
||||
const { CancelError } = require('./error');
|
||||
|
||||
const defaultOpts = {
|
||||
csr: null,
|
||||
@@ -250,7 +251,7 @@ module.exports = async (client, userOpts) => {
|
||||
i += 1;
|
||||
log(`开始第${i}组`);
|
||||
if (opts.signal && opts.signal.aborted) {
|
||||
throw new Error('用户取消');
|
||||
throw new CancelError('用户取消');
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
@@ -114,17 +114,19 @@ instance.interceptors.response.use(null, async (error) => {
|
||||
const code = response ? `HTTP ${response.status}` : error.code;
|
||||
log(`Caught ${code}, retry attempt ${config.retryAttempt}/${retryMaxAttempts} to URL ${config.url}`);
|
||||
|
||||
const retryAfter = (retryDefaultDelay * config.retryAttempt);
|
||||
/* Attempt to parse Retry-After header, fallback to default delay */
|
||||
let retryAfter = response ? parseRetryAfterHeader(response.headers['retry-after']) : 0;
|
||||
const headerRetryAfter = response ? parseRetryAfterHeader(response.headers['retry-after']) : 0;
|
||||
|
||||
if (retryAfter > 0) {
|
||||
log(`Found retry-after response header with value: ${response.headers['retry-after']}, waiting ${retryAfter} seconds`);
|
||||
}
|
||||
else {
|
||||
retryAfter = (retryDefaultDelay * config.retryAttempt);
|
||||
log(`Unable to locate or parse retry-after response header, waiting ${retryAfter} seconds`);
|
||||
if (headerRetryAfter > 0) {
|
||||
const waitMinutes = (headerRetryAfter / 60).toFixed(1);
|
||||
log(`Found retry-after response header with value: ${response.headers['retry-after']}, waiting ${waitMinutes} minutes`);
|
||||
log(JSON.stringify(response.data));
|
||||
return Promise.reject(new Agents.HttpError(error));
|
||||
}
|
||||
|
||||
log(`waiting ${retryAfter} seconds`);
|
||||
|
||||
/* Wait and retry the request */
|
||||
await new Promise((resolve) => { setTimeout(resolve, (retryAfter * 1000)); });
|
||||
return instance(config);
|
||||
|
||||
@@ -12,6 +12,7 @@ const AcmeApi = require('./api');
|
||||
const verify = require('./verify');
|
||||
const util = require('./util');
|
||||
const auto = require('./auto');
|
||||
const { CancelError } = require('./error');
|
||||
|
||||
/**
|
||||
* ACME states
|
||||
@@ -490,9 +491,10 @@ class AcmeClient {
|
||||
|
||||
const keyAuthorization = await this.getChallengeKeyAuthorization(challenge);
|
||||
|
||||
const verifyFn = async () => {
|
||||
const verifyFn = async (abort) => {
|
||||
if (this.opts.signal && this.opts.signal.aborted) {
|
||||
throw new Error('用户取消');
|
||||
abort();
|
||||
throw new CancelError('用户取消');
|
||||
}
|
||||
await verify[challenge.type](authz, challenge, keyAuthorization);
|
||||
};
|
||||
@@ -518,7 +520,7 @@ class AcmeClient {
|
||||
|
||||
async completeChallenge(challenge) {
|
||||
if (this.opts.signal && this.opts.signal.aborted) {
|
||||
throw new Error('用户取消');
|
||||
throw new CancelError('用户取消');
|
||||
}
|
||||
const resp = await this.api.completeChallenge(challenge.url, {});
|
||||
return resp.data;
|
||||
@@ -559,7 +561,7 @@ class AcmeClient {
|
||||
const verifyFn = async (abort) => {
|
||||
if (this.opts.signal && this.opts.signal.aborted) {
|
||||
abort();
|
||||
throw new Error('用户取消');
|
||||
throw new CancelError('用户取消');
|
||||
}
|
||||
|
||||
const resp = await this.api.apiRequest(item.url, null, [200]);
|
||||
|
||||
10
packages/core/acme-client/src/error.js
Normal file
@@ -0,0 +1,10 @@
|
||||
class CancelError extends Error {
|
||||
constructor(message) {
|
||||
super(message);
|
||||
this.name = 'CancelError';
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
CancelError,
|
||||
};
|
||||
@@ -48,3 +48,4 @@ exports.agents = require('./agents');
|
||||
exports.setLogger = require('./logger').setLogger;
|
||||
|
||||
exports.walkTxtRecord = require('./verify').walkTxtRecord;
|
||||
exports.CancelError = require('./error').CancelError;
|
||||
|
||||
@@ -5,5 +5,5 @@ async function wait(ms) {
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
wait
|
||||
wait,
|
||||
};
|
||||
|
||||
4
packages/core/acme-client/types/index.d.ts
vendored
@@ -198,6 +198,8 @@ export const agents: any;
|
||||
* Logger
|
||||
*/
|
||||
|
||||
export function setLogger(fn: (msg: string) => void): void;
|
||||
export function setLogger(fn: (message: any, ...args: any[]) => void): void;
|
||||
|
||||
export function walkTxtRecord(record: any): Promise<string[]>;
|
||||
|
||||
export const CancelError: Error;
|
||||
|
||||
@@ -3,6 +3,22 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.27.1](https://github.com/certd/certd/compare/v1.27.0...v1.27.1) (2024-11-04)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* cname 域名映射记录可读性优化 ([b1117ed](https://github.com/certd/certd/commit/b1117ed54a3ef015752999324ff72b821ef5e4b9))
|
||||
|
||||
# [1.27.0](https://github.com/certd/certd/compare/v1.26.16...v1.27.0) (2024-10-31)
|
||||
|
||||
**Note:** Version bump only for package @certd/basic
|
||||
|
||||
## [1.26.16](https://github.com/certd/certd/compare/v1.26.15...v1.26.16) (2024-10-30)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 支持华为云cdn ([81a3fdb](https://github.com/certd/certd/commit/81a3fdbc29b71f380762008cc151493ec97458f9))
|
||||
|
||||
## [1.26.15](https://github.com/certd/certd/compare/v1.26.14...v1.26.15) (2024-10-28)
|
||||
|
||||
**Note:** Version bump only for package @certd/basic
|
||||
|
||||
@@ -1 +1 @@
|
||||
21:56
|
||||
21:35
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/basic",
|
||||
"private": false,
|
||||
"version": "1.26.15",
|
||||
"version": "1.27.1",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.js",
|
||||
@@ -64,5 +64,5 @@
|
||||
"vite": "^4.3.8",
|
||||
"vue-tsc": "^1.6.5"
|
||||
},
|
||||
"gitHead": "1656e912963c1efaa1477e8ded8e959db7d5aceb"
|
||||
"gitHead": "c643d7edc3721a6d2ac701a35ef600f6b6ff4b34"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export * from './util.request.js';
|
||||
export * from './util.env.js';
|
||||
export * from './util.log.js';
|
||||
export * from './util.file.js';
|
||||
export * from './util.sp.js';
|
||||
@@ -7,8 +8,8 @@ export * from './util.hash.js';
|
||||
export * from './util.merge.js';
|
||||
export * from './util.cache.js';
|
||||
import sleep from './util.sleep.js';
|
||||
import { http } from './util.request.js';
|
||||
import { nanoid } from 'nanoid';
|
||||
import { http, download } from './util.request.js';
|
||||
|
||||
import { mergeUtils } from './util.merge.js';
|
||||
import { sp } from './util.sp.js';
|
||||
import { hashUtils } from './util.hash.js';
|
||||
@@ -19,10 +20,12 @@ import { cache } from './util.cache.js';
|
||||
import dayjs from 'dayjs';
|
||||
import { domainUtils } from './util.domain.js';
|
||||
import { optionsUtils } from './util.options.js';
|
||||
|
||||
import { nanoid } from 'nanoid';
|
||||
import * as id from './util.id.js';
|
||||
export const utils = {
|
||||
sleep,
|
||||
http,
|
||||
download,
|
||||
sp,
|
||||
hash: hashUtils,
|
||||
promises,
|
||||
@@ -31,6 +34,7 @@ export const utils = {
|
||||
mergeUtils,
|
||||
cache,
|
||||
nanoid,
|
||||
id,
|
||||
dayjs,
|
||||
domain: domainUtils,
|
||||
options: optionsUtils,
|
||||
|
||||
3
packages/core/basic/src/utils/util.env.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export function isDev() {
|
||||
return process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'local';
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import crypto from "crypto";
|
||||
import crypto from 'crypto';
|
||||
|
||||
function md5(data: string) {
|
||||
return crypto.createHash("md5").update(data).digest("hex");
|
||||
return crypto.createHash('md5').update(data).digest('hex');
|
||||
}
|
||||
|
||||
export const hashUtils = {
|
||||
|
||||
3
packages/core/basic/src/utils/util.id.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import { customAlphabet } from 'nanoid';
|
||||
|
||||
export const simpleNanoId = customAlphabet('1234567890abcdefghijklmopqrstuvwxyz', 12);
|
||||
@@ -1,4 +1,4 @@
|
||||
import log4js, { LoggingEvent, Logger } from "log4js";
|
||||
import log4js, { LoggingEvent, Logger } from 'log4js';
|
||||
|
||||
const OutputAppender = {
|
||||
configure: (config: any, layouts: any, findAppender: any, levels: any) => {
|
||||
@@ -18,18 +18,22 @@ const OutputAppender = {
|
||||
},
|
||||
};
|
||||
|
||||
// @ts-ignore
|
||||
log4js.configure({
|
||||
appenders: { std: { type: "stdout" }, output: { type: OutputAppender } },
|
||||
categories: { default: { appenders: ["std"], level: "info" }, pipeline: { appenders: ["std", "output"], level: "info" } },
|
||||
});
|
||||
export const logger = log4js.getLogger("default");
|
||||
export function resetLogConfigure() {
|
||||
// @ts-ignore
|
||||
log4js.configure({
|
||||
appenders: { std: { type: 'stdout' }, output: { type: OutputAppender } },
|
||||
categories: { default: { appenders: ['std'], level: 'info' }, pipeline: { appenders: ['std', 'output'], level: 'info' } },
|
||||
});
|
||||
}
|
||||
resetLogConfigure();
|
||||
export const logger = log4js.getLogger('default');
|
||||
|
||||
export function buildLogger(write: (text: string) => void) {
|
||||
const logger = log4js.getLogger("pipeline");
|
||||
logger.addContext("outputHandler", {
|
||||
const logger = log4js.getLogger('pipeline');
|
||||
logger.addContext('outputHandler', {
|
||||
write,
|
||||
});
|
||||
return logger;
|
||||
}
|
||||
|
||||
export type ILogger = Logger;
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import axios, { AxiosRequestConfig } from 'axios';
|
||||
import { logger } from './util.log.js';
|
||||
import { ILogger, logger } from './util.log.js';
|
||||
import { Logger } from 'log4js';
|
||||
import { HttpProxyAgent } from 'http-proxy-agent';
|
||||
import { HttpsProxyAgent } from 'https-proxy-agent';
|
||||
import nodeHttp from 'http';
|
||||
import * as https from 'node:https';
|
||||
import { merge } from 'lodash-es';
|
||||
import { safePromise } from './util.promise.js';
|
||||
import fs from 'fs';
|
||||
export class HttpError extends Error {
|
||||
status?: number;
|
||||
statusText?: string;
|
||||
@@ -17,15 +19,19 @@ export class HttpError extends Error {
|
||||
if (!error) {
|
||||
return;
|
||||
}
|
||||
super(error.message);
|
||||
super(error.message || error.response?.statusText);
|
||||
|
||||
if (error?.message?.indexOf('ssl3_get_record:wrong version number') >= 0) {
|
||||
this.message = 'http协议错误,服务端要求http协议,请检查是否使用了https请求';
|
||||
const message = error?.message;
|
||||
if (message && typeof message === 'string') {
|
||||
if (message.indexOf && message.indexOf('ssl3_get_record:wrong version number') >= 0) {
|
||||
this.message = `${message}(http协议错误,服务端要求http协议,请检查是否使用了https请求)`;
|
||||
} else if (message.indexOf('getaddrinfo EAI_AGAIN')) {
|
||||
this.message = `${message}(无法解析域名,请检查网络连接或dns配置,更换docker-compose.yaml中dns配置)`;
|
||||
}
|
||||
}
|
||||
|
||||
this.name = error.name;
|
||||
this.code = error.code;
|
||||
this.cause = error.cause;
|
||||
|
||||
this.status = error.response?.status;
|
||||
this.statusText = error.response?.statusText;
|
||||
@@ -38,7 +44,7 @@ export class HttpError extends Error {
|
||||
};
|
||||
let url = error.config?.url;
|
||||
if (error.config?.baseURL) {
|
||||
url = error.config?.baseURL + url;
|
||||
url = (error.config?.baseURL || '') + url;
|
||||
}
|
||||
if (url) {
|
||||
this.message = `${this.message} : url=${url}`;
|
||||
@@ -48,6 +54,9 @@ export class HttpError extends Error {
|
||||
data: error.response?.data,
|
||||
};
|
||||
|
||||
// const { stack, cause } = error;
|
||||
// this.cause = cause;
|
||||
// this.stack = stack;
|
||||
delete error.response;
|
||||
delete error.config;
|
||||
delete error.request;
|
||||
@@ -111,7 +120,12 @@ export function createAxiosService({ logger }: { logger: Logger }) {
|
||||
service.interceptors.response.use(
|
||||
(response: any) => {
|
||||
if (response?.config?.logRes !== false) {
|
||||
logger.info(`http response : status=${response?.status},data=${JSON.stringify(response?.data)}`);
|
||||
let resData = response?.data;
|
||||
try {
|
||||
resData = JSON.stringify(response?.data);
|
||||
} catch (e) {}
|
||||
|
||||
logger.info(`http response : status=${response?.status},data=${resData}`);
|
||||
} else {
|
||||
logger.info('http response status:', response?.status);
|
||||
}
|
||||
@@ -212,3 +226,44 @@ export function createAgent(opts: CreateAgentOptions = {}) {
|
||||
httpsAgent,
|
||||
};
|
||||
}
|
||||
|
||||
export async function download(req: { http: HttpClient; config: HttpRequestConfig; savePath: string; logger: ILogger }) {
|
||||
const { http, config, savePath, logger } = req;
|
||||
return safePromise((resolve, reject) => {
|
||||
http
|
||||
.request({
|
||||
logRes: false,
|
||||
responseType: 'stream',
|
||||
...config,
|
||||
})
|
||||
.then(res => {
|
||||
const writer = fs.createWriteStream(savePath);
|
||||
res.pipe(writer);
|
||||
writer.on('close', () => {
|
||||
logger.info('文件下载成功');
|
||||
resolve(true);
|
||||
});
|
||||
//error
|
||||
writer.on('error', err => {
|
||||
logger.error('下载失败', err);
|
||||
reject(err);
|
||||
});
|
||||
//进度条打印
|
||||
const totalLength = res.headers['content-length'];
|
||||
let currentLength = 0;
|
||||
// 每5%打印一次
|
||||
const step = (totalLength / 100) * 5;
|
||||
res.on('data', (chunk: any) => {
|
||||
currentLength += chunk.length;
|
||||
if (currentLength % step < chunk.length) {
|
||||
const percent = ((currentLength / totalLength) * 100).toFixed(2);
|
||||
logger.info(`下载进度:${percent}%`);
|
||||
}
|
||||
});
|
||||
})
|
||||
.catch(err => {
|
||||
logger.info('下载失败', err);
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
//转换为import
|
||||
import childProcess from "child_process";
|
||||
import { safePromise } from "./util.promise.js";
|
||||
import { ILogger, logger } from "./util.log.js";
|
||||
|
||||
import childProcess from 'child_process';
|
||||
import { safePromise } from './util.promise.js';
|
||||
import { ILogger, logger } from './util.log.js';
|
||||
import iconv from 'iconv-lite';
|
||||
export type ExecOption = {
|
||||
cmd: string | string[];
|
||||
env: any;
|
||||
@@ -11,12 +11,12 @@ export type ExecOption = {
|
||||
};
|
||||
|
||||
async function exec(opts: ExecOption): Promise<string> {
|
||||
let cmd = "";
|
||||
let cmd = '';
|
||||
const log = opts.logger || logger;
|
||||
if (opts.cmd instanceof Array) {
|
||||
for (const item of opts.cmd) {
|
||||
if (cmd) {
|
||||
cmd += " && " + item;
|
||||
cmd += ' && ' + item;
|
||||
} else {
|
||||
cmd = item;
|
||||
}
|
||||
@@ -38,7 +38,7 @@ async function exec(opts: ExecOption): Promise<string> {
|
||||
log.error(`exec error: ${error}`);
|
||||
reject(error);
|
||||
} else {
|
||||
const res = stdout.toString("utf-8");
|
||||
const res = stdout.toString('utf-8');
|
||||
log.info(`stdout: ${res}`);
|
||||
resolve(res);
|
||||
}
|
||||
@@ -55,13 +55,31 @@ export type SpawnOption = {
|
||||
logger?: ILogger;
|
||||
options?: any;
|
||||
};
|
||||
|
||||
function isWindows() {
|
||||
return process.platform === 'win32';
|
||||
}
|
||||
function convert(buffer: any) {
|
||||
if (isWindows()) {
|
||||
const decoded = iconv.decode(buffer, 'GBK');
|
||||
// 检查是否有有效字符
|
||||
return decoded && decoded.trim().length > 0 ? decoded : buffer.toString();
|
||||
} else {
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
|
||||
// function convert(buffer: any) {
|
||||
// return buffer;
|
||||
// }
|
||||
|
||||
async function spawn(opts: SpawnOption): Promise<string> {
|
||||
let cmd = "";
|
||||
let cmd = '';
|
||||
const log = opts.logger || logger;
|
||||
if (opts.cmd instanceof Array) {
|
||||
for (const item of opts.cmd) {
|
||||
if (cmd) {
|
||||
cmd += " && " + item;
|
||||
cmd += ' && ' + item;
|
||||
} else {
|
||||
cmd = item;
|
||||
}
|
||||
@@ -70,8 +88,8 @@ async function spawn(opts: SpawnOption): Promise<string> {
|
||||
cmd = opts.cmd;
|
||||
}
|
||||
log.info(`执行命令: ${cmd}`);
|
||||
let stdout = "";
|
||||
let stderr = "";
|
||||
let stdout = '';
|
||||
let stderr = '';
|
||||
return safePromise((resolve, reject) => {
|
||||
const ls = childProcess.spawn(cmd, {
|
||||
shell: true,
|
||||
@@ -81,21 +99,23 @@ async function spawn(opts: SpawnOption): Promise<string> {
|
||||
},
|
||||
...opts.options,
|
||||
});
|
||||
ls.stdout.on("data", (data) => {
|
||||
ls.stdout.on('data', data => {
|
||||
data = convert(data);
|
||||
log.info(`stdout: ${data}`);
|
||||
stdout += data;
|
||||
});
|
||||
|
||||
ls.stderr.on("data", (data) => {
|
||||
log.error(`stderr: ${data}`);
|
||||
ls.stderr.on('data', data => {
|
||||
data = convert(data);
|
||||
log.warn(`stderr: ${data}`);
|
||||
stderr += data;
|
||||
});
|
||||
ls.on("error", (error) => {
|
||||
ls.on('error', error => {
|
||||
log.error(`child process error: ${error}`);
|
||||
reject(error);
|
||||
});
|
||||
|
||||
ls.on("close", (code: number) => {
|
||||
ls.on('close', (code: number) => {
|
||||
if (code !== 0) {
|
||||
log.error(`child process exited with code ${code}`);
|
||||
reject(new Error(stderr));
|
||||
|
||||
@@ -3,6 +3,22 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.27.1](https://github.com/certd/certd/compare/v1.27.0...v1.27.1) (2024-11-04)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 优化时间选择器,自动填写分钟和秒钟 ([396dc34](https://github.com/certd/certd/commit/396dc34a841c7d016b033736afdba8366fb2d211))
|
||||
|
||||
# [1.27.0](https://github.com/certd/certd/compare/v1.26.16...v1.27.0) (2024-10-31)
|
||||
|
||||
**Note:** Version bump only for package @certd/pipeline
|
||||
|
||||
## [1.26.16](https://github.com/certd/certd/compare/v1.26.15...v1.26.16) (2024-10-30)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 支持白山云cdn部署 ([b1b2cd0](https://github.com/certd/certd/commit/b1b2cd088b684eda764962abd61754c26a204d1c))
|
||||
|
||||
## [1.26.15](https://github.com/certd/certd/compare/v1.26.14...v1.26.15) (2024-10-28)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
{
|
||||
"name": "@certd/pipeline",
|
||||
"private": false,
|
||||
"version": "1.26.15",
|
||||
"version": "1.27.1",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
@@ -15,8 +16,8 @@
|
||||
"test": "mocha --loader=ts-node/esm"
|
||||
},
|
||||
"dependencies": {
|
||||
"@certd/basic": "^1.26.15",
|
||||
"@certd/plus-core": "^1.26.15",
|
||||
"@certd/basic": "^1.27.1",
|
||||
"@certd/plus-core": "^1.27.1",
|
||||
"axios": "^1.7.2",
|
||||
"dayjs": "^1.11.7",
|
||||
"fix-path": "^4.0.0",
|
||||
@@ -66,5 +67,5 @@
|
||||
"vite": "^4.3.8",
|
||||
"vue-tsc": "^1.6.5"
|
||||
},
|
||||
"gitHead": "1656e912963c1efaa1477e8ded8e959db7d5aceb"
|
||||
"gitHead": "c643d7edc3721a6d2ac701a35ef600f6b6ff4b34"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Registrable } from "../registry/index.js";
|
||||
import { FormItemProps } from "../dt/index.js";
|
||||
import { HttpClient, ILogger, utils } from "../utils/index.js";
|
||||
import { HttpClient, ILogger, utils } from "@certd/basic";
|
||||
import _ from "lodash-es";
|
||||
import { AccessRequestHandleReq } from "../core";
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import { AccessContext, AccessDefine, AccessInputDefine } from "./api.js";
|
||||
import { Decorator } from "../decorator/index.js";
|
||||
import _ from "lodash-es";
|
||||
import { accessRegistry } from "./registry.js";
|
||||
import { http, logger, utils } from "../utils/index.js";
|
||||
import { http, logger, utils } from "@certd/basic";
|
||||
|
||||
// 提供一个唯一 key
|
||||
export const ACCESS_CLASS_KEY = "pipeline:access";
|
||||
|
||||
5
packages/core/pipeline/src/core/exceptions.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export class CancelError extends Error {
|
||||
constructor(message: string) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@ import { RunHistory, RunnableCollection } from "./run-history.js";
|
||||
import { AbstractTaskPlugin, PluginDefine, pluginRegistry, TaskInstanceContext, UserInfo } from "../plugin/index.js";
|
||||
import { ContextFactory, IContext } from "./context.js";
|
||||
import { IStorage } from "./storage.js";
|
||||
import { createAxiosService, hashUtils, logger, utils } from "../utils/index.js";
|
||||
import { createAxiosService, hashUtils, HttpRequestConfig, logger, utils } from "@certd/basic";
|
||||
import { Logger } from "log4js";
|
||||
import { IAccessService } from "../access/index.js";
|
||||
import { RegistryItem } from "../registry/index.js";
|
||||
@@ -135,7 +135,12 @@ export class Executor {
|
||||
this.runtime.success(runnable);
|
||||
return ResultType.success;
|
||||
} catch (e: any) {
|
||||
this.runtime.error(runnable, e);
|
||||
if (e.name === "CancelError" || this.abort.signal.aborted) {
|
||||
this.runtime.cancel(runnable);
|
||||
return ResultType.canceled;
|
||||
} else {
|
||||
this.runtime.error(runnable, e);
|
||||
}
|
||||
throw e;
|
||||
} finally {
|
||||
this.runtime.finally(runnable);
|
||||
@@ -285,11 +290,20 @@ export class Executor {
|
||||
}
|
||||
|
||||
const http = createAxiosService({ logger: currentLogger });
|
||||
const download = async (config: HttpRequestConfig, savePath: string) => {
|
||||
await utils.download({
|
||||
http,
|
||||
logger: currentLogger,
|
||||
config,
|
||||
savePath,
|
||||
});
|
||||
};
|
||||
const taskCtx: TaskInstanceContext = {
|
||||
pipeline: this.pipeline,
|
||||
step,
|
||||
lastStatus,
|
||||
http,
|
||||
download,
|
||||
logger: currentLogger,
|
||||
inputChanged,
|
||||
accessService: this.options.accessService,
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { fileUtils } from "../utils/index.js";
|
||||
import { fileUtils } from "@certd/basic";
|
||||
import dayjs from "dayjs";
|
||||
import path from "path";
|
||||
import fs from "fs";
|
||||
import { logger } from "../utils/index.js";
|
||||
import { logger } from "@certd/basic";
|
||||
|
||||
export type FileStoreOptions = {
|
||||
rootDir?: string;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { HttpClient, ILogger, utils } from "../utils/index.js";
|
||||
import { HttpClient, ILogger, utils } from "@certd/basic";
|
||||
|
||||
export type PluginRequestHandleReq<T = any> = {
|
||||
typeName: string;
|
||||
|
||||
@@ -3,5 +3,5 @@ export * from "./run-history.js";
|
||||
export * from "./context.js";
|
||||
export * from "./storage.js";
|
||||
export * from "./file-store.js";
|
||||
export * from "./license.js";
|
||||
export * from "./handler.js";
|
||||
export * from "./exceptions.js";
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
import { logger } from "../utils/index.js";
|
||||
import { setLogger, isPlus, isComm } from "@certd/plus-core";
|
||||
setLogger(logger);
|
||||
export * from "@certd/plus-core";
|
||||
|
||||
export function checkPlus() {
|
||||
if (!isPlus()) {
|
||||
throw new Error("此为专业版功能,请升级到专业版");
|
||||
}
|
||||
}
|
||||
|
||||
export function checkComm() {
|
||||
if (!isComm()) {
|
||||
throw new Error("此为商业版功能,请升级到商业版");
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import { HistoryResult, Pipeline, ResultType, Runnable, RunnableMap, Stage, Step, Task } from "../dt/index.js";
|
||||
import _ from "lodash-es";
|
||||
import { buildLogger } from "../utils/index.js";
|
||||
import { buildLogger } from "@certd/basic";
|
||||
import { Logger } from "log4js";
|
||||
|
||||
export type HistoryStatus = {
|
||||
@@ -117,7 +117,8 @@ export class RunHistory {
|
||||
}
|
||||
|
||||
logError(runnable: Runnable, e: Error) {
|
||||
// @ts-ignore
|
||||
// delete e.stack;
|
||||
// delete e.cause;
|
||||
const errorInfo = runnable.runnableType === "step" ? e : e.message;
|
||||
this._loggers[runnable.id].error(`[${runnable.runnableType}] [${runnable.title}]<id:${runnable.id}> :`, errorInfo);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import { fileUtils } from "../utils/index.js";
|
||||
import { fileUtils } from "@certd/basic";
|
||||
|
||||
export interface IStorage {
|
||||
get(scope: string, namespace: string, version: string, key: string): Promise<string | null>;
|
||||
|
||||
@@ -1,115 +0,0 @@
|
||||
/**
|
||||
* [x]-col的配置
|
||||
*/
|
||||
export type ColProps = {
|
||||
span?: number;
|
||||
[props: string]: any;
|
||||
};
|
||||
|
||||
export type FormItemProps = {
|
||||
/**
|
||||
* 字段label
|
||||
*/
|
||||
title?: string;
|
||||
/**
|
||||
* 表单字段组件配置
|
||||
*/
|
||||
component?: ComponentProps;
|
||||
/**
|
||||
* 表单字段 [a|el|n]-col的配置
|
||||
* 一般用来配置跨列:{span:24} 占满一行
|
||||
*/
|
||||
col?: ColProps;
|
||||
/**
|
||||
* 默认值
|
||||
*/
|
||||
value?: any;
|
||||
/**
|
||||
* 帮助提示配置
|
||||
*/
|
||||
helper?: string | FormItemHelperProps;
|
||||
/**
|
||||
* 排序号
|
||||
*/
|
||||
order?: number;
|
||||
/**
|
||||
* 是否显示此字段
|
||||
*/
|
||||
show?: boolean;
|
||||
/**
|
||||
* 是否是空白占位栏
|
||||
*/
|
||||
blank?: boolean;
|
||||
|
||||
[key: string]: any;
|
||||
};
|
||||
|
||||
/**
|
||||
* 表单字段帮助说明配置
|
||||
*/
|
||||
export type FormItemHelperProps = {
|
||||
/**
|
||||
* 自定义渲染帮助说明
|
||||
* @param scope
|
||||
*/
|
||||
render?: (scope: any) => any;
|
||||
/**
|
||||
* 帮助文本
|
||||
*/
|
||||
text?: string;
|
||||
/**
|
||||
* 帮助说明所在的位置,[ undefined | label]
|
||||
*/
|
||||
position?: string;
|
||||
/**
|
||||
* [a|el|n]-tooltip配置
|
||||
*/
|
||||
tooltip?: object;
|
||||
|
||||
[key: string]: any;
|
||||
};
|
||||
|
||||
/**
|
||||
* 组件配置
|
||||
*/
|
||||
export type ComponentProps = {
|
||||
/**
|
||||
* 组件的名称
|
||||
*/
|
||||
name?: string | object;
|
||||
/**
|
||||
* vmodel绑定的目标属性名
|
||||
*/
|
||||
vModel?: string;
|
||||
|
||||
/**
|
||||
* 当原始组件名的参数被以上属性名占用时,可以配置在这里
|
||||
* 例如:原始组件有一个叫name的属性,你想要配置它,则可以按如下配置
|
||||
* ```
|
||||
* component:{
|
||||
* name:"组件的名称"
|
||||
* props:{
|
||||
* name:"组件的name属性" <-----------
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
props?: {
|
||||
[key: string]: any;
|
||||
};
|
||||
|
||||
/**
|
||||
* 组件事件监听
|
||||
*/
|
||||
on?: {
|
||||
[key: string]: (context?: any) => void;
|
||||
};
|
||||
|
||||
/**
|
||||
* 组件其他参数
|
||||
* 事件:onXxx:(event)=>void 组件原始事件监听
|
||||
* on.onXxx:(context)=>void 组件事件监听(对原始事件包装)
|
||||
* 样式:style、class等
|
||||
*/
|
||||
[key: string]: any;
|
||||
};
|
||||
@@ -1,2 +0,0 @@
|
||||
export * from "./pipeline";
|
||||
export * from "./fast-crud";
|
||||
@@ -1,140 +0,0 @@
|
||||
export enum RunStrategy {
|
||||
AlwaysRun,
|
||||
SkipWhenSucceed,
|
||||
}
|
||||
|
||||
export enum ConcurrencyStrategy {
|
||||
Serial,
|
||||
Parallel,
|
||||
}
|
||||
|
||||
export enum NextStrategy {
|
||||
AllSuccess,
|
||||
OneSuccess,
|
||||
}
|
||||
|
||||
export enum HandlerType {
|
||||
//清空后续任务的状态
|
||||
ClearFollowStatus,
|
||||
SendEmail,
|
||||
}
|
||||
|
||||
export type EventHandler = {
|
||||
type: HandlerType;
|
||||
params: {
|
||||
[key: string]: any;
|
||||
};
|
||||
};
|
||||
|
||||
export type RunnableStrategy = {
|
||||
runStrategy?: RunStrategy;
|
||||
onSuccess?: EventHandler[];
|
||||
onError?: EventHandler[];
|
||||
};
|
||||
|
||||
export type Step = Runnable & {
|
||||
type: string; //插件类型
|
||||
input: {
|
||||
[key: string]: any;
|
||||
};
|
||||
};
|
||||
export type Task = Runnable & {
|
||||
steps: Step[];
|
||||
};
|
||||
|
||||
export type Stage = Runnable & {
|
||||
tasks: Task[];
|
||||
concurrency: ConcurrencyStrategy;
|
||||
next: NextStrategy;
|
||||
};
|
||||
|
||||
export type Trigger = {
|
||||
id: string;
|
||||
title: string;
|
||||
cron: string;
|
||||
type: string;
|
||||
};
|
||||
|
||||
export type FileItem = {
|
||||
id: string;
|
||||
filename: string;
|
||||
path: string;
|
||||
};
|
||||
export type Runnable = {
|
||||
id: string;
|
||||
title: string;
|
||||
strategy?: RunnableStrategy;
|
||||
runnableType?: string; // pipeline, stage, task , step
|
||||
status?: HistoryResult;
|
||||
timeout?: number;
|
||||
default?: {
|
||||
[key: string]: any;
|
||||
};
|
||||
context?: Context;
|
||||
};
|
||||
|
||||
export type EmailOptions = {
|
||||
receivers: string[];
|
||||
};
|
||||
export type NotificationWhen = "error" | "success" | "turnToSuccess" | "start";
|
||||
export type NotificationType = "email" | "url";
|
||||
export type Notification = {
|
||||
type: NotificationType;
|
||||
when: NotificationWhen[];
|
||||
options: EmailOptions;
|
||||
};
|
||||
|
||||
export type Pipeline = Runnable & {
|
||||
version?: number;
|
||||
userId: any;
|
||||
stages: Stage[];
|
||||
triggers: Trigger[];
|
||||
notifications?: Notification[];
|
||||
};
|
||||
|
||||
export type Context = {
|
||||
[key: string]: any;
|
||||
};
|
||||
|
||||
export type Log = {
|
||||
title: string;
|
||||
time: number;
|
||||
level: string;
|
||||
text: string;
|
||||
};
|
||||
|
||||
export enum ResultType {
|
||||
start = "start",
|
||||
success = "success",
|
||||
error = "error",
|
||||
canceled = "canceled",
|
||||
skip = "skip",
|
||||
none = "none",
|
||||
}
|
||||
|
||||
export type HistoryResultGroup = {
|
||||
[key: string]: {
|
||||
runnable: Runnable;
|
||||
res: HistoryResult;
|
||||
};
|
||||
};
|
||||
export type HistoryResult = {
|
||||
input: any;
|
||||
output: any;
|
||||
files?: FileItem[];
|
||||
/**
|
||||
* 任务状态
|
||||
*/
|
||||
status: ResultType;
|
||||
startTime: number;
|
||||
endTime?: number;
|
||||
/**
|
||||
* 处理结果
|
||||
*/
|
||||
result?: ResultType; //success, error,skip
|
||||
message?: string;
|
||||
};
|
||||
|
||||
export type RunnableMap = {
|
||||
[id: string]: Runnable;
|
||||
};
|
||||
@@ -3,7 +3,6 @@ export * from "./dt/index.js";
|
||||
export * from "./access/index.js";
|
||||
export * from "./registry/index.js";
|
||||
export * from "./plugin/index.js";
|
||||
export * from "./utils/index.js";
|
||||
export * from "./context/index.js";
|
||||
export * from "./decorator/index.js";
|
||||
export * from "./service/index.js";
|
||||
|
||||
@@ -4,9 +4,9 @@ import { FileStore } from "../core/file-store.js";
|
||||
import { Logger } from "log4js";
|
||||
import { IAccessService } from "../access/index.js";
|
||||
import { ICnameProxyService, IEmailService } from "../service/index.js";
|
||||
import { IContext, PluginRequestHandleReq, RunnableCollection } from "../core/index.js";
|
||||
import { ILogger, logger, utils } from "../utils/index.js";
|
||||
import { HttpClient } from "../utils/index.js";
|
||||
import { CancelError, IContext, PluginRequestHandleReq, RunnableCollection } from "../core/index.js";
|
||||
import { HttpRequestConfig, ILogger, logger, utils } from "@certd/basic";
|
||||
import { HttpClient } from "@certd/basic";
|
||||
import dayjs from "dayjs";
|
||||
import { IPluginConfigService } from "../service/config";
|
||||
import { upperFirst } from "lodash-es";
|
||||
@@ -85,6 +85,8 @@ export type TaskInstanceContext = {
|
||||
userContext: IContext;
|
||||
//http请求客户端
|
||||
http: HttpClient;
|
||||
//下载文件方法
|
||||
download: (config: HttpRequestConfig, savePath: string) => Promise<void>;
|
||||
//文件存储
|
||||
fileStore: FileStore;
|
||||
//上一次执行结果状态
|
||||
@@ -113,7 +115,7 @@ export abstract class AbstractTaskPlugin implements ITaskPlugin {
|
||||
|
||||
checkSignal() {
|
||||
if (this.ctx.signal && this.ctx.signal.aborted) {
|
||||
throw new Error("用户取消");
|
||||
throw new CancelError("用户取消");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,7 +125,7 @@ export abstract class AbstractTaskPlugin implements ITaskPlugin {
|
||||
this.accessService = ctx.accessService;
|
||||
}
|
||||
|
||||
async getAccess(accessId: string) {
|
||||
async getAccess<T = any>(accessId: string) {
|
||||
if (accessId == null) {
|
||||
throw new Error("您还没有配置授权");
|
||||
}
|
||||
@@ -131,7 +133,7 @@ export abstract class AbstractTaskPlugin implements ITaskPlugin {
|
||||
if (res == null) {
|
||||
throw new Error("授权不存在,可能已被删除,请前往任务配置里面重新选择授权");
|
||||
}
|
||||
return res;
|
||||
return res as T;
|
||||
}
|
||||
|
||||
randomFileId() {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { logger } from "../utils/index.js";
|
||||
import { isDev, logger } from "@certd/basic";
|
||||
|
||||
export type Registrable = {
|
||||
name: string;
|
||||
@@ -71,6 +71,9 @@ export class Registry<T> {
|
||||
if (define?.deprecated) {
|
||||
continue;
|
||||
}
|
||||
if (!isDev() && define.name.startsWith("demo")) {
|
||||
continue;
|
||||
}
|
||||
list.push({ ...define, key });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
export * from "@certd/basic";
|
||||
@@ -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.27.1](https://github.com/certd/certd/compare/v1.27.0...v1.27.1) (2024-11-04)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-huawei
|
||||
|
||||
# [1.27.0](https://github.com/certd/certd/compare/v1.26.16...v1.27.0) (2024-10-31)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-huawei
|
||||
|
||||
## [1.26.16](https://github.com/certd/certd/compare/v1.26.15...v1.26.16) (2024-10-30)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-huawei
|
||||
|
||||
## [1.26.15](https://github.com/certd/certd/compare/v1.26.14...v1.26.15) (2024-10-28)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-huawei
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/lib-huawei",
|
||||
"private": false,
|
||||
"version": "1.26.15",
|
||||
"version": "1.27.1",
|
||||
"main": "./dist/bundle.js",
|
||||
"module": "./dist/bundle.js",
|
||||
"types": "./dist/d/index.d.ts",
|
||||
@@ -17,5 +17,5 @@
|
||||
"rimraf": "^5.0.5",
|
||||
"rollup": "^3.7.4"
|
||||
},
|
||||
"gitHead": "1656e912963c1efaa1477e8ded8e959db7d5aceb"
|
||||
"gitHead": "c643d7edc3721a6d2ac701a35ef600f6b6ff4b34"
|
||||
}
|
||||
|
||||
@@ -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.27.1](https://github.com/certd/certd/compare/v1.27.0...v1.27.1) (2024-11-04)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-iframe
|
||||
|
||||
# [1.27.0](https://github.com/certd/certd/compare/v1.26.16...v1.27.0) (2024-10-31)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-iframe
|
||||
|
||||
## [1.26.16](https://github.com/certd/certd/compare/v1.26.15...v1.26.16) (2024-10-30)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-iframe
|
||||
|
||||
## [1.26.15](https://github.com/certd/certd/compare/v1.26.14...v1.26.15) (2024-10-28)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-iframe
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/lib-iframe",
|
||||
"private": false,
|
||||
"version": "1.26.15",
|
||||
"version": "1.27.1",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
@@ -39,5 +39,5 @@
|
||||
"tslib": "^2.5.2",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "1656e912963c1efaa1477e8ded8e959db7d5aceb"
|
||||
"gitHead": "c643d7edc3721a6d2ac701a35ef600f6b6ff4b34"
|
||||
}
|
||||
|
||||
@@ -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.27.1](https://github.com/certd/certd/compare/v1.27.0...v1.27.1) (2024-11-04)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-jdcloud
|
||||
|
||||
# [1.27.0](https://github.com/certd/certd/compare/v1.26.16...v1.27.0) (2024-10-31)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-jdcloud
|
||||
|
||||
## [1.26.16](https://github.com/certd/certd/compare/v1.26.15...v1.26.16) (2024-10-30)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-jdcloud
|
||||
|
||||
## [1.26.15](https://github.com/certd/certd/compare/v1.26.14...v1.26.15) (2024-10-28)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-jdcloud
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/lib-jdcloud",
|
||||
"private": false,
|
||||
"version": "1.26.15",
|
||||
"version": "1.27.1",
|
||||
"main": "./dist/bundle.mjs",
|
||||
"module": "./dist/bundle.mjs",
|
||||
"types": "./dist/d/index.d.ts",
|
||||
@@ -27,5 +27,5 @@
|
||||
"rimraf": "^5.0.5",
|
||||
"rollup": "^3.7.4"
|
||||
},
|
||||
"gitHead": "1656e912963c1efaa1477e8ded8e959db7d5aceb"
|
||||
"gitHead": "c643d7edc3721a6d2ac701a35ef600f6b6ff4b34"
|
||||
}
|
||||
|
||||
@@ -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.27.1](https://github.com/certd/certd/compare/v1.27.0...v1.27.1) (2024-11-04)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-k8s
|
||||
|
||||
# [1.27.0](https://github.com/certd/certd/compare/v1.26.16...v1.27.0) (2024-10-31)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-k8s
|
||||
|
||||
## [1.26.16](https://github.com/certd/certd/compare/v1.26.15...v1.26.16) (2024-10-30)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-k8s
|
||||
|
||||
## [1.26.15](https://github.com/certd/certd/compare/v1.26.14...v1.26.15) (2024-10-28)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-k8s
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/lib-k8s",
|
||||
"private": false,
|
||||
"version": "1.26.15",
|
||||
"version": "1.27.1",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
@@ -18,7 +18,7 @@
|
||||
"@kubernetes/client-node": "0.21.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@certd/pipeline": "^1.26.15",
|
||||
"@certd/basic": "^1.27.1",
|
||||
"@rollup/plugin-commonjs": "^23.0.4",
|
||||
"@rollup/plugin-json": "^6.0.0",
|
||||
"@rollup/plugin-node-resolve": "^15.0.1",
|
||||
@@ -40,5 +40,5 @@
|
||||
"tslib": "^2.5.2",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "1656e912963c1efaa1477e8ded8e959db7d5aceb"
|
||||
"gitHead": "c643d7edc3721a6d2ac701a35ef600f6b6ff4b34"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { CoreV1Api, KubeConfig, NetworkingV1Api, V1Ingress, V1Secret } from '@kubernetes/client-node';
|
||||
import dns from 'dns';
|
||||
import { ILogger } from '@certd/pipeline';
|
||||
import { ILogger } from '@certd/basic';
|
||||
import _ from 'lodash-es';
|
||||
|
||||
export type K8sClientOpts = {
|
||||
|
||||
@@ -3,6 +3,20 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.27.1](https://github.com/certd/certd/compare/v1.27.0...v1.27.1) (2024-11-04)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* cname 域名映射记录可读性优化 ([b1117ed](https://github.com/certd/certd/commit/b1117ed54a3ef015752999324ff72b821ef5e4b9))
|
||||
|
||||
# [1.27.0](https://github.com/certd/certd/compare/v1.26.16...v1.27.0) (2024-10-31)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-server
|
||||
|
||||
## [1.26.16](https://github.com/certd/certd/compare/v1.26.15...v1.26.16) (2024-10-30)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-server
|
||||
|
||||
## [1.26.15](https://github.com/certd/certd/compare/v1.26.14...v1.26.15) (2024-10-28)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-server
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@certd/lib-server",
|
||||
"version": "1.26.15",
|
||||
"version": "1.27.1",
|
||||
"description": "midway with flyway, sql upgrade way ",
|
||||
"private": false,
|
||||
"type": "module",
|
||||
@@ -26,9 +26,10 @@
|
||||
],
|
||||
"license": "AGPL",
|
||||
"dependencies": {
|
||||
"@certd/acme-client": "^1.26.15",
|
||||
"@certd/basic": "^1.26.15",
|
||||
"@certd/pipeline": "^1.26.15",
|
||||
"@certd/acme-client": "^1.27.1",
|
||||
"@certd/basic": "^1.27.1",
|
||||
"@certd/pipeline": "^1.27.1",
|
||||
"@certd/plus-core": "^1.27.1",
|
||||
"@midwayjs/cache": "~3.14.0",
|
||||
"@midwayjs/core": "~3.17.1",
|
||||
"@midwayjs/i18n": "~3.17.3",
|
||||
@@ -69,5 +70,5 @@
|
||||
"typeorm": "^0.3.11",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "1656e912963c1efaa1477e8ded8e959db7d5aceb"
|
||||
"gitHead": "c643d7edc3721a6d2ac701a35ef600f6b6ff4b34"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { IMidwayContainer } from '@midwayjs/core';
|
||||
import { Configuration } from '@midwayjs/core';
|
||||
import { logger } from '@certd/pipeline';
|
||||
import { logger } from '@certd/basic';
|
||||
@Configuration({
|
||||
namespace: 'lib-server',
|
||||
})
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Provide, Scope, ScopeEnum } from '@midwayjs/core';
|
||||
import dayjs from 'dayjs';
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
import { cache, logger, utils } from '@certd/pipeline';
|
||||
import { cache, logger, utils } from '@certd/basic';
|
||||
import { NotFoundException, ParamException, PermissionException } from '../../../basic/index.js';
|
||||
|
||||
export type UploadFileItem = {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Config, Inject, Provide, Scope, ScopeEnum } from '@midwayjs/core';
|
||||
import { AppKey, PlusRequestService, verify } from '@certd/pipeline';
|
||||
import { AppKey, PlusRequestService, verify } from '@certd/plus-core';
|
||||
import { logger } from '@certd/basic';
|
||||
import { SysInstallInfo, SysLicenseInfo, SysSettingsService } from '../../settings/index.js';
|
||||
|
||||
@@ -12,13 +12,18 @@ export class PlusService {
|
||||
plusServerBaseUrls: string[];
|
||||
|
||||
async getPlusRequestService() {
|
||||
const installInfo: SysInstallInfo = await this.sysSettingsService.getSetting(SysInstallInfo);
|
||||
const subjectId = await this.getSubjectId();
|
||||
return new PlusRequestService({
|
||||
plusServerBaseUrls: this.plusServerBaseUrls,
|
||||
subjectId: installInfo.siteId,
|
||||
subjectId,
|
||||
});
|
||||
}
|
||||
|
||||
async getSubjectId() {
|
||||
const installInfo: SysInstallInfo = await this.sysSettingsService.getSetting(SysInstallInfo);
|
||||
return installInfo.siteId;
|
||||
}
|
||||
|
||||
async requestWithoutSign(config: any) {
|
||||
const plusRequestService = await this.getPlusRequestService();
|
||||
return await plusRequestService.requestWithoutSign(config);
|
||||
|
||||
@@ -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.27.1](https://github.com/certd/certd/compare/v1.27.0...v1.27.1) (2024-11-04)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
# [1.27.0](https://github.com/certd/certd/compare/v1.26.16...v1.27.0) (2024-10-31)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
## [1.26.16](https://github.com/certd/certd/compare/v1.26.15...v1.26.16) (2024-10-30)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
## [1.26.15](https://github.com/certd/certd/compare/v1.26.14...v1.26.15) (2024-10-28)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@certd/midway-flyway-js",
|
||||
"version": "1.26.15",
|
||||
"version": "1.27.1",
|
||||
"description": "midway with flyway, sql upgrade way ",
|
||||
"private": false,
|
||||
"type": "module",
|
||||
@@ -56,5 +56,5 @@
|
||||
"typeorm": "^0.3.11",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "1656e912963c1efaa1477e8ded8e959db7d5aceb"
|
||||
"gitHead": "c643d7edc3721a6d2ac701a35ef600f6b6ff4b34"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,30 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.27.1](https://github.com/certd/certd/compare/v1.27.0...v1.27.1) (2024-11-04)
|
||||
|
||||
**Note:** Version bump only for package @certd/plugin-cert
|
||||
|
||||
# [1.27.0](https://github.com/certd/certd/compare/v1.26.16...v1.27.0) (2024-10-31)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* pfx兼容windows server 2016 ([e5e468a](https://github.com/certd/certd/commit/e5e468a463f66d02f235de54b7c1e09ace5f1cb1))
|
||||
|
||||
### Features
|
||||
|
||||
* 首页全新改版 ([63ec5b5](https://github.com/certd/certd/commit/63ec5b5519c760a3330569c0da6dac157302a330))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* lego 升级到 4.19.2 ([129bf53](https://github.com/certd/certd/commit/129bf53edc9bbb001fe49fbd7e239bd1d09cc128))
|
||||
|
||||
## [1.26.16](https://github.com/certd/certd/compare/v1.26.15...v1.26.16) (2024-10-30)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复lego No help topic for 错误 ([aaaf8d7](https://github.com/certd/certd/commit/aaaf8d7db34896cf8f2ff8f12eec1ab0cae58f0f))
|
||||
|
||||
## [1.26.15](https://github.com/certd/certd/compare/v1.26.14...v1.26.15) (2024-10-28)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/plugin-cert",
|
||||
"private": false,
|
||||
"version": "1.26.15",
|
||||
"version": "1.27.1",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
@@ -15,9 +15,9 @@
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@certd/acme-client": "^1.26.15",
|
||||
"@certd/basic": "^1.26.15",
|
||||
"@certd/pipeline": "^1.26.15",
|
||||
"@certd/acme-client": "^1.27.1",
|
||||
"@certd/basic": "^1.27.1",
|
||||
"@certd/pipeline": "^1.27.1",
|
||||
"@google-cloud/publicca": "^1.3.0",
|
||||
"dayjs": "^1.11.7",
|
||||
"jszip": "^3.10.1",
|
||||
@@ -57,5 +57,5 @@
|
||||
"vite": "^3.1.0",
|
||||
"vue-tsc": "^0.38.9"
|
||||
},
|
||||
"gitHead": "1656e912963c1efaa1477e8ded8e959db7d5aceb"
|
||||
"gitHead": "c643d7edc3721a6d2ac701a35ef600f6b6ff4b34"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { HttpClient, IAccess, ILogger, Registrable, utils } from "@certd/pipeline";
|
||||
import { HttpClient, ILogger, utils } from "@certd/basic";
|
||||
import { IAccess, Registrable } from "@certd/pipeline";
|
||||
|
||||
export type DnsProviderDefine = Registrable & {
|
||||
accessType: string;
|
||||
|
||||
@@ -4,7 +4,8 @@ import { ClientExternalAccountBindingOptions, UrlMapping } from "@certd/acme-cli
|
||||
import _ from "lodash-es";
|
||||
import { Challenge } from "@certd/acme-client/types/rfc8555";
|
||||
import { Logger } from "log4js";
|
||||
import { IContext, utils } from "@certd/pipeline";
|
||||
import { IContext } from "@certd/pipeline";
|
||||
import { utils } from "@certd/basic";
|
||||
import { IDnsProvider, parseDomain } from "../../dns-provider/index.js";
|
||||
|
||||
export type CnameVerifyPlan = {
|
||||
@@ -30,6 +31,7 @@ export type CertInfo = {
|
||||
ic?: string;
|
||||
pfx?: string;
|
||||
der?: string;
|
||||
jks?: string;
|
||||
};
|
||||
export type SSLProvider = "letsencrypt" | "google" | "zerossl";
|
||||
export type PrivateKeyType = "rsa_1024" | "rsa_2048" | "rsa_3072" | "rsa_4096" | "ec_256" | "ec_384" | "ec_521";
|
||||
@@ -59,8 +61,8 @@ export class AcmeService {
|
||||
this.sslProvider = options.sslProvider || "letsencrypt";
|
||||
this.eab = options.eab;
|
||||
this.skipLocalVerify = options.skipLocalVerify ?? false;
|
||||
acme.setLogger((text: string) => {
|
||||
this.logger.info(text);
|
||||
acme.setLogger((message: any, ...args: any[]) => {
|
||||
this.logger.info(message, ...args);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { AbstractTaskPlugin, HttpClient, IContext, Step, TaskInput, TaskOutput } from "@certd/pipeline";
|
||||
import { AbstractTaskPlugin, IContext, Step, TaskInput, TaskOutput } from "@certd/pipeline";
|
||||
import dayjs from "dayjs";
|
||||
import type { CertInfo } from "./acme.js";
|
||||
import { CertReader } from "./cert-reader.js";
|
||||
@@ -6,6 +6,7 @@ import JSZip from "jszip";
|
||||
import { CertConverter } from "./convert.js";
|
||||
import fs from "fs";
|
||||
import { pick } from "lodash-es";
|
||||
import { HttpClient } from "@certd/basic";
|
||||
|
||||
export { CertReader };
|
||||
export type { CertInfo };
|
||||
@@ -55,7 +56,8 @@ export abstract class CertApplyBasePlugin extends AbstractTaskPlugin {
|
||||
},
|
||||
required: false,
|
||||
order: 100,
|
||||
helper: "PFX格式证书是否需要加密",
|
||||
// helper: "PFX、jks格式证书是否加密;jks必须设置密码,不传则默认123456",
|
||||
helper: "PFX证书是否加密",
|
||||
})
|
||||
pfxPassword!: string;
|
||||
|
||||
@@ -157,14 +159,28 @@ export abstract class CertApplyBasePlugin extends AbstractTaskPlugin {
|
||||
cert,
|
||||
pfxPassword: this.pfxPassword,
|
||||
});
|
||||
const pfxBuffer = fs.readFileSync(res.pfxPath);
|
||||
cert.pfx = pfxBuffer.toString("base64");
|
||||
if (res.pfxPath) {
|
||||
const pfxBuffer = fs.readFileSync(res.pfxPath);
|
||||
cert.pfx = pfxBuffer.toString("base64");
|
||||
fs.unlinkSync(res.pfxPath);
|
||||
isNew = true;
|
||||
}
|
||||
|
||||
const derBuffer = fs.readFileSync(res.derPath);
|
||||
cert.der = derBuffer.toString("base64");
|
||||
if (res.derPath) {
|
||||
const derBuffer = fs.readFileSync(res.derPath);
|
||||
cert.der = derBuffer.toString("base64");
|
||||
fs.unlinkSync(res.derPath);
|
||||
isNew = true;
|
||||
}
|
||||
|
||||
if (res.jksPath) {
|
||||
const jksBuffer = fs.readFileSync(res.jksPath);
|
||||
cert.jks = jksBuffer.toString("base64");
|
||||
fs.unlinkSync(res.jksPath);
|
||||
isNew = true;
|
||||
}
|
||||
|
||||
this.logger.info("转换证书格式成功");
|
||||
isNew = true;
|
||||
} catch (e) {
|
||||
this.logger.error("转换证书格式失败", e);
|
||||
}
|
||||
@@ -186,12 +202,16 @@ export abstract class CertApplyBasePlugin extends AbstractTaskPlugin {
|
||||
zip.file("cert.crt", cert.crt);
|
||||
zip.file("cert.key", cert.key);
|
||||
zip.file("intermediate.crt", cert.ic);
|
||||
|
||||
if (cert.pfx) {
|
||||
zip.file("cert.pfx", Buffer.from(cert.pfx, "base64"));
|
||||
}
|
||||
if (cert.der) {
|
||||
zip.file("cert.der", Buffer.from(cert.der, "base64"));
|
||||
}
|
||||
if (cert.jks) {
|
||||
zip.file("cert.jks", Buffer.from(cert.jks, "base64"));
|
||||
}
|
||||
const content = await zip.generateAsync({ type: "nodebuffer" });
|
||||
this.saveFile(filename, content);
|
||||
this.logger.info(`已保存文件:${filename}`);
|
||||
|
||||
@@ -3,7 +3,7 @@ import fs from "fs";
|
||||
import os from "os";
|
||||
import path from "path";
|
||||
import { crypto } from "@certd/acme-client";
|
||||
import { ILogger } from "@certd/pipeline";
|
||||
import { ILogger } from "@certd/basic";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
export type CertReaderHandleContext = {
|
||||
@@ -13,6 +13,7 @@ export type CertReaderHandleContext = {
|
||||
tmpPfxPath?: string;
|
||||
tmpDerPath?: string;
|
||||
tmpIcPath?: string;
|
||||
tmpJksPath?: string;
|
||||
};
|
||||
export type CertReaderHandle = (ctx: CertReaderHandleContext) => Promise<void>;
|
||||
export type HandleOpts = { logger: ILogger; handle: CertReaderHandle };
|
||||
@@ -72,14 +73,14 @@ export class CertReader {
|
||||
return domains;
|
||||
}
|
||||
|
||||
saveToFile(type: "crt" | "key" | "pfx" | "der" | "ic", filepath?: string) {
|
||||
saveToFile(type: "crt" | "key" | "pfx" | "der" | "ic" | "jks", filepath?: string) {
|
||||
if (!this.cert[type]) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (filepath == null) {
|
||||
//写入临时目录
|
||||
filepath = path.join(os.tmpdir(), "/certd/tmp/", Math.floor(Math.random() * 1000000) + "", `cert.${type}`);
|
||||
filepath = path.join(os.tmpdir(), "/certd/tmp/", Math.floor(Math.random() * 1000000) + `_cert.${type}`);
|
||||
}
|
||||
|
||||
const dir = path.dirname(filepath);
|
||||
@@ -103,6 +104,7 @@ export class CertReader {
|
||||
const tmpIcPath = this.saveToFile("ic");
|
||||
logger.info("本地文件写入成功");
|
||||
const tmpDerPath = this.saveToFile("der");
|
||||
const tmpJksPath = this.saveToFile("jks");
|
||||
try {
|
||||
return await opts.handle({
|
||||
reader: this,
|
||||
@@ -111,6 +113,7 @@ export class CertReader {
|
||||
tmpPfxPath: tmpPfxPath,
|
||||
tmpDerPath: tmpDerPath,
|
||||
tmpIcPath: tmpIcPath,
|
||||
tmpJksPath: tmpJksPath,
|
||||
});
|
||||
} catch (err) {
|
||||
throw err;
|
||||
@@ -127,6 +130,7 @@ export class CertReader {
|
||||
removeFile(tmpPfxPath);
|
||||
removeFile(tmpDerPath);
|
||||
removeFile(tmpIcPath);
|
||||
removeFile(tmpJksPath);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ILogger, sp } from "@certd/pipeline";
|
||||
import { ILogger, sp } from "@certd/basic";
|
||||
import type { CertInfo } from "../cert-plugin/acme.js";
|
||||
import { CertReader, CertReaderHandleContext } from "../cert-plugin/cert-reader.js";
|
||||
import path from "path";
|
||||
@@ -17,16 +17,20 @@ export class CertConverter {
|
||||
async convert(opts: { cert: CertInfo; pfxPassword: string }): Promise<{
|
||||
pfxPath: string;
|
||||
derPath: string;
|
||||
jksPath: string;
|
||||
}> {
|
||||
const certReader = new CertReader(opts.cert);
|
||||
let pfxPath: string;
|
||||
let derPath: string;
|
||||
let jksPath: string;
|
||||
const handle = async (ctx: CertReaderHandleContext) => {
|
||||
// 调用openssl 转pfx
|
||||
pfxPath = await this.convertPfx(ctx, opts.pfxPassword);
|
||||
|
||||
// 转der
|
||||
derPath = await this.convertDer(ctx);
|
||||
|
||||
//jksPath = await this.convertJks(ctx, opts.pfxPassword);
|
||||
};
|
||||
|
||||
await certReader.readCertFile({ logger: this.logger, handle });
|
||||
@@ -34,10 +38,12 @@ export class CertConverter {
|
||||
return {
|
||||
pfxPath,
|
||||
derPath,
|
||||
jksPath,
|
||||
};
|
||||
}
|
||||
|
||||
async exec(cmd: string) {
|
||||
process.env.LANG = "zh_CN.GBK";
|
||||
await sp.spawn({
|
||||
cmd: cmd,
|
||||
logger: this.logger,
|
||||
@@ -47,7 +53,7 @@ export class CertConverter {
|
||||
private async convertPfx(opts: CertReaderHandleContext, pfxPassword: string) {
|
||||
const { tmpCrtPath, tmpKeyPath } = opts;
|
||||
|
||||
const pfxPath = path.join(os.tmpdir(), "/certd/tmp/", Math.floor(Math.random() * 1000000) + "", "cert.pfx");
|
||||
const pfxPath = path.join(os.tmpdir(), "/certd/tmp/", Math.floor(Math.random() * 1000000) + "_cert.pfx");
|
||||
|
||||
const dir = path.dirname(pfxPath);
|
||||
if (!fs.existsSync(dir)) {
|
||||
@@ -58,7 +64,10 @@ export class CertConverter {
|
||||
if (pfxPassword) {
|
||||
passwordArg = `-password pass:${pfxPassword}`;
|
||||
}
|
||||
await this.exec(`openssl pkcs12 -export -out ${pfxPath} -inkey ${tmpKeyPath} -in ${tmpCrtPath} ${passwordArg}`);
|
||||
// 兼容server 2016,旧版本不能用sha256
|
||||
const oldPfxCmd = `openssl pkcs12 -macalg SHA1 -keypbe PBE-SHA1-3DES -certpbe PBE-SHA1-3DES -export -out ${pfxPath} -inkey ${tmpKeyPath} -in ${tmpCrtPath} ${passwordArg}`;
|
||||
// const newPfx = `openssl pkcs12 -export -out ${pfxPath} -inkey ${tmpKeyPath} -in ${tmpCrtPath} ${passwordArg}`;
|
||||
await this.exec(oldPfxCmd);
|
||||
return pfxPath;
|
||||
// const fileBuffer = fs.readFileSync(pfxPath);
|
||||
// this.pfxCert = fileBuffer.toString("base64");
|
||||
@@ -70,7 +79,7 @@ export class CertConverter {
|
||||
|
||||
private async convertDer(opts: CertReaderHandleContext) {
|
||||
const { tmpCrtPath } = opts;
|
||||
const derPath = path.join(os.tmpdir(), "/certd/tmp/", Math.floor(Math.random() * 1000000) + "", `cert.der`);
|
||||
const derPath = path.join(os.tmpdir(), "/certd/tmp/", Math.floor(Math.random() * 1000000) + `_cert.der`);
|
||||
|
||||
const dir = path.dirname(derPath);
|
||||
if (!fs.existsSync(dir)) {
|
||||
@@ -88,4 +97,33 @@ export class CertConverter {
|
||||
// const filename = reader.buildCertFileName("der", applyTime);
|
||||
// this.saveFile(filename, fileBuffer);
|
||||
}
|
||||
|
||||
async convertJks(opts: CertReaderHandleContext, pfxPassword = "") {
|
||||
const jksPassword = pfxPassword || "123456";
|
||||
try {
|
||||
const randomStr = Math.floor(Math.random() * 1000000) + "";
|
||||
|
||||
const p12Path = path.join(os.tmpdir(), "/certd/tmp/", randomStr + `_cert.p12`);
|
||||
const { tmpCrtPath, tmpKeyPath } = opts;
|
||||
let passwordArg = "-passout pass:";
|
||||
if (pfxPassword) {
|
||||
passwordArg = `-password pass:${pfxPassword}`;
|
||||
}
|
||||
await this.exec(`openssl pkcs12 -export -in ${tmpCrtPath} -inkey ${tmpKeyPath} -out ${p12Path} -name certd ${passwordArg}`);
|
||||
|
||||
const jksPath = path.join(os.tmpdir(), "/certd/tmp/", randomStr + `_cert.jks`);
|
||||
const dir = path.dirname(jksPath);
|
||||
if (!fs.existsSync(dir)) {
|
||||
fs.mkdirSync(dir, { recursive: true });
|
||||
}
|
||||
await this.exec(
|
||||
`keytool -importkeystore -srckeystore ${p12Path} -srcstoretype PKCS12 -srcstorepass "${pfxPassword}" -destkeystore ${jksPath} -deststoretype PKCS12 -deststorepass "${jksPassword}" `
|
||||
);
|
||||
fs.unlinkSync(p12Path);
|
||||
return jksPath;
|
||||
} catch (e) {
|
||||
this.logger.error("转换jks失败", e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { IsTaskPlugin, pluginGroups, RunStrategy, TaskInput, utils } from "@certd/pipeline";
|
||||
import { IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from "@certd/pipeline";
|
||||
import { utils } from "@certd/basic";
|
||||
|
||||
import type { CertInfo, CnameVerifyPlan, DomainsVerifyPlan, PrivateKeyType, SSLProvider } from "./acme.js";
|
||||
import { AcmeService } from "./acme.js";
|
||||
import _ from "lodash-es";
|
||||
@@ -7,6 +9,7 @@ import { CertReader } from "./cert-reader.js";
|
||||
import { CertApplyBasePlugin } from "./base.js";
|
||||
import { GoogleClient } from "../../libs/google.js";
|
||||
import { EabAccess } from "../../access";
|
||||
import { CancelError } from "@certd/pipeline";
|
||||
|
||||
export type { CertInfo };
|
||||
export * from "./cert-reader.js";
|
||||
@@ -55,12 +58,12 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
|
||||
},
|
||||
required: true,
|
||||
helper:
|
||||
"DNS直接验证:适合域名是在阿里云、腾讯云、华为云、Cloudflare、西数注册的,需要提供Access授权信息。\nCNAME代理验证:支持任何注册商注册的域名,并且不需要提供Access授权信息,但第一次需要手动添加CNAME记录",
|
||||
"DNS直接验证:域名是在阿里云、腾讯云、华为云、Cloudflare、西数注册的,选它。\nCNAME代理验证:支持任何注册商注册的域名,但第一次需要手动添加CNAME记录",
|
||||
})
|
||||
challengeType!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: "DNS提供商",
|
||||
title: "DNS解析服务商",
|
||||
component: {
|
||||
name: "dns-provider-selector",
|
||||
},
|
||||
@@ -72,7 +75,7 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
|
||||
}
|
||||
`,
|
||||
required: true,
|
||||
helper: "请选择dns解析提供商,您的域名是在哪里注册的,或者域名的dns解析服务器属于哪个平台\n如果这里没有您需要的dns解析提供商,请选择CNAME代理验证校验方式",
|
||||
helper: "您的域名注册商,或者域名的dns服务器属于哪个平台\n如果这里没有,请选择CNAME代理验证校验方式",
|
||||
})
|
||||
dnsProviderType!: string;
|
||||
|
||||
@@ -82,7 +85,7 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
|
||||
name: "access-selector",
|
||||
},
|
||||
required: true,
|
||||
helper: "请选择dns解析提供商授权",
|
||||
helper: "请选择dns解析服务商授权",
|
||||
mergeScript: `return {
|
||||
component:{
|
||||
type: ctx.compute(({form})=>{
|
||||
@@ -134,7 +137,7 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
|
||||
{ value: "zerossl", label: "ZeroSSL" },
|
||||
],
|
||||
},
|
||||
helper: "Let's Encrypt最简单,如果使用ZeroSSL、Google证书,需要提供EAB授权",
|
||||
helper: "Let's Encrypt:申请最简单\nGoogle:大厂光环,兼容性好,需要翻墙获取EAB授权\nZeroSSL:有数量限制,获取EAB授权无需翻墙",
|
||||
required: true,
|
||||
})
|
||||
sslProvider!: SSLProvider;
|
||||
@@ -293,6 +296,7 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
|
||||
useMappingProxy: this.useProxy,
|
||||
reverseProxy: this.reverseProxy,
|
||||
privateKeyType: this.privateKeyType,
|
||||
signal: this.ctx.signal,
|
||||
// cnameProxyService: this.ctx.cnameProxyService,
|
||||
// dnsProviderCreator: this.createDnsProvider.bind(this),
|
||||
});
|
||||
@@ -347,6 +351,9 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
|
||||
this.logger.error(e);
|
||||
throw new Error(`通配符域名已经包含了普通域名,请删除其中一个(${message})`);
|
||||
}
|
||||
if (e.name === "CancelError") {
|
||||
throw new CancelError(e.message);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { IsTaskPlugin, pluginGroups, RunStrategy, sp, Step, TaskInput } from "@certd/pipeline";
|
||||
import { IsTaskPlugin, pluginGroups, RunStrategy, Step, TaskInput } from "@certd/pipeline";
|
||||
import type { CertInfo } from "../acme.js";
|
||||
import { CertReader } from "../cert-reader.js";
|
||||
import { CertApplyBasePlugin } from "../base.js";
|
||||
import fs from "fs";
|
||||
import { EabAccess } from "../../../access/index.js";
|
||||
import path from "path";
|
||||
import JSZip from "jszip";
|
||||
|
||||
export { CertReader };
|
||||
export type { CertInfo };
|
||||
@@ -118,14 +119,63 @@ export class CertApplyLegoPlugin extends CertApplyBasePlugin {
|
||||
this.logger.info(`环境变量:${JSON.stringify(env)}`);
|
||||
let eabArgs = "";
|
||||
if (this.eab) {
|
||||
eabArgs = ` --eab "${this.eab.kid}" --kid "${this.eab.kid}" --hmac "${this.eab.hmacKey}"`;
|
||||
eabArgs = ` --eab --kid "${this.eab.kid}" --hmac "${this.eab.hmacKey}"`;
|
||||
}
|
||||
const keyType = "-k rsa2048";
|
||||
|
||||
const saveDir = `./data/.lego/pipeline_${this.pipeline.id}/`;
|
||||
const savePathArgs = `--path "${saveDir}"`;
|
||||
const os_type = process.platform === "win32" ? "windows" : "linux";
|
||||
const legoPath = path.resolve("./tools", os_type, "lego");
|
||||
const legoDir = "./tools/lego";
|
||||
const legoPath = path.resolve(legoDir, os_type === "windows" ? "lego.exe" : "lego");
|
||||
if (!fs.existsSync(legoPath)) {
|
||||
//解压缩
|
||||
const arch = process.arch;
|
||||
let platform = "amd64";
|
||||
if (arch === "arm64" || arch === "arm") {
|
||||
platform = "arm64";
|
||||
}
|
||||
const LEGO_VERSION = process.env.LEGO_VERSION;
|
||||
let legoZipFileName = `lego_v${LEGO_VERSION}_windows_${platform}.zip`;
|
||||
if (os_type === "linux") {
|
||||
legoZipFileName = `lego_v${LEGO_VERSION}_linux_${platform}.tar.gz`;
|
||||
}
|
||||
const legoZipFilePath = `${legoDir}/${legoZipFileName}`;
|
||||
if (!fs.existsSync(legoZipFilePath)) {
|
||||
this.logger.info(`lego文件不存在:${legoZipFilePath},准备下载`);
|
||||
const downloadUrl = `https://github.com/go-acme/lego/releases/download/v${LEGO_VERSION}/${legoZipFileName}`;
|
||||
await this.ctx.download(
|
||||
{
|
||||
url: downloadUrl,
|
||||
method: "GET",
|
||||
logRes: false,
|
||||
},
|
||||
legoZipFilePath
|
||||
);
|
||||
this.logger.info("下载lego成功");
|
||||
}
|
||||
|
||||
if (os_type === "linux") {
|
||||
//tar是否存在
|
||||
await this.ctx.utils.sp.spawn({
|
||||
cmd: `tar -zxvf ${legoZipFilePath} -C ${legoDir}/`,
|
||||
});
|
||||
await this.ctx.utils.sp.spawn({
|
||||
cmd: `chmod +x ${legoDir}/*`,
|
||||
});
|
||||
this.logger.info("解压lego成功");
|
||||
} else {
|
||||
const zip = new JSZip();
|
||||
const data = fs.readFileSync(legoZipFilePath);
|
||||
const zipData = await zip.loadAsync(data);
|
||||
const files = Object.keys(zipData.files);
|
||||
for (const file of files) {
|
||||
const content = await zipData.files[file].async("nodebuffer");
|
||||
fs.writeFileSync(`${legoDir}/${file}`, content);
|
||||
}
|
||||
this.logger.info("解压lego成功");
|
||||
}
|
||||
}
|
||||
let serverArgs = "";
|
||||
if (this.acmeServer) {
|
||||
serverArgs = ` --server ${this.acmeServer}`;
|
||||
@@ -136,7 +186,7 @@ export class CertApplyLegoPlugin extends CertApplyBasePlugin {
|
||||
} run`,
|
||||
];
|
||||
|
||||
await sp.spawn({
|
||||
await this.ctx.utils.sp.spawn({
|
||||
cmd: cmds,
|
||||
logger: this.logger,
|
||||
env,
|
||||
|
||||
@@ -10,12 +10,26 @@ RUN npm install -g pnpm@8.15.7
|
||||
RUN cp /workspace/certd-client/dist/* /workspace/certd-server/public/ -rf
|
||||
RUN cd /workspace/certd-server && pnpm install && npm run build-on-docker
|
||||
|
||||
|
||||
FROM node:18-alpine
|
||||
RUN apk add --no-cache openssl
|
||||
RUN apk add --no-cache openjdk8
|
||||
WORKDIR /app/
|
||||
COPY --from=builder /workspace/certd-server/ /app/
|
||||
RUN chmod +x /app/tools/linux/*
|
||||
|
||||
ENV LEGO_VERSION=4.19.2
|
||||
ENV LEGO_DOWNLOAD_DIR /app/tools/lego
|
||||
RUN mkdir -p $LEGO_DOWNLOAD_DIR
|
||||
|
||||
# 根据架构下载不同的文件
|
||||
RUN ARCH=$(uname -m) && \
|
||||
if [ "$ARCH" = "x86_64" ]; then \
|
||||
wget -O $LEGO_DOWNLOAD_DIR/lego_v${LEGO_VERSION}_linux_amd64.tar.gz https://github.com/go-acme/lego/releases/download/v${LEGO_VERSION}/lego_v${LEGO_VERSION}_linux_arm64.tar.gz; \
|
||||
elif [ "$ARCH" = "aarch64" ]; then \
|
||||
wget -O $LEGO_DOWNLOAD_DIR/lego_v${LEGO_VERSION}_linux_arm64.tar.gz https://github.com/go-acme/lego/releases/download/v${LEGO_VERSION}/lego_v${LEGO_VERSION}_linux_amd64.tar.gz; \
|
||||
else \
|
||||
echo "Unsupported architecture: $ARCH"; \
|
||||
fi
|
||||
|
||||
ENV TZ=Asia/Shanghai
|
||||
ENV NODE_ENV=production
|
||||
ENV MIDWAY_SERVER_ENV=production
|
||||
|
||||
@@ -3,6 +3,37 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.27.1](https://github.com/certd/certd/compare/v1.27.0...v1.27.1) (2024-11-04)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复头像没有更新的bug ([9b4a31f](https://github.com/certd/certd/commit/9b4a31fa6a32b9cab2e22bd141cf96ca29120445))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 禁止页面缓存,点击tab页签可以刷新数据 ([7ad4b55](https://github.com/certd/certd/commit/7ad4b55ee000c1dd0747832b11107f32b0ffb889))
|
||||
* 优化时间选择器,自动填写分钟和秒钟 ([396dc34](https://github.com/certd/certd/commit/396dc34a841c7d016b033736afdba8366fb2d211))
|
||||
* cname 域名映射记录可读性优化 ([b1117ed](https://github.com/certd/certd/commit/b1117ed54a3ef015752999324ff72b821ef5e4b9))
|
||||
|
||||
# [1.27.0](https://github.com/certd/certd/compare/v1.26.16...v1.27.0) (2024-10-31)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复历史记录不能按名称查询的bug ([6113c38](https://github.com/certd/certd/commit/6113c388b7fc58b11ca19ff05cc1286d096c8d28))
|
||||
|
||||
### Features
|
||||
|
||||
* 首页全新改版 ([63ec5b5](https://github.com/certd/certd/commit/63ec5b5519c760a3330569c0da6dac157302a330))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 管理控制台数据统计 ([babd589](https://github.com/certd/certd/commit/babd5897ae013ff7c04ebfcbfac8a00d84dd627c))
|
||||
* 增加向导 ([6d9ef26](https://github.com/certd/certd/commit/6d9ef26ecab71d752c2c55d75aed4fb5f6c05a39))
|
||||
|
||||
## [1.26.16](https://github.com/certd/certd/compare/v1.26.15...v1.26.16) (2024-10-30)
|
||||
|
||||
**Note:** Version bump only for package @certd/ui-client
|
||||
|
||||
## [1.26.15](https://github.com/certd/certd/compare/v1.26.14...v1.26.15) (2024-10-28)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@certd/ui-client",
|
||||
"version": "1.26.15",
|
||||
"version": "1.27.1",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "vite --open",
|
||||
@@ -26,10 +26,10 @@
|
||||
"dependencies": {
|
||||
"@ant-design/colors": "^7.0.2",
|
||||
"@ant-design/icons-vue": "^6.1.0",
|
||||
"@fast-crud/fast-crud": "^1.22.2",
|
||||
"@fast-crud/fast-extends": "^1.22.2",
|
||||
"@fast-crud/ui-antdv4": "^1.22.2",
|
||||
"@fast-crud/ui-interface": "^1.22.2",
|
||||
"@fast-crud/fast-crud": "^1.22.3",
|
||||
"@fast-crud/fast-extends": "^1.22.3",
|
||||
"@fast-crud/ui-antdv4": "^1.22.3",
|
||||
"@fast-crud/ui-interface": "^1.22.3",
|
||||
"@iconify/vue": "^4.1.1",
|
||||
"@soerenmartius/vue3-clipboard": "^0.1.2",
|
||||
"@vue-js-cron/light": "^4.0.5",
|
||||
@@ -45,6 +45,7 @@
|
||||
"cron-parser": "^4.9.0",
|
||||
"cropperjs": "^1.6.1",
|
||||
"dayjs": "^1.11.10",
|
||||
"echarts": "^5.5.1",
|
||||
"highlight.js": "^11.9.0",
|
||||
"humanize-duration": "^3.27.3",
|
||||
"lodash-es": "^4.17.21",
|
||||
@@ -58,13 +59,14 @@
|
||||
"sortablejs": "^1.15.2",
|
||||
"vue": "^3.4.21",
|
||||
"vue-cropperjs": "^5.0.0",
|
||||
"vue-echarts": "^7.0.3",
|
||||
"vue-i18n": "^9.10.2",
|
||||
"vue-router": "^4.3.0",
|
||||
"vuedraggable": "^4.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@certd/lib-iframe": "^1.26.15",
|
||||
"@certd/pipeline": "^1.26.15",
|
||||
"@certd/lib-iframe": "^1.27.1",
|
||||
"@certd/pipeline": "^1.27.1",
|
||||
"@rollup/plugin-commonjs": "^25.0.7",
|
||||
"@rollup/plugin-node-resolve": "^15.2.3",
|
||||
"@types/chai": "^4.3.12",
|
||||
|
||||
|
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 106 KiB |
|
Before Width: | Height: | Size: 124 KiB After Width: | Height: | Size: 129 KiB |
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 35 KiB |
|
Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 79 KiB |
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 35 KiB |
|
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 82 KiB After Width: | Height: | Size: 37 KiB |
|
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 53 KiB |