Compare commits
153 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a188385817 | ||
|
|
0a6baf331b | ||
|
|
0e29e052d5 | ||
|
|
d8d255980e | ||
|
|
dc5a5fa543 | ||
|
|
8638fc91ff | ||
|
|
96a0900edc | ||
|
|
abea80e3ab | ||
|
|
42dfe936b7 | ||
|
|
8385bcc2d7 | ||
|
|
9b8f60b64b | ||
|
|
474114236e | ||
|
|
238b0b421a | ||
|
|
8abe62886a | ||
|
|
78cc9cffe4 | ||
|
|
59a5dd713f | ||
|
|
a39024ff03 | ||
|
|
72bfbd93a8 | ||
|
|
c9a3e3d9d2 | ||
|
|
8387708901 | ||
|
|
b565b4b3b9 | ||
|
|
893dcd4f24 | ||
|
|
d613aa8f3e | ||
|
|
5750bb7067 | ||
|
|
0e07ae6ce8 | ||
|
|
02b6351e13 | ||
|
|
78367af830 | ||
|
|
dc05cd481f | ||
|
|
7daad5477a | ||
|
|
45cdfbfae8 | ||
|
|
3fb5c38571 | ||
|
|
59f80ebc47 | ||
|
|
198a97b00c | ||
|
|
3ea4e917e8 | ||
|
|
60ad077172 | ||
|
|
356ad28e41 | ||
|
|
e241141220 | ||
|
|
14bb1b467a | ||
|
|
2bbea6fd3f | ||
|
|
48aef25b3f | ||
|
|
8e50e5dee3 | ||
|
|
d5d54d4d3b | ||
|
|
412e8a32dd | ||
|
|
0f82cf409b | ||
|
|
79df39acab | ||
|
|
8786bae7dc | ||
|
|
4b3f8ca361 | ||
|
|
03183218f7 | ||
|
|
95b6db57e1 | ||
|
|
bbe0c2457b | ||
|
|
c894c53e69 | ||
|
|
5b3fb7387d | ||
|
|
feac310caf | ||
|
|
d67ec3feb3 | ||
|
|
cf8abb4528 | ||
|
|
d66de26de4 | ||
|
|
7edf3f6147 | ||
|
|
2143dff2ae | ||
|
|
32c714d1b6 | ||
|
|
84e699ee24 | ||
|
|
7fdb572b8b | ||
|
|
cfd3b66be9 | ||
|
|
75c4f9dea8 | ||
|
|
a76a32230d | ||
|
|
0730f5ff4f | ||
|
|
c43d0a684c | ||
|
|
66f1eda6cf | ||
|
|
bf4d191c8b | ||
|
|
d76d56fcce | ||
|
|
251b0c58de | ||
|
|
073cca4e8e | ||
|
|
a4ad99f189 | ||
|
|
d37b910889 | ||
|
|
be69244e8d | ||
|
|
617f74a225 | ||
|
|
a2710ddc25 | ||
|
|
70101bfa7a | ||
|
|
203f2984d7 | ||
|
|
1d510e76b8 | ||
|
|
64244af2cc | ||
|
|
35e109882e | ||
|
|
18a32ffb0b | ||
|
|
a5af3ba0cb | ||
|
|
83bd39a9a8 | ||
|
|
cc0657aaa8 | ||
|
|
965dc2cb47 | ||
|
|
9c4cbe17a2 | ||
|
|
835fcfa4ea | ||
|
|
932780c578 | ||
|
|
37f160a452 | ||
|
|
f80b706fc3 | ||
|
|
f78cbed4d8 | ||
|
|
e0b12c78ff | ||
|
|
e7cf814a59 | ||
|
|
865c45593b | ||
|
|
62e6f109c7 | ||
|
|
60be8ed022 | ||
|
|
c157882900 | ||
|
|
a23c211a65 | ||
|
|
293ed6bd7e | ||
|
|
13ddd7c5f9 | ||
|
|
0de015fc8b | ||
|
|
d34fedae01 | ||
|
|
7c623fc467 | ||
|
|
359079c3e6 | ||
|
|
ba72fa3f05 | ||
|
|
23caab5b06 | ||
|
|
b506bd15a5 | ||
|
|
d0d9d68fe6 | ||
|
|
88134ac130 | ||
|
|
3d8a5196a0 | ||
|
|
c4fb138ae8 | ||
|
|
759cfdaabd | ||
|
|
3d9620abb0 | ||
|
|
420b0394a7 | ||
|
|
84bb4c8b07 | ||
|
|
310dbb61ee | ||
|
|
9b536af9e6 | ||
|
|
c2ca1ea1e5 | ||
|
|
ada4b226de | ||
|
|
67f956d4a0 | ||
|
|
f68af7dcf2 | ||
|
|
be1b6f8edc | ||
|
|
1150f62927 | ||
|
|
b4c7a521b4 | ||
|
|
5d083a1536 | ||
|
|
2f5ed3aead | ||
|
|
2951df0cd9 | ||
|
|
ec22070957 | ||
|
|
0e36f03954 | ||
|
|
57309ae3d5 | ||
|
|
7545194f97 | ||
|
|
4bb0918e27 | ||
|
|
64e5449ab3 | ||
|
|
a0eeb17d73 | ||
|
|
c021dd03d3 | ||
|
|
2f1683b26a | ||
|
|
c99939f435 | ||
|
|
efad8bac3c | ||
|
|
eaf68fa463 | ||
|
|
9475f2e56c | ||
|
|
2e0c067cd2 | ||
|
|
59a6043549 | ||
|
|
840a7b7c73 | ||
|
|
61e322678b | ||
|
|
04acd08ad2 | ||
|
|
f3bf4faee0 | ||
|
|
c3603ba220 | ||
|
|
a3a52fd12c | ||
|
|
d24fb6ed48 | ||
|
|
021dc5b82c | ||
|
|
545aa50898 | ||
|
|
071ef281c1 |
32
.github/workflows/build-image-for-test.yml
vendored
@@ -10,6 +10,7 @@ on:
|
||||
# - cron: '17 19 * * *'
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
jobs:
|
||||
build-certd-image:
|
||||
@@ -43,7 +44,7 @@ jobs:
|
||||
# cache: 'npm'
|
||||
# working-directory: ./packages/ui/certd-client
|
||||
- run: |
|
||||
npm install -g pnpm@8.15.7
|
||||
npm install -g pnpm
|
||||
pnpm install
|
||||
npm run build
|
||||
working-directory: ./packages/ui/certd-client
|
||||
@@ -61,19 +62,38 @@ jobs:
|
||||
username: ${{ secrets.aliyun_cs_username }}
|
||||
password: ${{ secrets.aliyun_cs_password }}
|
||||
|
||||
- name: Login to GitHub Packages
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.dockerhub_username }}
|
||||
password: ${{ secrets.dockerhub_password }}
|
||||
|
||||
- name: Build default platforms
|
||||
# - 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
|
||||
# ghcr.io/${{ github.repository }}:dev-latest
|
||||
|
||||
- name: Build armv7
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
platforms: linux/amd64,linux/arm64
|
||||
platforms: linux/arm/v7
|
||||
push: true
|
||||
context: ./packages/ui/
|
||||
tags: |
|
||||
registry.cn-shenzhen.aliyuncs.com/handsfree/certd-dev:latest
|
||||
greper/certd-dev:latest
|
||||
|
||||
registry.cn-shenzhen.aliyuncs.com/handsfree/certd:armv7
|
||||
registry.cn-shenzhen.aliyuncs.com/handsfree/certd:${{steps.get_certd_version.outputs.result}}-armv7
|
||||
greper/certd:armv7
|
||||
greper/certd:${{steps.get_certd_version.outputs.result}}-armv7
|
||||
37
.github/workflows/build-image.yml
vendored
@@ -10,6 +10,7 @@ on:
|
||||
# - cron: '17 19 * * *'
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
jobs:
|
||||
build-certd-image:
|
||||
@@ -43,7 +44,7 @@ jobs:
|
||||
# cache: 'npm'
|
||||
# working-directory: ./packages/ui/certd-client
|
||||
- run: |
|
||||
npm install -g pnpm@8.15.7
|
||||
npm install -g pnpm
|
||||
pnpm install
|
||||
npm run build
|
||||
working-directory: ./packages/ui/certd-client
|
||||
@@ -61,6 +62,13 @@ jobs:
|
||||
username: ${{ secrets.aliyun_cs_username }}
|
||||
password: ${{ secrets.aliyun_cs_password }}
|
||||
|
||||
- name: Login to GitHub Packages
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
@@ -78,18 +86,21 @@ jobs:
|
||||
registry.cn-shenzhen.aliyuncs.com/handsfree/certd:${{steps.get_certd_version.outputs.result}}
|
||||
greper/certd:latest
|
||||
greper/certd:${{steps.get_certd_version.outputs.result}}
|
||||
|
||||
# - name: Build armv7
|
||||
# uses: docker/build-push-action@v6
|
||||
# with:
|
||||
# platforms: linux/arm/v7
|
||||
# push: true
|
||||
# context: ./packages/ui/
|
||||
# tags: |
|
||||
# registry.cn-shenzhen.aliyuncs.com/handsfree/certd:armv7
|
||||
# registry.cn-shenzhen.aliyuncs.com/handsfree/certd:${{steps.get_certd_version.outputs.result}}-armv7
|
||||
# greper/certd:armv7
|
||||
# greper/certd:${{steps.get_certd_version.outputs.result}}-armv7
|
||||
ghcr.io/${{ github.repository }}:latest
|
||||
ghcr.io/${{ github.repository }}:${{steps.get_certd_version.outputs.result}}
|
||||
- name: Build armv7
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
platforms: linux/arm/v7
|
||||
push: true
|
||||
context: ./packages/ui/
|
||||
tags: |
|
||||
registry.cn-shenzhen.aliyuncs.com/handsfree/certd:armv7
|
||||
registry.cn-shenzhen.aliyuncs.com/handsfree/certd:${{steps.get_certd_version.outputs.result}}-armv7
|
||||
greper/certd:armv7
|
||||
greper/certd:${{steps.get_certd_version.outputs.result}}-armv7
|
||||
ghcr.io/${{ github.repository }}:armv7
|
||||
ghcr.io/${{ github.repository }}:${{steps.get_certd_version.outputs.result}}-armv7
|
||||
|
||||
# - name: Build agent
|
||||
# uses: docker/build-push-action@v6
|
||||
|
||||
93
CHANGELOG.md
@@ -3,6 +3,99 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.33.7](https://github.com/certd/certd/compare/v1.33.6...v1.33.7) (2025-04-22)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 添加部署证书至火山 Live ([abea80e](https://github.com/certd/certd/commit/abea80e3ab9b1672aebe1c5d5e856693b29931a8))
|
||||
* 优化首页插件列表展示 ([9b8f60b](https://github.com/certd/certd/commit/9b8f60b64b5f9a3db7dfa9b3dcbd9201984358d0))
|
||||
* 证书申请支持51dns ([8638fc9](https://github.com/certd/certd/commit/8638fc91ff34fccaf12ff9874fd3fa9d2a8c18b7))
|
||||
* 支持51dns ([96a0900](https://github.com/certd/certd/commit/96a0900edc95dcfd9acccf9d13592f12f5a09b3d))
|
||||
* ssh PTY模式登录设置 ([8385bcc](https://github.com/certd/certd/commit/8385bcc2d7f2411a07748bb5c53f9eaf4d38d7cc))
|
||||
* ssh伪终端模式优化,windows下不开启 ([42dfe93](https://github.com/certd/certd/commit/42dfe936b773b7bdd82ca3378363252ffffd7b71))
|
||||
|
||||
## [1.33.6](https://github.com/certd/certd/compare/v1.33.5...v1.33.6) (2025-04-20)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 上传商用证书,直接粘贴文本报错的问题;修复无法上传ec加密证书的bug ([5750bb7](https://github.com/certd/certd/commit/5750bb706779da274d8e7a87e71416cb64d2df79))
|
||||
* 修复下载证书时提示token已过期的问题 ([0e07ae6](https://github.com/certd/certd/commit/0e07ae6ce84dcb9279d3c44060d621566afa593c))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 更新license时同时绑定url ([78367af](https://github.com/certd/certd/commit/78367af8307f801e778c76d49f0918c21ffe032f))
|
||||
* 切换到不同的分组后再打开创建对话框,会自动选择分组 ([893dcd4](https://github.com/certd/certd/commit/893dcd4f2487891199ed3e5a3d47a79a75efc942))
|
||||
* 新增部署到火山引擎ALB/CLB、上传到证书中心 ([c9a3e3d](https://github.com/certd/certd/commit/c9a3e3d9d26f964c7af7b56667936f1414fbf42a))
|
||||
* 优化/api缓存为0 ([dc05cd4](https://github.com/certd/certd/commit/dc05cd481f186b13375192be965000e6b4b429a5))
|
||||
* 优化华为cdn插件引用ccm证书 ([b565b4b](https://github.com/certd/certd/commit/b565b4b3b919b71b98ea2517670bc1ef00e00dc9))
|
||||
* 优化证书流水线创建,支持选择分组 ([d613aa8](https://github.com/certd/certd/commit/d613aa8f3e85d8dc475ef1b62d49394ce7fd7d24))
|
||||
|
||||
## [1.33.5](https://github.com/certd/certd/compare/v1.33.4...v1.33.5) (2025-04-17)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 登录支持双重认证 ([48aef25](https://github.com/certd/certd/commit/48aef25b3f6499d674ca4e4ef16f4c62399fb735))
|
||||
* 多重认证登录 ([0f82cf4](https://github.com/certd/certd/commit/0f82cf409bc60706ab07e4ca4f272b9a1ca7eecb))
|
||||
* 优化部署到华为云CDN,支持先上传到ccm,再使用证书id部署,修复offline状态下导致部署报错的bug ([79df39a](https://github.com/certd/certd/commit/79df39acabab10ae7e1864dadcdc186bb007a3c5))
|
||||
|
||||
## [1.33.4](https://github.com/certd/certd/compare/v1.33.3...v1.33.4) (2025-04-15)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 补充类型断言 ([2143dff](https://github.com/certd/certd/commit/2143dff2ae96e6a78bef9f0498e36f8cd9e6941f))
|
||||
* 修复腾讯云部署到任意资源插件,无法使用之前已上传的腾讯云证书问题 ([32c714d](https://github.com/certd/certd/commit/32c714d1b6e68c71a74a7452115040c87ac4bfdc))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 插件支持导入导出 ([cf8abb4](https://github.com/certd/certd/commit/cf8abb45282070c8ba91469f93fd379fabf1f74a))
|
||||
* 支持上传证书到华为云CCM ([cfd3b66](https://github.com/certd/certd/commit/cfd3b66be9ebf53a26693057e70ed60c3f116be9))
|
||||
|
||||
## [1.33.3](https://github.com/certd/certd/compare/v1.33.2...v1.33.3) (2025-04-14)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复登录错误次数过多阻止再次登录逻辑 ([bf4d191](https://github.com/certd/certd/commit/bf4d191c8bd2f9209eb6768f662b9c77de99e998))
|
||||
|
||||
## [1.33.2](https://github.com/certd/certd/compare/v1.33.1...v1.33.2) (2025-04-12)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复某些情况下无法输出日志的bug ([70101bf](https://github.com/certd/certd/commit/70101bfa7ade65678d9202c804bbae2cb808b594))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 修复内置插件分页查询逻辑 ([a2710dd](https://github.com/certd/certd/commit/a2710ddc2525e4e637fd157f0180e6d3b801c8be))
|
||||
|
||||
## [1.33.1](https://github.com/certd/certd/compare/v1.33.0...v1.33.1) (2025-04-12)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复阿里云cdn证书部署失败问题,增加certname参数传入 ([965dc2c](https://github.com/certd/certd/commit/965dc2cb476f690af716f291c6b20ba98be0c8f0))
|
||||
* 修复ssh插件报length空指针的bug ([9c4cbe1](https://github.com/certd/certd/commit/9c4cbe17a22b548611cf1fbefecc83a421788e42))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 镜像支持armv7 ([f78cbed](https://github.com/certd/certd/commit/f78cbed4d817859721fdafe7d348864848d0dfbf))
|
||||
|
||||
# [1.33.0](https://github.com/certd/certd/compare/v1.32.0...v1.33.0) (2025-04-11)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 升级mysql驱动,支持mysql8最新版本的认证 ([2f5ed3a](https://github.com/certd/certd/commit/2f5ed3aead97641f2c80d692a50226839016df0b))
|
||||
* 修复eab授权,没有email绑定的bug ([2f1683b](https://github.com/certd/certd/commit/2f1683b26acebbfb7d6e2d751435be04a4e7cab4))
|
||||
|
||||
### Features
|
||||
|
||||
* 支持在线自定义插件,无需源码开发 ([d0d9d68](https://github.com/certd/certd/commit/d0d9d68fe6740f6ff49fe40b7c9917c5a2e4b442))
|
||||
* **lego:** support set key type ([f3bf4fa](https://github.com/certd/certd/commit/f3bf4faee0be5bdbfdbcf70a502849ed4c8ed4c4))
|
||||
* release image to ghcr ([9b536af](https://github.com/certd/certd/commit/9b536af9e656dc89e2a87078c129cad6f591e467))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 修复tab页缓存问题 ([64e5449](https://github.com/certd/certd/commit/64e5449ab3c6b219b0e89eddad14bfb6b71a0650))
|
||||
* 隐藏运行策略选项 ([2951df0](https://github.com/certd/certd/commit/2951df0cd94c23e2efee84ff1b843055aac56cae))
|
||||
* 增加手动上传证书功能说明 ([5d083a1](https://github.com/certd/certd/commit/5d083a153637caddbc6f44e915d9fb2d1ae87b33))
|
||||
|
||||
# [1.32.0](https://github.com/certd/certd/compare/v1.31.11...v1.32.0) (2025-04-04)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
131
README.md
@@ -9,13 +9,16 @@ Certd 是一个免费全自动申请和自动部署更新SSL证书的管理系
|
||||
本项目不仅支持证书申请过程自动化,还可以自动化部署更新证书,让你的证书永不过期。
|
||||
|
||||
* 全自动申请证书(支持所有注册商注册的域名)
|
||||
* 全自动部署更新证书(目前支持部署到主机、阿里云、腾讯云等,目前已支持60+部署插件)
|
||||
* 全自动部署更新证书(目前支持部署到主机、阿里云、腾讯云等70+部署插件)
|
||||
* 支持DNS-01、HTTP-01、CNAME代理等多种域名验证方式
|
||||
* 支持通配符域名/泛域名,支持多个域名打到一个证书上,支持pem、pfx、der、jks等多种证书格式
|
||||
* 邮件通知、webhook通知
|
||||
* 私有化部署,数据保存本地,授权信息加密存储,镜像由Github Actions构建,过程公开透明
|
||||
* 支持SQLite,PostgreSQL、MySQL数据库
|
||||
|
||||
|
||||

|
||||
|
||||
>
|
||||
> 流水线数量现已调整为无限制,欢迎大家使用
|
||||
>
|
||||
@@ -23,7 +26,7 @@ Certd 是一个免费全自动申请和自动部署更新SSL证书的管理系
|
||||
> 关于证书续期:
|
||||
>* 实际上没有办法不改变证书文件本身情况下直接续期或者续签。
|
||||
>* 我们所说的续期,其实就是按照全套流程重新申请一份新证书,然后重新部署上去。
|
||||
|
||||
>* 免费证书过期时间90天,以后可能还会缩短,所以自动化部署必不可少
|
||||
|
||||
## 二、在线体验
|
||||
|
||||
@@ -62,7 +65,7 @@ https://certd.handfree.work/
|
||||
-------> [点我查看详细使用步骤演示](./step.md) <--------
|
||||
↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
|
||||
|
||||
更多教程请访问文档网站 [certd.docmirror.cn](https://certd.docmirror.cn/)
|
||||
更多教程请访问官方文档 [certd.docmirror.cn](https://certd.docmirror.cn/guide/)
|
||||
|
||||
|
||||
|
||||
@@ -72,10 +75,10 @@ https://certd.handfree.work/
|
||||
|
||||
您可以根据实际情况从如下方式中选择一种方式进行私有化部署:
|
||||
|
||||
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/)
|
||||
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镜像说明:
|
||||
* 国内镜像地址:
|
||||
@@ -85,93 +88,36 @@ https://certd.handfree.work/
|
||||
* `https://hub.docker.com/r/greper/certd`
|
||||
* `greper/certd:latest`
|
||||
* `greper/certd:armv7`、`greper/certd:[version]-armv7`
|
||||
* GitHub Packages地址:
|
||||
* `ghcr.io/certd/certd:latest`
|
||||
* `ghcr.io/certd/certd:armv7`、`ghcr.io/certd/certd:[version]-armv7`
|
||||
|
||||
* 镜像构建通过`Actions`自动执行,过程公开透明,请放心使用
|
||||
* [点我查看镜像构建日志](https://github.com/certd/certd/actions/workflows/build-image.yml)
|
||||
|
||||

|
||||
|
||||
|
||||
## 五、 升级
|
||||
|
||||
### docker-compose方式部署
|
||||
#### 1. 如果使用固定版本号
|
||||
1. 修改`docker-compose.yaml`中的镜像版本号
|
||||
2. 运行`docker compose up -d` 即可
|
||||
|
||||
#### 2. 如果需要使用最新版本
|
||||
```shell
|
||||
#重新拉取镜像
|
||||
docker pull registry.cn-shenzhen.aliyuncs.com/handsfree/certd:latest
|
||||
# 重新启动容器
|
||||
docker compose down
|
||||
docker compose up -d
|
||||
```
|
||||
> 数据默认存在`/data/certd`目录下,不用担心数据丢失
|
||||
|
||||
### 自动升级(仅限尝鲜建议非生产使用)
|
||||
```yaml
|
||||
version: '3.3'
|
||||
services:
|
||||
certd:
|
||||
image: registry.cn-shenzhen.aliyuncs.com/handsfree/certd:latest
|
||||
container_name: certd
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- /data/certd:/app/data
|
||||
ports:
|
||||
- "7001:7001"
|
||||
- "7002:7002"
|
||||
environment:
|
||||
- certd_system_resetAdminPasswd=false
|
||||
labels:
|
||||
com.centurylinklabs.watchtower.enable: "true"
|
||||
|
||||
certd-updater: # 添加 Watchtower 服务
|
||||
image: containrrr/watchtower:latest
|
||||
container_name: certd-updater
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
# 配置 自动更新
|
||||
environment:
|
||||
- WATCHTOWER_CLEANUP=true # 自动清理旧版本容器
|
||||
- WATCHTOWER_INCLUDE_STOPPED=false # 不更新已停止的容器
|
||||
- WATCHTOWER_LABEL_ENABLE=true # 根据容器标签进行更新
|
||||
- WATCHTOWER_POLL_INTERVAL=300 # 每 5 分钟检查一次更新
|
||||
|
||||
```
|
||||
|
||||
### 其他部署方式升级方法
|
||||
请参考 https://certd.docmirror.cn/guide/install/upgrade.html
|
||||
> 注意:
|
||||
> * 本应用存储的证书、授权信息等属于高度敏感数据,请做好安全防护
|
||||
> * 请务必使用HTTPS协议访问本应用,避免被中间人攻击
|
||||
> * 请务必使用web应用防火墙防护本应用,防止XSS、SQL注入等攻击
|
||||
> * 请务必做好服务器本身的安全防护,防止数据库泄露
|
||||
> * 请务必做好数据备份,避免数据丢失
|
||||
|
||||
|
||||
|
||||
### 更新日志:
|
||||
|
||||
[CHANGELOG](./CHANGELOG.md)
|
||||
## 五、更多帮助
|
||||
请访问官方文档:[https://certd.docmirror.cn/](https://certd.docmirror.cn/guide/)
|
||||
|
||||
* 升级方法:[升级方法](https://certd.docmirror.cn/guide/install/upgrade/)
|
||||
* 常见问题:[忘记密码](https://certd.docmirror.cn/guide/use/forgotpasswd/)
|
||||
* 多数据库:[多数据库配置](https://certd.docmirror.cn/guide/install/database/)
|
||||
* 站点安全:[站点安全特性](https://certd.docmirror.cn/guide/feature/safe/)
|
||||
* 更新日志:[CHANGELOG](./CHANGELOG.md)
|
||||
|
||||
|
||||
## 六、一些说明
|
||||
* 本项目ssl证书提供商为letencrypt/Google/ZeroSSL
|
||||
* 申请过程遵循acme协议
|
||||
* 证书续期:
|
||||
* 实际上没有办法不改变证书文件本身情况下直接续期或者续签。
|
||||
* 我们所说的续期,其实就是按照全套流程重新申请一份新证书,然后重新部署上去。
|
||||
* 免费证书过期时间90天,以后可能还会缩短,所以自动化部署必不可少
|
||||
* 设置每天自动运行,当证书过期前35天,会自动重新申请证书并部署
|
||||
|
||||
|
||||
## 七、不同平台的设置说明
|
||||
|
||||
* 已迁移到新的文档网站,请到常见问题章节查看
|
||||
* [最新文档站链接 https://certd.docmirror.cn](https://certd.docmirror.cn/)
|
||||
|
||||
## 八、问题处理
|
||||
### 7.1 忘记管理员密码
|
||||
[重置管理员密码方法](https://certd.docmirror.cn/guide/use/forgotpasswd/)
|
||||
|
||||
## 九、联系作者
|
||||
## 六、联系作者
|
||||
如有疑问,欢迎加入群聊(请备注certd)
|
||||
|
||||
| 加群 | 微信群 | QQ群 |
|
||||
@@ -185,7 +131,7 @@ services:
|
||||
| 二维码 | <img height="230" src="./docs/guide/contact/images/me.png"> |
|
||||
|
||||
|
||||
## 十、捐赠
|
||||
## 七、捐赠
|
||||
************************
|
||||
支持开源,为爱发电,我已入驻爱发电
|
||||
https://afdian.com/a/greper
|
||||
@@ -194,8 +140,6 @@ https://afdian.com/a/greper
|
||||
1. 可加入发电专属群,可以获得作者一对一技术支持
|
||||
2. 您的需求我们将优先实现,并且将作为专业版功能提供
|
||||
3. 一年期专业版激活码
|
||||
4. 赠送国外免费服务器部署方案(0成本使用Certd,可能需要翻墙,不过现在性能越来越差了)
|
||||
|
||||
|
||||
专业版特权对比
|
||||
|
||||
@@ -211,33 +155,26 @@ https://afdian.com/a/greper
|
||||
|
||||
************************
|
||||
|
||||
## 十一、贡献代码
|
||||
## 八、贡献代码
|
||||
|
||||
1. 本地开发 [贡献插件](https://certd.docmirror.cn/guide/development/)
|
||||
1. 本地开发请参考 [贡献插件向导](https://certd.docmirror.cn/guide/development/)
|
||||
2. 作为贡献者,代表您同意您贡献的代码如下许可:
|
||||
1. 可以调整开源协议以使其更严格或更宽松。
|
||||
2. 可以用于商业用途。
|
||||
|
||||
|
||||
|
||||
## 十二、 开源许可
|
||||
## 九、 开源许可
|
||||
* 本项目遵循 GNU Affero General Public License(AGPL)开源协议。
|
||||
* 允许个人和公司内部自由使用、复制、修改和分发本项目,未获得商业授权情况下禁止任何形式的商业用途
|
||||
* 未获得商业授权情况下,禁止任何对logo、版权信息及授权许可相关代码的修改。
|
||||
* 如需商业授权,请联系作者。
|
||||
|
||||
## 十三、我的其他项目(求Star)
|
||||
|
||||
## 十、我的其他项目(求Star)
|
||||
|
||||
| 项目名称 | stars | 项目描述 |
|
||||
|---------------------------------------------------------|-------------------------------------------------------------------------------------------------------|-----------------------------------|
|
||||
| [袖手AI](https://ai.handsfree.work/) | | 袖手GPT,国内可用,无需FQ,每日免费额度 |
|
||||
| [fast-crud](https://gitee.com/fast-crud/fast-crud/) | <img alt="GitHub stars" src="https://img.shields.io/github/stars/fast-crud/fast-crud?logo=github"/> | 基于vue3的crud快速开发框架 |
|
||||
| [dev-sidecar](https://github.com/docmirror/dev-sidecar/) | <img alt="GitHub stars" src="https://img.shields.io/github/stars/docmirror/dev-sidecar?logo=github"/> | 直连访问github工具,无需FQ,解决github无法访问的问题 |
|
||||
|
||||
|
||||
|
||||
## 十四、更新日志
|
||||
|
||||
更新日志:[CHANGELOG](./CHANGELOG.md)
|
||||
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
1
|
||||
2
|
||||
|
||||
@@ -1 +1 @@
|
||||
00:33
|
||||
00:08
|
||||
|
||||
@@ -1,156 +1,166 @@
|
||||
import { defineConfig } from "vitepress";
|
||||
import {defineConfig} from "vitepress";
|
||||
// Import lightbox plugin
|
||||
import lightbox from "vitepress-plugin-lightbox";
|
||||
|
||||
// https://vitepress.dev/reference/site-config
|
||||
export default defineConfig({
|
||||
title: "Certd",
|
||||
titleTemplate: "开源SSL证书管理工具,证书自动化申请部署,让你的网站证书永不过期",
|
||||
description: "Certd帮助文档,Certd是一款开源免费的全自动SSL证书管理工具;证书自动化申请部署流水线;自动证书申请、更新、续期;通配符证书,泛域名证书申请;证书自动化部署到阿里云、腾讯云、主机、群晖、宝塔。",
|
||||
markdown: {
|
||||
config: (md) => {
|
||||
// Use lightbox plugin
|
||||
md.use(lightbox, {});
|
||||
}
|
||||
},
|
||||
sitemap: {
|
||||
hostname: 'https://certd.docmirror.cn'
|
||||
},
|
||||
head: [
|
||||
// [
|
||||
// 'meta',
|
||||
// {
|
||||
// name: 'viewport',
|
||||
// content:
|
||||
// 'width=device-width,initial-scale=1,minimfast-cum-scale=1.0,maximum-scale=1.0,user-scalable=no',
|
||||
// },
|
||||
// ],
|
||||
["meta", {
|
||||
name: "keywords",
|
||||
content: "证书自动申请、证书自动更新、证书自动续期、证书自动续签、证书管理工具、Certd、SSL证书自动部署、证书自动化,https证书,pfx证书,der证书,TLS证书,nginx证书自动续签自动部署,SSL平台,证书管理平台,证书流水线"
|
||||
}],
|
||||
// ["meta", { name: "google-site-verification",content: "V5XLTSnXoT15uQotwpxJoQolUo2d5UbSL-TacsyOsC0"}],
|
||||
//<meta name="baidu-site-verification" content="codeva-MiWN8Y07Ua" />
|
||||
// ["meta", {name: "baidu-site-verification",content: "codeva-MiWN8Y07Ua"}],
|
||||
["link", { rel: "icon", href: "/static/logo/logo.svg" }]
|
||||
],
|
||||
themeConfig: {
|
||||
logo: "/static/logo/logo.svg",
|
||||
search: {
|
||||
provider: "local",
|
||||
options: {
|
||||
detailedView: true,
|
||||
translations: {
|
||||
button: {
|
||||
buttonText: "搜索文档",
|
||||
buttonAriaLabel: "搜索文档"
|
||||
},
|
||||
modal: {
|
||||
noResultsText: "无法找到相关结果",
|
||||
resetButtonTitle: "清除查询条件",
|
||||
footer: {
|
||||
selectText: "选择",
|
||||
closeText: "关闭",
|
||||
navigateText: "切换"
|
||||
title: "Certd",
|
||||
titleTemplate: "开源SSL证书管理工具,证书自动化申请部署,让你的网站证书永不过期",
|
||||
description: "Certd帮助文档,Certd是一款开源免费的全自动SSL证书管理工具;证书自动化申请部署流水线;自动证书申请、更新、续期;通配符证书,泛域名证书申请;证书自动化部署到阿里云、腾讯云、主机、群晖、宝塔。",
|
||||
markdown: {
|
||||
config: (md) => {
|
||||
// Use lightbox plugin
|
||||
md.use(lightbox, {});
|
||||
}
|
||||
},
|
||||
sitemap: {
|
||||
hostname: 'https://certd.docmirror.cn'
|
||||
},
|
||||
head: [
|
||||
// [
|
||||
// 'meta',
|
||||
// {
|
||||
// name: 'viewport',
|
||||
// content:
|
||||
// 'width=device-width,initial-scale=1,minimfast-cum-scale=1.0,maximum-scale=1.0,user-scalable=no',
|
||||
// },
|
||||
// ],
|
||||
["meta", {
|
||||
name: "keywords",
|
||||
content: "证书自动申请、证书自动更新、证书自动续期、证书自动续签、证书管理工具、Certd、SSL证书自动部署、证书自动化,https证书,pfx证书,der证书,TLS证书,nginx证书自动续签自动部署,SSL平台,证书管理平台,证书流水线"
|
||||
}],
|
||||
// ["meta", { name: "google-site-verification",content: "V5XLTSnXoT15uQotwpxJoQolUo2d5UbSL-TacsyOsC0"}],
|
||||
//<meta name="baidu-site-verification" content="codeva-MiWN8Y07Ua" />
|
||||
// ["meta", {name: "baidu-site-verification",content: "codeva-MiWN8Y07Ua"}],
|
||||
["link", {rel: "icon", href: "/static/logo/logo.svg"}]
|
||||
],
|
||||
themeConfig: {
|
||||
logo: "/static/logo/logo.svg",
|
||||
search: {
|
||||
provider: "local",
|
||||
options: {
|
||||
detailedView: true,
|
||||
translations: {
|
||||
button: {
|
||||
buttonText: "搜索文档",
|
||||
buttonAriaLabel: "搜索文档"
|
||||
},
|
||||
modal: {
|
||||
noResultsText: "无法找到相关结果",
|
||||
resetButtonTitle: "清除查询条件",
|
||||
footer: {
|
||||
selectText: "选择",
|
||||
closeText: "关闭",
|
||||
navigateText: "切换"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
// https://vitepress.dev/reference/default-theme-config
|
||||
nav: [
|
||||
{ text: "首页", link: "/" },
|
||||
{ text: "指南", link: "/guide/" },
|
||||
{ text: "商业版", link: "/comm/" },
|
||||
{ text: "Demo体验", link: "https://certd.handfree.work" }
|
||||
],
|
||||
sidebar: {
|
||||
"/guide/": [
|
||||
{
|
||||
text: "入门",
|
||||
items: [
|
||||
{ text: "简介", link: "/guide/" },
|
||||
{ text: "快速开始", link: "/guide/start.md" },
|
||||
{
|
||||
text: "私有化部署",
|
||||
items: [
|
||||
{ text: "docker部署", link: "/guide/install/docker/" },
|
||||
{ text: "宝塔面板部署", link: "/guide/install/baota/" },
|
||||
{ text: "1Panel部署", link: "/guide/install/1panel/" },
|
||||
{ text: "群晖部署", link: "/guide/use/synology/" },
|
||||
{ text: "源码部署", link: "/guide/install/source/" }
|
||||
]
|
||||
},
|
||||
{ text: "演示教程", link: "/guide/tutorial.md" },
|
||||
{ text: "版本升级", link: "/guide/install/upgrade.md" }
|
||||
]
|
||||
},
|
||||
{
|
||||
text: "特性",
|
||||
items: [
|
||||
{ text: "CNAME代理校验", link: "/guide/feature/cname/index.md" },
|
||||
{ text: "插件列表", link: "/guide/plugins.md" },
|
||||
{ text: "多数据库支持", link: "/guide/install/database.md" },
|
||||
{ text: "开放接口", link: "/guide/open/index.md" }
|
||||
]
|
||||
},
|
||||
{
|
||||
text: "常见问题",
|
||||
items: [
|
||||
{ text: "群晖证书部署", link: "/guide/use/synology/" },
|
||||
{ text: "腾讯云密钥获取", link: "/guide/use/tencent/" },
|
||||
{ text: "连接windows主机", link: "/guide/use/host/windows.md" },
|
||||
{ text: "Google EAB获取", link: "/guide/use/google/" },
|
||||
{ text: "阿里云相关", link: "/guide/use/aliyun/" },
|
||||
{ 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: "IPv6支持", link: "/guide/use/setting/ipv6.md" },
|
||||
]
|
||||
},
|
||||
{
|
||||
text: "其他",
|
||||
items: [
|
||||
{ text: "贡献代码", link: "/guide/development/index.md" },
|
||||
{ text: "更新日志", link: "/guide/changelogs/CHANGELOG.md" },
|
||||
{ text: "镜像说明", link: "/guide/image.md" },
|
||||
{ text: "联系我们", link: "/guide/contact/" },
|
||||
{ text: "捐赠", link: "/guide/donate/" },
|
||||
{ text: "开源协议", link: "/guide/license/" },
|
||||
{ text: "我的其他开源项目", link: "/guide/link/" },
|
||||
// https://vitepress.dev/reference/default-theme-config
|
||||
nav: [
|
||||
{text: "首页", link: "/"},
|
||||
{text: "指南", link: "/guide/"},
|
||||
{text: "Demo体验", link: "https://certd.handfree.work"}
|
||||
],
|
||||
sidebar: {
|
||||
"/guide/": [
|
||||
{
|
||||
text: "入门",
|
||||
items: [
|
||||
{text: "简介", link: "/guide/"},
|
||||
{text: "快速开始", link: "/guide/start.md"},
|
||||
{
|
||||
text: "私有化部署",
|
||||
items: [
|
||||
{text: "docker部署", link: "/guide/install/docker/"},
|
||||
{text: "宝塔面板部署", link: "/guide/install/baota/"},
|
||||
{text: "1Panel部署", link: "/guide/install/1panel/"},
|
||||
{text: "群晖部署", link: "/guide/use/synology/"},
|
||||
{text: "源码部署", link: "/guide/install/source/"}
|
||||
]
|
||||
},
|
||||
{text: "演示教程", link: "/guide/tutorial.md"},
|
||||
{text: "版本升级", link: "/guide/install/upgrade.md"}
|
||||
]
|
||||
},
|
||||
{
|
||||
text: "特性",
|
||||
items: [
|
||||
{text: "CNAME代理校验", link: "/guide/feature/cname/index.md"},
|
||||
{text: "插件列表", link: "/guide/plugins.md"},
|
||||
{text: "多数据库支持", link: "/guide/install/database.md"},
|
||||
{text: "开放接口", link: "/guide/open/index.md"},
|
||||
{
|
||||
text: "站点安全", items: [
|
||||
{text: "安全特性", link: "/guide/feature/safe"},
|
||||
{text: "站点隐藏", link: "/guide/feature/safe/hidden"},
|
||||
{text: "安全生产建议", link: "/guide/feature/safe/suggest"},
|
||||
]
|
||||
},
|
||||
|
||||
]
|
||||
}
|
||||
],
|
||||
"/deploy/":[
|
||||
{
|
||||
text: "部署任务",
|
||||
items: [
|
||||
{ text: "部署到ESXi", link: "/deploy/ESXi/index.md" },
|
||||
]
|
||||
}
|
||||
],
|
||||
"/comm/": [
|
||||
{
|
||||
text: "商业版",
|
||||
items: [
|
||||
{ text: "支付宝配置", link: "/comm/payments/alipay.md" },
|
||||
{ text: "微信支付配置", link: "/comm/payments/wxpay.md" },
|
||||
{ text: "彩虹易支付配置", link: "/comm/payments/yizhifu.md" },
|
||||
]
|
||||
}
|
||||
]
|
||||
,
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
text: "常见问题",
|
||||
items: [
|
||||
{text: "群晖证书部署", link: "/guide/use/synology/"},
|
||||
{text: "腾讯云密钥获取", link: "/guide/use/tencent/"},
|
||||
{text: "连接windows主机", link: "/guide/use/host/windows.md"},
|
||||
{text: "Google EAB获取", link: "/guide/use/google/"},
|
||||
{text: "阿里云相关", link: "/guide/use/aliyun/"},
|
||||
{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: "IPv6支持", link: "/guide/use/setting/ipv6.md"},
|
||||
{text: "其他插件使用", link: "/deploy/"},
|
||||
{text: "商业版说明", link: "/comm/"},
|
||||
]
|
||||
},
|
||||
{
|
||||
text: "其他",
|
||||
items: [
|
||||
{text: "贡献代码", link: "/guide/development/index.md"},
|
||||
{text: "更新日志", link: "/guide/changelogs/CHANGELOG.md"},
|
||||
{text: "镜像说明", link: "/guide/image.md"},
|
||||
{text: "联系我们", link: "/guide/contact/"},
|
||||
{text: "捐赠", link: "/guide/donate/"},
|
||||
{text: "开源协议", link: "/guide/license/"},
|
||||
{text: "我的其他开源项目", link: "/guide/link/"},
|
||||
|
||||
socialLinks: [
|
||||
{ icon: "github", link: "https://github.com/certd/certd" }
|
||||
],
|
||||
footer: {
|
||||
message: "Certd帮助文档 | <a href='https://beian.miit.gov.cn/' target='_blank'>粤ICP备14088435号</a> ",
|
||||
copyright: "Copyright © 2021-present <a href='https://handfree.work/' target='_blank'>handfree.work</a> "
|
||||
]
|
||||
}
|
||||
],
|
||||
"/deploy/": [
|
||||
{
|
||||
text: "部署证书插件",
|
||||
items: [
|
||||
{text: "插件说明", link: "/deploy/index.md"},
|
||||
{text: "部署到ESXi", link: "/deploy/ESXi/index.md"},
|
||||
]
|
||||
}
|
||||
],
|
||||
"/comm/": [
|
||||
{
|
||||
text: "商业版",
|
||||
items: [
|
||||
{text: "支付宝配置", link: "/comm/payments/alipay.md"},
|
||||
{text: "微信支付配置", link: "/comm/payments/wxpay.md"},
|
||||
{text: "彩虹易支付配置", link: "/comm/payments/yizhifu.md"},
|
||||
]
|
||||
}
|
||||
]
|
||||
,
|
||||
},
|
||||
|
||||
socialLinks: [
|
||||
{icon: "github", link: "https://github.com/certd/certd"}
|
||||
],
|
||||
footer: {
|
||||
message: "Certd帮助文档 | <a href='https://beian.miit.gov.cn/' target='_blank'>粤ICP备14088435号</a> ",
|
||||
copyright: "Copyright © 2021-present <a href='https://handfree.work/' target='_blank'>handfree.work</a> "
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
4
docs/deploy/index.md
Normal file
@@ -0,0 +1,4 @@
|
||||
# 部署插件说明
|
||||
|
||||
## 待完善
|
||||
|
||||
@@ -3,6 +3,105 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.33.6](https://github.com/certd/certd/compare/v1.33.5...v1.33.6) (2025-04-20)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 上传商用证书,直接粘贴文本报错的问题;修复无法上传ec加密证书的bug ([5750bb7](https://github.com/certd/certd/commit/5750bb706779da274d8e7a87e71416cb64d2df79))
|
||||
* 修复下载证书时提示token已过期的问题 ([0e07ae6](https://github.com/certd/certd/commit/0e07ae6ce84dcb9279d3c44060d621566afa593c))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 更新license时同时绑定url ([78367af](https://github.com/certd/certd/commit/78367af8307f801e778c76d49f0918c21ffe032f))
|
||||
* 切换到不同的分组后再打开创建对话框,会自动选择分组 ([893dcd4](https://github.com/certd/certd/commit/893dcd4f2487891199ed3e5a3d47a79a75efc942))
|
||||
* 新增部署到火山引擎ALB/CLB、上传到证书中心 ([c9a3e3d](https://github.com/certd/certd/commit/c9a3e3d9d26f964c7af7b56667936f1414fbf42a))
|
||||
* 优化/api缓存为0 ([dc05cd4](https://github.com/certd/certd/commit/dc05cd481f186b13375192be965000e6b4b429a5))
|
||||
* 优化华为cdn插件引用ccm证书 ([b565b4b](https://github.com/certd/certd/commit/b565b4b3b919b71b98ea2517670bc1ef00e00dc9))
|
||||
* 优化证书流水线创建,支持选择分组 ([d613aa8](https://github.com/certd/certd/commit/d613aa8f3e85d8dc475ef1b62d49394ce7fd7d24))
|
||||
|
||||
## [1.33.5](https://github.com/certd/certd/compare/v1.33.4...v1.33.5) (2025-04-17)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 登录支持双重认证 ([48aef25](https://github.com/certd/certd/commit/48aef25b3f6499d674ca4e4ef16f4c62399fb735))
|
||||
* 多重认证登录 ([0f82cf4](https://github.com/certd/certd/commit/0f82cf409bc60706ab07e4ca4f272b9a1ca7eecb))
|
||||
* 优化部署到华为云CDN,支持先上传到ccm,再使用证书id部署,修复offline状态下导致部署报错的bug ([79df39a](https://github.com/certd/certd/commit/79df39acabab10ae7e1864dadcdc186bb007a3c5))
|
||||
|
||||
## [1.33.4](https://github.com/certd/certd/compare/v1.33.3...v1.33.4) (2025-04-15)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 补充类型断言 ([2143dff](https://github.com/certd/certd/commit/2143dff2ae96e6a78bef9f0498e36f8cd9e6941f))
|
||||
* 修复腾讯云部署到任意资源插件,无法使用之前已上传的腾讯云证书问题 ([32c714d](https://github.com/certd/certd/commit/32c714d1b6e68c71a74a7452115040c87ac4bfdc))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 插件支持导入导出 ([cf8abb4](https://github.com/certd/certd/commit/cf8abb45282070c8ba91469f93fd379fabf1f74a))
|
||||
* 支持上传证书到华为云CCM ([cfd3b66](https://github.com/certd/certd/commit/cfd3b66be9ebf53a26693057e70ed60c3f116be9))
|
||||
|
||||
## [1.33.3](https://github.com/certd/certd/compare/v1.33.2...v1.33.3) (2025-04-14)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复登录错误次数过多阻止再次登录逻辑 ([bf4d191](https://github.com/certd/certd/commit/bf4d191c8bd2f9209eb6768f662b9c77de99e998))
|
||||
|
||||
## [1.33.2](https://github.com/certd/certd/compare/v1.33.1...v1.33.2) (2025-04-12)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复某些情况下无法输出日志的bug ([70101bf](https://github.com/certd/certd/commit/70101bfa7ade65678d9202c804bbae2cb808b594))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 修复内置插件分页查询逻辑 ([a2710dd](https://github.com/certd/certd/commit/a2710ddc2525e4e637fd157f0180e6d3b801c8be))
|
||||
|
||||
## [1.33.1](https://github.com/certd/certd/compare/v1.33.0...v1.33.1) (2025-04-12)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复阿里云cdn证书部署失败问题,增加certname参数传入 ([965dc2c](https://github.com/certd/certd/commit/965dc2cb476f690af716f291c6b20ba98be0c8f0))
|
||||
* 修复ssh插件报length空指针的bug ([9c4cbe1](https://github.com/certd/certd/commit/9c4cbe17a22b548611cf1fbefecc83a421788e42))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 镜像支持armv7 ([f78cbed](https://github.com/certd/certd/commit/f78cbed4d817859721fdafe7d348864848d0dfbf))
|
||||
|
||||
# [1.33.0](https://github.com/certd/certd/compare/v1.32.0...v1.33.0) (2025-04-11)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 升级mysql驱动,支持mysql8最新版本的认证 ([2f5ed3a](https://github.com/certd/certd/commit/2f5ed3aead97641f2c80d692a50226839016df0b))
|
||||
* 修复eab授权,没有email绑定的bug ([2f1683b](https://github.com/certd/certd/commit/2f1683b26acebbfb7d6e2d751435be04a4e7cab4))
|
||||
|
||||
### Features
|
||||
|
||||
* 支持在线自定义插件,无需源码开发 ([d0d9d68](https://github.com/certd/certd/commit/d0d9d68fe6740f6ff49fe40b7c9917c5a2e4b442))
|
||||
* **lego:** support set key type ([f3bf4fa](https://github.com/certd/certd/commit/f3bf4faee0be5bdbfdbcf70a502849ed4c8ed4c4))
|
||||
* release image to ghcr ([9b536af](https://github.com/certd/certd/commit/9b536af9e656dc89e2a87078c129cad6f591e467))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 修复tab页缓存问题 ([64e5449](https://github.com/certd/certd/commit/64e5449ab3c6b219b0e89eddad14bfb6b71a0650))
|
||||
* 隐藏运行策略选项 ([2951df0](https://github.com/certd/certd/commit/2951df0cd94c23e2efee84ff1b843055aac56cae))
|
||||
* 增加手动上传证书功能说明 ([5d083a1](https://github.com/certd/certd/commit/5d083a153637caddbc6f44e915d9fb2d1ae87b33))
|
||||
|
||||
# [1.32.0](https://github.com/certd/certd/compare/v1.31.11...v1.32.0) (2025-04-04)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 创建cname记录移除域名两端的空格 ([903a413](https://github.com/certd/certd/commit/903a4131ab5f42c8286cd2150ed1032d486fda2f))
|
||||
* 修复从本地dns获取记录报错的bug ([c39b1bf](https://github.com/certd/certd/commit/c39b1bf823ddc6216bed2049e4c87e6107def08a))
|
||||
|
||||
### Features
|
||||
|
||||
* 优化证书申请速度,修复某些情况下letsencrypt 校验失败的问题 ([857589b](https://github.com/certd/certd/commit/857589b365c6f709e0ae67914d2f50ce182e6dd6))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 优化华为dns解析记录创建和删除问题 ([0948c5b](https://github.com/certd/certd/commit/0948c5bc691d2ee6eb47c72a85da1b7453361878))
|
||||
* 又拍云支持云存储 ([9339b78](https://github.com/certd/certd/commit/9339b78f801d193472c0af25749e8e7a27ffb7af))
|
||||
* 又拍云支持云存储 ([8449f85](https://github.com/certd/certd/commit/8449f8580da90c1f6b5d02d07c3236ebaf6cf161))
|
||||
|
||||
## [1.31.11](https://github.com/certd/certd/compare/v1.31.10...v1.31.11) (2025-04-02)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
BIN
docs/guide/feature/safe/hidden/images/hidden1.png
Normal file
|
After Width: | Height: | Size: 51 KiB |
BIN
docs/guide/feature/safe/hidden/images/hidden2.png
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
25
docs/guide/feature/safe/hidden/index.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# 站点隐藏
|
||||
|
||||
* 一般来说Certd设置好之后,很少需要访问。
|
||||
* 所以我们`平时`可以把`站点访问关闭`,需要的时候再打开,减少站点被攻击的风险
|
||||
|
||||
## 1、开启站点隐藏
|
||||
`系统管理->系统设置->安全设置->站点隐藏 `
|
||||
|
||||
|
||||

|
||||
|
||||
:::warning
|
||||
|
||||
注意保存好`解除地址`和`解除密码`
|
||||
|
||||
:::
|
||||
|
||||
## 2、临时关闭站点隐藏
|
||||
|
||||
访问上面的`解除地址`,输入`解除密码`,`临时解除`站点隐藏
|
||||
|
||||

|
||||
|
||||
## 3、忘记解除地址和解除密码怎么办
|
||||
登录服务器,在数据库平级的目录下创建`.unhidden`文件即可`临时解除`站点隐藏
|
||||
BIN
docs/guide/feature/safe/images/2fa.png
Normal file
|
After Width: | Height: | Size: 70 KiB |
BIN
docs/guide/feature/safe/images/access.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
docs/guide/feature/safe/images/hidden.png
Normal file
|
After Width: | Height: | Size: 35 KiB |
BIN
docs/guide/feature/safe/images/login.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
36
docs/guide/feature/safe/index.md
Normal file
@@ -0,0 +1,36 @@
|
||||
# 站点安全特性
|
||||
|
||||
Certd 存储了证书以及授权等敏感数据,所以需要严格保障安全。
|
||||
我们非常重视您的数据安全,提供了以下安全特性
|
||||
|
||||
## 1、 授权数据加密存储【默认开启】
|
||||
* 所有的授权敏感字段会加密后存储
|
||||
* 每个用户独立维护授权数据,连管理员都无权查看
|
||||
|
||||

|
||||
星号部分为加密数据
|
||||
|
||||
## 2、 密码防爆破【默认开启】
|
||||
* 登录失败次数过多,账号将被锁定,最高24小时(重启服务可解除锁定)
|
||||
* 用户登录密码加密hash后存储,无法计算出密码明文
|
||||

|
||||
|
||||
## 3、站点隐藏【建议开启】
|
||||
* 一般来说Certd设置好之后,后续很少需要访问修改。
|
||||
* 所以我们平时可以把站点访问关闭,需要的时候再打开,减少站点被攻击的风险
|
||||
* 请前往 `系统管理->系统设置->安全设置->开启站点隐藏`
|
||||
* [站点隐藏设置说明](./hidden/)
|
||||

|
||||
|
||||
## 4、登录双重验证
|
||||
|
||||
支持2FA双重认证
|
||||
|
||||

|
||||
|
||||
## 5、数据库自动备份【建议开启】
|
||||
* [自动备份设置说明](../../use/backup/)
|
||||
|
||||
|
||||
## 更多安全生产建议
|
||||
[安全生产建议](./suggest.md)
|
||||
10
docs/guide/feature/safe/suggest.md
Normal file
@@ -0,0 +1,10 @@
|
||||
# 安全生产建议
|
||||
|
||||
尽管`Cert`本身实现了很多安全特性,但`外部环境的安全`仍需要您来确保。
|
||||
请`务必`遵循如下建议做好安全防护
|
||||
|
||||
* 请`务必`使用`HTTPS协议`访问本应用,避免被中间人攻击
|
||||
* 请`务必`使用`web应用防火墙`防护本应用,防止XSS、SQL注入等攻击
|
||||
* 请`务必`做好`服务器本身`的安全防护,防止数据库泄露
|
||||
* 请`务必`做好[`数据备份`](../../use/backup/),避免数据丢失
|
||||
* 建议开启[`站点隐藏`](./hidden/)功能
|
||||
@@ -9,6 +9,10 @@
|
||||
* `greper/certd:latest`
|
||||
* `greper/certd:armv7`、`greper/certd:[version]-armv7`
|
||||
|
||||
## GitHub Packages地址:
|
||||
* `ghcr.io/certd/certd:latest`
|
||||
* `ghcr.io/certd/certd:armv7`、`ghcr.io/certd/certd:[version]-armv7`
|
||||
*
|
||||
## 镜像构建公开
|
||||
镜像构建通过`Actions`自动执行,过程公开透明,请放心使用
|
||||
* [点我查看镜像构建日志](https://github.com/certd/certd/actions/workflows/build-image.yml)
|
||||
|
||||
@@ -17,6 +17,8 @@ Certd 是一款开源、免费、全自动申请和部署更新SSL证书的工
|
||||
* 支持SQLite、Postgresql、MySQL数据库
|
||||
|
||||
|
||||

|
||||
|
||||
## 二、一些说明
|
||||
* 本项目申请证书过程遵循acme协议
|
||||
* 需要验证域名所有权,一般有两种方式
|
||||
|
||||
BIN
docs/guide/install/baota/images/network.png
Normal file
|
After Width: | Height: | Size: 82 KiB |
@@ -13,7 +13,7 @@
|
||||
|
||||
#### 2.1 应用商店一键部署【推荐】
|
||||
|
||||
* 在应用商店中找到`certd`(要先点右上角更新应用)
|
||||
* 在宝塔Docker应用商店中找到`certd`(要先点右上角更新应用)
|
||||
* 点击安装,配置域名等基本信息即可完成安装
|
||||
|
||||
> 需要宝塔9.2.0及以上版本才支持
|
||||
@@ -70,3 +70,12 @@ admin/123456
|
||||
## 五、备份恢复
|
||||
|
||||
将备份的`db.sqlite`及同目录下的其他文件一起覆盖到原来的位置,重启certd即可
|
||||
|
||||
|
||||
## 六、宝塔部署相关问题排查
|
||||
|
||||
### 1. 无法访问Certd
|
||||
1. 确认服务器的安全规则,是否放开了对应端口
|
||||
2. 确认宝塔防火墙是否放开对应端口
|
||||
3. 尝试将Certd容器加入宝塔的`bridge`网络
|
||||

|
||||
@@ -1,5 +1,6 @@
|
||||
# 数据库自动备份
|
||||
|
||||
# 数据库备份
|
||||
* 两种备份方法: 1、手动备份 2、自动备份
|
||||
* 本文仅限sqlite数据库。
|
||||
## 一、手动备份
|
||||
数据库文件根据不同的部署方式保存的位置不一样,您可以手动复制出来进行备份
|
||||
|
||||
|
||||
1
docs/images/intro/intro.svg
Normal file
|
After Width: | Height: | Size: 60 KiB |
@@ -9,5 +9,5 @@
|
||||
}
|
||||
},
|
||||
"npmClient": "pnpm",
|
||||
"version": "1.32.0"
|
||||
"version": "1.33.7"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,38 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.33.7](https://github.com/publishlab/node-acme-client/compare/v1.33.6...v1.33.7) (2025-04-22)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
## [1.33.6](https://github.com/publishlab/node-acme-client/compare/v1.33.5...v1.33.6) (2025-04-20)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
## [1.33.5](https://github.com/publishlab/node-acme-client/compare/v1.33.4...v1.33.5) (2025-04-17)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
## [1.33.4](https://github.com/publishlab/node-acme-client/compare/v1.33.3...v1.33.4) (2025-04-15)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
## [1.33.3](https://github.com/publishlab/node-acme-client/compare/v1.33.2...v1.33.3) (2025-04-14)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
## [1.33.2](https://github.com/publishlab/node-acme-client/compare/v1.33.1...v1.33.2) (2025-04-12)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
## [1.33.1](https://github.com/publishlab/node-acme-client/compare/v1.33.0...v1.33.1) (2025-04-12)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
# [1.33.0](https://github.com/publishlab/node-acme-client/compare/v1.32.0...v1.33.0) (2025-04-11)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
# [1.32.0](https://github.com/publishlab/node-acme-client/compare/v1.31.11...v1.32.0) (2025-04-04)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"description": "Simple and unopinionated ACME client",
|
||||
"private": false,
|
||||
"author": "nmorsman",
|
||||
"version": "1.32.0",
|
||||
"version": "1.33.7",
|
||||
"type": "module",
|
||||
"module": "scr/index.js",
|
||||
"main": "src/index.js",
|
||||
@@ -18,7 +18,7 @@
|
||||
"types"
|
||||
],
|
||||
"dependencies": {
|
||||
"@certd/basic": "^1.32.0",
|
||||
"@certd/basic": "^1.33.7",
|
||||
"@peculiar/x509": "^1.11.0",
|
||||
"asn1js": "^3.0.5",
|
||||
"axios": "^1.7.2",
|
||||
@@ -67,5 +67,5 @@
|
||||
"bugs": {
|
||||
"url": "https://github.com/publishlab/node-acme-client/issues"
|
||||
},
|
||||
"gitHead": "8374c3941a9d1398989b8f38fd4bfa2a2f29937b"
|
||||
"gitHead": "8abe62886ab50634b4b05abedd2981ec8ee0422e"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,44 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.33.7](https://github.com/certd/certd/compare/v1.33.6...v1.33.7) (2025-04-22)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 支持51dns ([96a0900](https://github.com/certd/certd/commit/96a0900edc95dcfd9acccf9d13592f12f5a09b3d))
|
||||
|
||||
## [1.33.6](https://github.com/certd/certd/compare/v1.33.5...v1.33.6) (2025-04-20)
|
||||
|
||||
**Note:** Version bump only for package @certd/basic
|
||||
|
||||
## [1.33.5](https://github.com/certd/certd/compare/v1.33.4...v1.33.5) (2025-04-17)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 多重认证登录 ([0f82cf4](https://github.com/certd/certd/commit/0f82cf409bc60706ab07e4ca4f272b9a1ca7eecb))
|
||||
|
||||
## [1.33.4](https://github.com/certd/certd/compare/v1.33.3...v1.33.4) (2025-04-15)
|
||||
|
||||
**Note:** Version bump only for package @certd/basic
|
||||
|
||||
## [1.33.3](https://github.com/certd/certd/compare/v1.33.2...v1.33.3) (2025-04-14)
|
||||
|
||||
**Note:** Version bump only for package @certd/basic
|
||||
|
||||
## [1.33.2](https://github.com/certd/certd/compare/v1.33.1...v1.33.2) (2025-04-12)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复某些情况下无法输出日志的bug ([70101bf](https://github.com/certd/certd/commit/70101bfa7ade65678d9202c804bbae2cb808b594))
|
||||
|
||||
## [1.33.1](https://github.com/certd/certd/compare/v1.33.0...v1.33.1) (2025-04-12)
|
||||
|
||||
**Note:** Version bump only for package @certd/basic
|
||||
|
||||
# [1.33.0](https://github.com/certd/certd/compare/v1.32.0...v1.33.0) (2025-04-11)
|
||||
|
||||
**Note:** Version bump only for package @certd/basic
|
||||
|
||||
# [1.32.0](https://github.com/certd/certd/compare/v1.31.11...v1.32.0) (2025-04-04)
|
||||
|
||||
**Note:** Version bump only for package @certd/basic
|
||||
|
||||
@@ -1 +1 @@
|
||||
01:33
|
||||
22:12
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/basic",
|
||||
"private": false,
|
||||
"version": "1.32.0",
|
||||
"version": "1.33.7",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.js",
|
||||
@@ -44,5 +44,5 @@
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "8374c3941a9d1398989b8f38fd4bfa2a2f29937b"
|
||||
"gitHead": "8abe62886ab50634b4b05abedd2981ec8ee0422e"
|
||||
}
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
import crypto, { BinaryToTextEncoding } from 'crypto';
|
||||
import crypto, { BinaryToTextEncoding } from "crypto";
|
||||
|
||||
function md5(data: string, digest: BinaryToTextEncoding = 'hex') {
|
||||
return crypto.createHash('md5').update(data).digest(digest);
|
||||
function md5(data: string, digest: BinaryToTextEncoding = "hex") {
|
||||
return crypto.createHash("md5").update(data).digest(digest);
|
||||
}
|
||||
function sha256(data: string, digest: BinaryToTextEncoding = 'hex') {
|
||||
return crypto.createHash('sha256').update(data).digest(digest);
|
||||
function sha256(data: string, digest: BinaryToTextEncoding = "hex") {
|
||||
return crypto.createHash("sha256").update(data).digest(digest);
|
||||
}
|
||||
|
||||
function hmacSha256(data: string, digest: BinaryToTextEncoding = 'base64') {
|
||||
return crypto.createHmac('sha256', data).update(Buffer.alloc(0)).digest(digest);
|
||||
function hmacSha256(data: string, digest: BinaryToTextEncoding = "base64") {
|
||||
return crypto.createHmac("sha256", data).update(Buffer.alloc(0)).digest(digest);
|
||||
}
|
||||
|
||||
function base64(data: string) {
|
||||
return Buffer.from(data).toString('base64');
|
||||
return Buffer.from(data).toString("base64");
|
||||
}
|
||||
export const hashUtils = {
|
||||
md5,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { customAlphabet } from "nanoid";
|
||||
|
||||
export const randomNumber = customAlphabet("1234567890", 4);
|
||||
export const simpleNanoId = customAlphabet("1234567890abcdefghijklmopqrstuvwxyz", 12);
|
||||
export const simpleNanoId = customAlphabet("1234567890abcdefghijklmopqrstuvwxyzABCDEFGHIJKLMOPQRSTUVWXYZ", 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) => {
|
||||
@@ -21,17 +21,31 @@ const OutputAppender = {
|
||||
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' } },
|
||||
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 const logger = log4js.getLogger("default");
|
||||
|
||||
export function buildLogger(write: (text: string) => void) {
|
||||
const logger = log4js.getLogger('pipeline');
|
||||
logger.addContext('outputHandler', {
|
||||
write,
|
||||
const logger = log4js.getLogger("pipeline");
|
||||
const _secrets: string[] = [];
|
||||
//@ts-ignore
|
||||
logger.addSecret = (secret: string) => {
|
||||
_secrets.push(secret);
|
||||
};
|
||||
logger.addContext("outputHandler", {
|
||||
write: (text: string) => {
|
||||
for (const item of _secrets) {
|
||||
if (item == null) {
|
||||
continue;
|
||||
}
|
||||
//换成同长度的*号, item可能有多行
|
||||
text = text.replaceAll(item, "*".repeat(item.length));
|
||||
}
|
||||
write(text);
|
||||
},
|
||||
});
|
||||
return logger;
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import axios, { AxiosHeaders, AxiosRequestConfig } from 'axios';
|
||||
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';
|
||||
import axios, { AxiosHeaders, AxiosRequestConfig } from "axios";
|
||||
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;
|
||||
@@ -22,10 +22,10 @@ export class HttpError extends Error {
|
||||
super(error.message || error.response?.statusText);
|
||||
|
||||
const message = error?.message;
|
||||
if (message && typeof message === 'string') {
|
||||
if (message.indexOf && message.indexOf('ssl3_get_record:wrong version number') >= 0) {
|
||||
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') >= 0) {
|
||||
} else if (message.indexOf("getaddrinfo EAI_AGAIN") >= 0) {
|
||||
this.message = `${message}(无法解析域名,请检查网络连接或dns配置,更换docker-compose.yaml中dns配置)`;
|
||||
}
|
||||
}
|
||||
@@ -47,7 +47,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}】`;
|
||||
@@ -73,7 +73,7 @@ export const HttpCommonError = HttpError;
|
||||
let defaultAgents = createAgent();
|
||||
|
||||
export function setGlobalProxy(opts: { httpProxy?: string; httpsProxy?: string }) {
|
||||
logger.info('setGlobalProxy:', opts);
|
||||
logger.info("setGlobalProxy:", opts);
|
||||
defaultAgents = createAgent(opts);
|
||||
}
|
||||
|
||||
@@ -102,12 +102,12 @@ export function createAxiosService({ logger }: { logger: Logger }) {
|
||||
if (config.skipSslVerify || config.httpProxy) {
|
||||
let rejectUnauthorized = true;
|
||||
if (config.skipSslVerify) {
|
||||
logger.info('跳过SSL验证');
|
||||
logger.info("跳过SSL验证");
|
||||
rejectUnauthorized = false;
|
||||
}
|
||||
const proxy: any = {};
|
||||
if (config.httpProxy) {
|
||||
logger.info('使用自定义http代理:', config.httpProxy);
|
||||
logger.info("使用自定义http代理:", config.httpProxy);
|
||||
proxy.httpProxy = config.httpProxy;
|
||||
proxy.httpsProxy = config.httpProxy;
|
||||
}
|
||||
@@ -128,7 +128,7 @@ export function createAxiosService({ logger }: { logger: Logger }) {
|
||||
},
|
||||
(error: Error) => {
|
||||
// 发送失败
|
||||
logger.error('接口请求失败:', error);
|
||||
logger.error("接口请求失败:", error);
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
@@ -143,7 +143,7 @@ export function createAxiosService({ logger }: { logger: Logger }) {
|
||||
|
||||
logger.info(`http response : status=${response?.status},data=${resData}`);
|
||||
} else {
|
||||
logger.info('http response status:', response?.status);
|
||||
logger.info("http response status:", response?.status);
|
||||
}
|
||||
if (response?.config?.returnResponse) {
|
||||
return response;
|
||||
@@ -154,53 +154,51 @@ export function createAxiosService({ logger }: { logger: Logger }) {
|
||||
const status = error.response?.status;
|
||||
switch (status) {
|
||||
case 400:
|
||||
error.message = '请求错误';
|
||||
error.message = "请求错误";
|
||||
break;
|
||||
case 401:
|
||||
error.message = '认证/登录失败';
|
||||
error.message = "认证/登录失败";
|
||||
break;
|
||||
case 403:
|
||||
error.message = '拒绝访问';
|
||||
error.message = "拒绝访问";
|
||||
break;
|
||||
case 404:
|
||||
error.message = `请求地址出错`;
|
||||
break;
|
||||
case 408:
|
||||
error.message = '请求超时';
|
||||
error.message = "请求超时";
|
||||
break;
|
||||
case 500:
|
||||
error.message = '服务器内部错误';
|
||||
error.message = "服务器内部错误";
|
||||
break;
|
||||
case 501:
|
||||
error.message = '服务未实现';
|
||||
error.message = "服务未实现";
|
||||
break;
|
||||
case 502:
|
||||
error.message = '网关错误';
|
||||
error.message = "网关错误";
|
||||
break;
|
||||
case 503:
|
||||
error.message = '服务不可用';
|
||||
error.message = "服务不可用";
|
||||
break;
|
||||
case 504:
|
||||
error.message = '网关超时';
|
||||
error.message = "网关超时";
|
||||
break;
|
||||
case 505:
|
||||
error.message = 'HTTP版本不受支持';
|
||||
error.message = "HTTP版本不受支持";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
logger.error(
|
||||
`请求出错:status:${error.response?.status},statusText:${error.response?.statusText},url:${error.config?.url},method:${error.config?.method}。`
|
||||
);
|
||||
logger.error('返回数据:', JSON.stringify(error.response?.data));
|
||||
logger.error(`请求出错:status:${error.response?.status},statusText:${error.response?.statusText},url:${error.config?.url},method:${error.config?.method}。`);
|
||||
logger.error("返回数据:", JSON.stringify(error.response?.data));
|
||||
if (error.response?.data) {
|
||||
const message = error.response.data.message || error.response.data.msg || error.response.data.error;
|
||||
if (typeof message === 'string') {
|
||||
if (typeof message === "string") {
|
||||
error.message = message;
|
||||
}
|
||||
}
|
||||
if (error instanceof AggregateError) {
|
||||
logger.error('AggregateError', error);
|
||||
logger.error("AggregateError", error);
|
||||
}
|
||||
const err = new HttpError(error);
|
||||
return Promise.reject(err);
|
||||
@@ -244,24 +242,24 @@ export function createAgent(opts: CreateAgentOptions = {}) {
|
||||
if (httpProxy) {
|
||||
process.env.HTTP_PROXY = httpProxy;
|
||||
process.env.http_proxy = httpProxy;
|
||||
logger.info('use httpProxy:', httpProxy);
|
||||
logger.info("use httpProxy:", httpProxy);
|
||||
httpAgent = new HttpProxyAgent(httpProxy, opts as any);
|
||||
merge(httpAgent.options, opts);
|
||||
} else {
|
||||
process.env.HTTP_PROXY = '';
|
||||
process.env.http_proxy = '';
|
||||
process.env.HTTP_PROXY = "";
|
||||
process.env.http_proxy = "";
|
||||
httpAgent = new nodeHttp.Agent(opts);
|
||||
}
|
||||
const httpsProxy = opts.httpsProxy;
|
||||
if (httpsProxy) {
|
||||
process.env.HTTPS_PROXY = httpsProxy;
|
||||
process.env.https_proxy = httpsProxy;
|
||||
logger.info('use httpsProxy:', httpsProxy);
|
||||
logger.info("use httpsProxy:", httpsProxy);
|
||||
httpsAgent = new HttpsProxyAgent(httpsProxy, opts as any);
|
||||
merge(httpsAgent.options, opts);
|
||||
} else {
|
||||
process.env.HTTPS_PROXY = '';
|
||||
process.env.https_proxy = '';
|
||||
process.env.HTTPS_PROXY = "";
|
||||
process.env.https_proxy = "";
|
||||
httpsAgent = new https.Agent(opts);
|
||||
}
|
||||
return {
|
||||
@@ -276,27 +274,27 @@ export async function download(req: { http: HttpClient; config: HttpRequestConfi
|
||||
http
|
||||
.request({
|
||||
logRes: false,
|
||||
responseType: 'stream',
|
||||
responseType: "stream",
|
||||
...config,
|
||||
})
|
||||
.then(res => {
|
||||
const writer = fs.createWriteStream(savePath);
|
||||
res.pipe(writer);
|
||||
writer.on('close', () => {
|
||||
logger.info('文件下载成功');
|
||||
writer.on("close", () => {
|
||||
logger.info("文件下载成功");
|
||||
resolve(true);
|
||||
});
|
||||
//error
|
||||
writer.on('error', err => {
|
||||
logger.error('下载失败', err);
|
||||
writer.on("error", err => {
|
||||
logger.error("下载失败", err);
|
||||
reject(err);
|
||||
});
|
||||
//进度条打印
|
||||
const totalLength = res.headers['content-length'];
|
||||
const totalLength = res.headers["content-length"];
|
||||
let currentLength = 0;
|
||||
// 每5%打印一次
|
||||
const step = (totalLength / 100) * 5;
|
||||
res.on('data', (chunk: any) => {
|
||||
res.on("data", (chunk: any) => {
|
||||
currentLength += chunk.length;
|
||||
if (currentLength % step < chunk.length) {
|
||||
const percent = ((currentLength / totalLength) * 100).toFixed(2);
|
||||
@@ -305,19 +303,19 @@ export async function download(req: { http: HttpClient; config: HttpRequestConfi
|
||||
});
|
||||
})
|
||||
.catch(err => {
|
||||
logger.info('下载失败', err);
|
||||
logger.info("下载失败", err);
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function getCookie(response: any, name: string) {
|
||||
const cookies = response.headers['set-cookie'];
|
||||
const cookies = response.headers["set-cookie"];
|
||||
//根据name 返回对应的cookie
|
||||
const found = cookies.find((cookie: any) => cookie.includes(name));
|
||||
if (!found) {
|
||||
return null;
|
||||
}
|
||||
const cookie = found.split(';')[0];
|
||||
return cookie.substring(cookie.indexOf('=') + 1);
|
||||
const cookie = found.split(";")[0];
|
||||
return cookie.substring(cookie.indexOf("=") + 1);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,42 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.33.7](https://github.com/certd/certd/compare/v1.33.6...v1.33.7) (2025-04-22)
|
||||
|
||||
**Note:** Version bump only for package @certd/pipeline
|
||||
|
||||
## [1.33.6](https://github.com/certd/certd/compare/v1.33.5...v1.33.6) (2025-04-20)
|
||||
|
||||
**Note:** Version bump only for package @certd/pipeline
|
||||
|
||||
## [1.33.5](https://github.com/certd/certd/compare/v1.33.4...v1.33.5) (2025-04-17)
|
||||
|
||||
**Note:** Version bump only for package @certd/pipeline
|
||||
|
||||
## [1.33.4](https://github.com/certd/certd/compare/v1.33.3...v1.33.4) (2025-04-15)
|
||||
|
||||
**Note:** Version bump only for package @certd/pipeline
|
||||
|
||||
## [1.33.3](https://github.com/certd/certd/compare/v1.33.2...v1.33.3) (2025-04-14)
|
||||
|
||||
**Note:** Version bump only for package @certd/pipeline
|
||||
|
||||
## [1.33.2](https://github.com/certd/certd/compare/v1.33.1...v1.33.2) (2025-04-12)
|
||||
|
||||
**Note:** Version bump only for package @certd/pipeline
|
||||
|
||||
## [1.33.1](https://github.com/certd/certd/compare/v1.33.0...v1.33.1) (2025-04-12)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复ssh插件报length空指针的bug ([9c4cbe1](https://github.com/certd/certd/commit/9c4cbe17a22b548611cf1fbefecc83a421788e42))
|
||||
|
||||
# [1.33.0](https://github.com/certd/certd/compare/v1.32.0...v1.33.0) (2025-04-11)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 隐藏运行策略选项 ([2951df0](https://github.com/certd/certd/commit/2951df0cd94c23e2efee84ff1b843055aac56cae))
|
||||
|
||||
# [1.32.0](https://github.com/certd/certd/compare/v1.31.11...v1.32.0) (2025-04-04)
|
||||
|
||||
**Note:** Version bump only for package @certd/pipeline
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/pipeline",
|
||||
"private": false,
|
||||
"version": "1.32.0",
|
||||
"version": "1.33.7",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.js",
|
||||
@@ -16,8 +16,8 @@
|
||||
"test": "mocha --loader=ts-node/esm"
|
||||
},
|
||||
"dependencies": {
|
||||
"@certd/basic": "^1.32.0",
|
||||
"@certd/plus-core": "^1.32.0",
|
||||
"@certd/basic": "^1.33.7",
|
||||
"@certd/plus-core": "^1.33.7",
|
||||
"dayjs": "^1.11.7",
|
||||
"lodash-es": "^4.17.21",
|
||||
"reflect-metadata": "^0.1.13"
|
||||
@@ -43,5 +43,5 @@
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "8374c3941a9d1398989b8f38fd4bfa2a2f29937b"
|
||||
"gitHead": "8abe62886ab50634b4b05abedd2981ec8ee0422e"
|
||||
}
|
||||
|
||||
@@ -26,7 +26,9 @@ export function IsAccess(define: AccessDefine): ClassDecorator {
|
||||
target.define = define;
|
||||
accessRegistry.register(define.name, {
|
||||
define,
|
||||
target,
|
||||
target: async () => {
|
||||
return target;
|
||||
},
|
||||
});
|
||||
};
|
||||
}
|
||||
@@ -39,13 +41,15 @@ export function AccessInput(input?: AccessInputDefine): PropertyDecorator {
|
||||
};
|
||||
}
|
||||
|
||||
export function newAccess(type: string, input: any, ctx?: AccessContext) {
|
||||
export async function newAccess(type: string, input: any, ctx?: AccessContext) {
|
||||
const register = accessRegistry.get(type);
|
||||
if (register == null) {
|
||||
throw new Error(`access ${type} not found`);
|
||||
}
|
||||
// @ts-ignore
|
||||
const access = new register.target();
|
||||
const accessCls = await register.target();
|
||||
// @ts-ignore
|
||||
const access = new accessCls();
|
||||
for (const key in input) {
|
||||
access[key] = input[key];
|
||||
}
|
||||
@@ -57,5 +61,6 @@ export function newAccess(type: string, input: any, ctx?: AccessContext) {
|
||||
};
|
||||
}
|
||||
access.setCtx(ctx);
|
||||
access._type = type;
|
||||
return access;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ConcurrencyStrategy, NotificationWhen, Pipeline, ResultType, Runnable, RunStrategy, Stage, Step, Task, ResultError } from "../dt/index.js";
|
||||
import { RunHistory, RunnableCollection } from "./run-history.js";
|
||||
import { AbstractTaskPlugin, PluginDefine, pluginRegistry, TaskInstanceContext, UserInfo } from "../plugin/index.js";
|
||||
import { AbstractTaskPlugin, ITaskPlugin, PluginDefine, pluginRegistry, TaskInstanceContext, UserInfo } from "../plugin/index.js";
|
||||
import { ContextFactory, IContext } from "./context.js";
|
||||
import { IStorage } from "./storage.js";
|
||||
import { createAxiosService, hashUtils, HttpRequestConfig, ILogger, logger, utils } from "@certd/basic";
|
||||
@@ -261,6 +261,7 @@ export class Executor {
|
||||
const resList: ResultType[] = [];
|
||||
for (const step of task.steps) {
|
||||
step.runnableType = "step";
|
||||
// @ts-ignore
|
||||
const res: ResultType = await this.runWithHistory(step, "step", async () => {
|
||||
return await this.runStep(step);
|
||||
});
|
||||
@@ -276,8 +277,18 @@ export class Executor {
|
||||
//执行任务
|
||||
const plugin: RegistryItem<AbstractTaskPlugin> = pluginRegistry.get(step.type);
|
||||
|
||||
// @ts-ignore
|
||||
const instance: ITaskPlugin = new plugin.target();
|
||||
//@ts-ignore
|
||||
let instance: ITaskPlugin = null;
|
||||
try {
|
||||
//@ts-ignore
|
||||
const pluginCls = await plugin.target();
|
||||
//@ts-ignore
|
||||
instance = new pluginCls();
|
||||
} catch (e: any) {
|
||||
currentLogger.error(`实例化插件失败:${e.message}`);
|
||||
throw new Error(`实例化插件失败`, e);
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
const define: PluginDefine = plugin.define;
|
||||
const pluginName = define.name;
|
||||
|
||||
@@ -150,11 +150,11 @@ export class RunnableCollection {
|
||||
pipeline.stages = [];
|
||||
return;
|
||||
}
|
||||
pipeline.stages.forEach((stage) => {
|
||||
pipeline.stages.forEach(stage => {
|
||||
stage.runnableType = "stage";
|
||||
stage.tasks.forEach((task) => {
|
||||
stage.tasks.forEach(task => {
|
||||
task.runnableType = "task";
|
||||
task.steps.forEach((step) => {
|
||||
task.steps.forEach(step => {
|
||||
step.runnableType = "step";
|
||||
});
|
||||
});
|
||||
@@ -162,7 +162,7 @@ export class RunnableCollection {
|
||||
}
|
||||
|
||||
static each<T extends Runnable>(list: T[], exec: (item: Runnable) => void) {
|
||||
list.forEach((item) => {
|
||||
list.forEach(item => {
|
||||
exec(item);
|
||||
if (item.runnableType === "pipeline") {
|
||||
// @ts-ignore
|
||||
@@ -179,7 +179,7 @@ export class RunnableCollection {
|
||||
public toMap(pipeline: Pipeline) {
|
||||
const map: RunnableMap = {};
|
||||
|
||||
RunnableCollection.each(pipeline.stages, (item) => {
|
||||
RunnableCollection.each(pipeline.stages, item => {
|
||||
map[item.id] = item;
|
||||
});
|
||||
return map;
|
||||
@@ -193,7 +193,7 @@ export class RunnableCollection {
|
||||
if (!this.pipeline) {
|
||||
return;
|
||||
}
|
||||
RunnableCollection.each(this.pipeline.stages, (item) => {
|
||||
RunnableCollection.each(this.pipeline.stages, item => {
|
||||
item.status = undefined;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -26,7 +26,9 @@ export function IsNotification(define: NotificationDefine): ClassDecorator {
|
||||
target.define = define;
|
||||
notificationRegistry.register(define.name, {
|
||||
define,
|
||||
target,
|
||||
target: async () => {
|
||||
return target;
|
||||
},
|
||||
});
|
||||
};
|
||||
}
|
||||
@@ -44,9 +46,10 @@ export async function newNotification(type: string, input: any, ctx: Notificatio
|
||||
if (register == null) {
|
||||
throw new Error(`notification ${type} not found`);
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
const plugin = new register.target();
|
||||
const pluginCls = await register.target();
|
||||
// @ts-ignore
|
||||
const plugin = new pluginCls();
|
||||
merge(plugin, input);
|
||||
if (!ctx) {
|
||||
throw new Error("ctx is required");
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Registrable } from "../registry/index.js";
|
||||
import { FileItem, FormItemProps, Pipeline, Runnable, Step } from "../dt/index.js";
|
||||
import { FileStore } from "../core/file-store.js";
|
||||
import { IAccessService } from "../access/index.js";
|
||||
import { accessRegistry, IAccessService } from "../access/index.js";
|
||||
import { ICnameProxyService, IEmailService, IServiceGetter, IUrlService } from "../service/index.js";
|
||||
import { CancelError, IContext, RunHistory, RunnableCollection } from "../core/index.js";
|
||||
import { HttpRequestConfig, ILogger, logger, utils } from "@certd/basic";
|
||||
@@ -64,6 +64,9 @@ export type PluginDefine = Registrable & {
|
||||
};
|
||||
};
|
||||
needPlus?: boolean;
|
||||
showRunStrategy?: boolean;
|
||||
pluginType?: string; //类型
|
||||
type?: string; //来源
|
||||
};
|
||||
|
||||
export type ITaskPlugin = {
|
||||
@@ -155,14 +158,35 @@ export abstract class AbstractTaskPlugin implements ITaskPlugin {
|
||||
this.http = ctx.http;
|
||||
}
|
||||
|
||||
async getAccess<T = any>(accessId: string) {
|
||||
async getAccess<T = any>(accessId: string | number, isCommon = false) {
|
||||
if (accessId == null) {
|
||||
throw new Error("您还没有配置授权");
|
||||
}
|
||||
const res = await this.ctx.accessService.getById(accessId);
|
||||
let res: any = null;
|
||||
if (isCommon) {
|
||||
res = await this.ctx.accessService.getCommonById(accessId);
|
||||
} else {
|
||||
res = await this.ctx.accessService.getById(accessId);
|
||||
}
|
||||
if (res == null) {
|
||||
throw new Error("授权不存在,可能已被删除,请前往任务配置里面重新选择授权");
|
||||
}
|
||||
// @ts-ignore
|
||||
if (this.logger?.addSecret) {
|
||||
// 隐藏加密信息,不在日志中输出
|
||||
const type = res._type;
|
||||
const plugin = accessRegistry.get(type);
|
||||
const define = plugin.define;
|
||||
// @ts-ignore
|
||||
const input = define.input;
|
||||
for (const key in input) {
|
||||
if (input[key].encrypt && res[key] != null) {
|
||||
// @ts-ignore
|
||||
this.logger.addSecret(res[key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res as T;
|
||||
}
|
||||
|
||||
|
||||
@@ -48,14 +48,26 @@ export function IsTaskPlugin(define: PluginDefine): ClassDecorator {
|
||||
inputMap[item[0]] = item[1];
|
||||
});
|
||||
|
||||
merge(define, { input: inputMap, autowire: autowires, output: outputs });
|
||||
const defaultConfig = {
|
||||
showRunStrategy: false,
|
||||
default: {
|
||||
strategy: {
|
||||
runStrategy: 1, // 0:正常执行,1:成功后跳过
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
define = merge(defaultConfig, define, { input: inputMap, autowire: autowires, output: outputs });
|
||||
|
||||
Reflect.defineMetadata(PLUGIN_CLASS_KEY, define, target);
|
||||
|
||||
target.define = define;
|
||||
|
||||
pluginRegistry.register(define.name, {
|
||||
define,
|
||||
target,
|
||||
target: async () => {
|
||||
return target;
|
||||
},
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
@@ -3,14 +3,23 @@ import { AbstractTaskPlugin } from "./api.js";
|
||||
import { pluginGroups } from "./group.js";
|
||||
|
||||
const onRegister = ({ key, value }: OnRegisterContext<AbstractTaskPlugin>) => {
|
||||
//如果有相同名字的先移除
|
||||
|
||||
for (const group of Object.values(pluginGroups)) {
|
||||
const index = group.plugins.findIndex(plugin => plugin.name === key);
|
||||
if (index > -1) {
|
||||
group.plugins.splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
const group = value?.define?.group as string;
|
||||
if (group) {
|
||||
if (pluginGroups.hasOwnProperty(group)) {
|
||||
// @ts-ignore
|
||||
pluginGroups[group].plugins.push(value.define);
|
||||
} else {
|
||||
pluginGroups.other.plugins.push(value.define);
|
||||
return;
|
||||
}
|
||||
}
|
||||
pluginGroups.other.plugins.push(value.define);
|
||||
};
|
||||
export const pluginRegistry = createRegistry<AbstractTaskPlugin>("plugin", onRegister);
|
||||
|
||||
@@ -8,10 +8,10 @@ export type Registrable = {
|
||||
deprecated?: string;
|
||||
order?: number;
|
||||
};
|
||||
|
||||
export type TargetGetter<T> = () => Promise<T>;
|
||||
export type RegistryItem<T> = {
|
||||
define: Registrable;
|
||||
target: T;
|
||||
target: TargetGetter<T>;
|
||||
};
|
||||
|
||||
export type OnRegisterContext<T> = {
|
||||
|
||||
@@ -4,5 +4,5 @@ export * from "./config.js";
|
||||
export * from "./url.js";
|
||||
export * from "./emit.js";
|
||||
export type IServiceGetter = {
|
||||
get: (name: string) => Promise<any>;
|
||||
get: <T>(name: string) => Promise<T>;
|
||||
};
|
||||
|
||||
@@ -3,6 +3,38 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.33.7](https://github.com/certd/certd/compare/v1.33.6...v1.33.7) (2025-04-22)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-huawei
|
||||
|
||||
## [1.33.6](https://github.com/certd/certd/compare/v1.33.5...v1.33.6) (2025-04-20)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-huawei
|
||||
|
||||
## [1.33.5](https://github.com/certd/certd/compare/v1.33.4...v1.33.5) (2025-04-17)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-huawei
|
||||
|
||||
## [1.33.4](https://github.com/certd/certd/compare/v1.33.3...v1.33.4) (2025-04-15)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-huawei
|
||||
|
||||
## [1.33.3](https://github.com/certd/certd/compare/v1.33.2...v1.33.3) (2025-04-14)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-huawei
|
||||
|
||||
## [1.33.2](https://github.com/certd/certd/compare/v1.33.1...v1.33.2) (2025-04-12)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-huawei
|
||||
|
||||
## [1.33.1](https://github.com/certd/certd/compare/v1.33.0...v1.33.1) (2025-04-12)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-huawei
|
||||
|
||||
# [1.33.0](https://github.com/certd/certd/compare/v1.32.0...v1.33.0) (2025-04-11)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-huawei
|
||||
|
||||
# [1.32.0](https://github.com/certd/certd/compare/v1.31.11...v1.32.0) (2025-04-04)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-huawei
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/lib-huawei",
|
||||
"private": false,
|
||||
"version": "1.32.0",
|
||||
"version": "1.33.7",
|
||||
"main": "./dist/bundle.js",
|
||||
"module": "./dist/bundle.js",
|
||||
"types": "./dist/d/index.d.ts",
|
||||
@@ -23,5 +23,5 @@
|
||||
"prettier": "^2.8.8",
|
||||
"tslib": "^2.8.1"
|
||||
},
|
||||
"gitHead": "8374c3941a9d1398989b8f38fd4bfa2a2f29937b"
|
||||
"gitHead": "8abe62886ab50634b4b05abedd2981ec8ee0422e"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,40 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.33.7](https://github.com/certd/certd/compare/v1.33.6...v1.33.7) (2025-04-22)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-iframe
|
||||
|
||||
## [1.33.6](https://github.com/certd/certd/compare/v1.33.5...v1.33.6) (2025-04-20)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 更新license时同时绑定url ([78367af](https://github.com/certd/certd/commit/78367af8307f801e778c76d49f0918c21ffe032f))
|
||||
|
||||
## [1.33.5](https://github.com/certd/certd/compare/v1.33.4...v1.33.5) (2025-04-17)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-iframe
|
||||
|
||||
## [1.33.4](https://github.com/certd/certd/compare/v1.33.3...v1.33.4) (2025-04-15)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-iframe
|
||||
|
||||
## [1.33.3](https://github.com/certd/certd/compare/v1.33.2...v1.33.3) (2025-04-14)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-iframe
|
||||
|
||||
## [1.33.2](https://github.com/certd/certd/compare/v1.33.1...v1.33.2) (2025-04-12)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-iframe
|
||||
|
||||
## [1.33.1](https://github.com/certd/certd/compare/v1.33.0...v1.33.1) (2025-04-12)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-iframe
|
||||
|
||||
# [1.33.0](https://github.com/certd/certd/compare/v1.32.0...v1.33.0) (2025-04-11)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-iframe
|
||||
|
||||
# [1.32.0](https://github.com/certd/certd/compare/v1.31.11...v1.32.0) (2025-04-04)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-iframe
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/lib-iframe",
|
||||
"private": false,
|
||||
"version": "1.32.0",
|
||||
"version": "1.33.7",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.js",
|
||||
@@ -30,5 +30,5 @@
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "8374c3941a9d1398989b8f38fd4bfa2a2f29937b"
|
||||
"gitHead": "8abe62886ab50634b4b05abedd2981ec8ee0422e"
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ export class IframeClient {
|
||||
return window.self !== window.top;
|
||||
}
|
||||
|
||||
register<T = any>(action: string, handler: (data: IframeMessageData<T>) => Promise<void>) {
|
||||
register<T = any>(action: string, handler: (data: IframeMessageData<T>) => Promise<any>) {
|
||||
this.handlers[action] = handler;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,38 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.33.7](https://github.com/certd/certd/compare/v1.33.6...v1.33.7) (2025-04-22)
|
||||
|
||||
**Note:** Version bump only for package @certd/jdcloud
|
||||
|
||||
## [1.33.6](https://github.com/certd/certd/compare/v1.33.5...v1.33.6) (2025-04-20)
|
||||
|
||||
**Note:** Version bump only for package @certd/jdcloud
|
||||
|
||||
## [1.33.5](https://github.com/certd/certd/compare/v1.33.4...v1.33.5) (2025-04-17)
|
||||
|
||||
**Note:** Version bump only for package @certd/jdcloud
|
||||
|
||||
## [1.33.4](https://github.com/certd/certd/compare/v1.33.3...v1.33.4) (2025-04-15)
|
||||
|
||||
**Note:** Version bump only for package @certd/jdcloud
|
||||
|
||||
## [1.33.3](https://github.com/certd/certd/compare/v1.33.2...v1.33.3) (2025-04-14)
|
||||
|
||||
**Note:** Version bump only for package @certd/jdcloud
|
||||
|
||||
## [1.33.2](https://github.com/certd/certd/compare/v1.33.1...v1.33.2) (2025-04-12)
|
||||
|
||||
**Note:** Version bump only for package @certd/jdcloud
|
||||
|
||||
## [1.33.1](https://github.com/certd/certd/compare/v1.33.0...v1.33.1) (2025-04-12)
|
||||
|
||||
**Note:** Version bump only for package @certd/jdcloud
|
||||
|
||||
# [1.33.0](https://github.com/certd/certd/compare/v1.32.0...v1.33.0) (2025-04-11)
|
||||
|
||||
**Note:** Version bump only for package @certd/jdcloud
|
||||
|
||||
# [1.32.0](https://github.com/certd/certd/compare/v1.31.11...v1.32.0) (2025-04-04)
|
||||
|
||||
**Note:** Version bump only for package @certd/jdcloud
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@certd/jdcloud",
|
||||
"version": "1.32.0",
|
||||
"version": "1.33.7",
|
||||
"description": "jdcloud openApi sdk",
|
||||
"main": "./dist/bundle.js",
|
||||
"module": "./dist/bundle.js",
|
||||
@@ -60,5 +60,5 @@
|
||||
"fetch"
|
||||
]
|
||||
},
|
||||
"gitHead": "8374c3941a9d1398989b8f38fd4bfa2a2f29937b"
|
||||
"gitHead": "8abe62886ab50634b4b05abedd2981ec8ee0422e"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,38 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.33.7](https://github.com/certd/certd/compare/v1.33.6...v1.33.7) (2025-04-22)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-k8s
|
||||
|
||||
## [1.33.6](https://github.com/certd/certd/compare/v1.33.5...v1.33.6) (2025-04-20)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-k8s
|
||||
|
||||
## [1.33.5](https://github.com/certd/certd/compare/v1.33.4...v1.33.5) (2025-04-17)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-k8s
|
||||
|
||||
## [1.33.4](https://github.com/certd/certd/compare/v1.33.3...v1.33.4) (2025-04-15)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-k8s
|
||||
|
||||
## [1.33.3](https://github.com/certd/certd/compare/v1.33.2...v1.33.3) (2025-04-14)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-k8s
|
||||
|
||||
## [1.33.2](https://github.com/certd/certd/compare/v1.33.1...v1.33.2) (2025-04-12)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-k8s
|
||||
|
||||
## [1.33.1](https://github.com/certd/certd/compare/v1.33.0...v1.33.1) (2025-04-12)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-k8s
|
||||
|
||||
# [1.33.0](https://github.com/certd/certd/compare/v1.32.0...v1.33.0) (2025-04-11)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-k8s
|
||||
|
||||
# [1.32.0](https://github.com/certd/certd/compare/v1.31.11...v1.32.0) (2025-04-04)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-k8s
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/lib-k8s",
|
||||
"private": false,
|
||||
"version": "1.32.0",
|
||||
"version": "1.33.7",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.js",
|
||||
@@ -16,7 +16,7 @@
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@certd/basic": "^1.32.0",
|
||||
"@certd/basic": "^1.33.7",
|
||||
"@kubernetes/client-node": "0.21.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -31,5 +31,5 @@
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "8374c3941a9d1398989b8f38fd4bfa2a2f29937b"
|
||||
"gitHead": "8abe62886ab50634b4b05abedd2981ec8ee0422e"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,40 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.33.7](https://github.com/certd/certd/compare/v1.33.6...v1.33.7) (2025-04-22)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-server
|
||||
|
||||
## [1.33.6](https://github.com/certd/certd/compare/v1.33.5...v1.33.6) (2025-04-20)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-server
|
||||
|
||||
## [1.33.5](https://github.com/certd/certd/compare/v1.33.4...v1.33.5) (2025-04-17)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 登录支持双重认证 ([48aef25](https://github.com/certd/certd/commit/48aef25b3f6499d674ca4e4ef16f4c62399fb735))
|
||||
|
||||
## [1.33.4](https://github.com/certd/certd/compare/v1.33.3...v1.33.4) (2025-04-15)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-server
|
||||
|
||||
## [1.33.3](https://github.com/certd/certd/compare/v1.33.2...v1.33.3) (2025-04-14)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-server
|
||||
|
||||
## [1.33.2](https://github.com/certd/certd/compare/v1.33.1...v1.33.2) (2025-04-12)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-server
|
||||
|
||||
## [1.33.1](https://github.com/certd/certd/compare/v1.33.0...v1.33.1) (2025-04-12)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-server
|
||||
|
||||
# [1.33.0](https://github.com/certd/certd/compare/v1.32.0...v1.33.0) (2025-04-11)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-server
|
||||
|
||||
# [1.32.0](https://github.com/certd/certd/compare/v1.31.11...v1.32.0) (2025-04-04)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-server
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@certd/lib-server",
|
||||
"version": "1.32.0",
|
||||
"version": "1.33.7",
|
||||
"description": "midway with flyway, sql upgrade way ",
|
||||
"private": false,
|
||||
"type": "module",
|
||||
@@ -27,10 +27,10 @@
|
||||
],
|
||||
"license": "AGPL",
|
||||
"dependencies": {
|
||||
"@certd/acme-client": "^1.32.0",
|
||||
"@certd/basic": "^1.32.0",
|
||||
"@certd/pipeline": "^1.32.0",
|
||||
"@certd/plus-core": "^1.32.0",
|
||||
"@certd/acme-client": "^1.33.7",
|
||||
"@certd/basic": "^1.33.7",
|
||||
"@certd/pipeline": "^1.33.7",
|
||||
"@certd/plus-core": "^1.33.7",
|
||||
"@midwayjs/cache": "~3.14.0",
|
||||
"@midwayjs/core": "~3.20.3",
|
||||
"@midwayjs/i18n": "~3.20.3",
|
||||
@@ -61,5 +61,5 @@
|
||||
"typeorm": "^0.3.11",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "8374c3941a9d1398989b8f38fd4bfa2a2f29937b"
|
||||
"gitHead": "8abe62886ab50634b4b05abedd2981ec8ee0422e"
|
||||
}
|
||||
|
||||
@@ -217,4 +217,20 @@ export abstract class BaseService<T> {
|
||||
}
|
||||
throw new PermissionException('权限不足');
|
||||
}
|
||||
|
||||
async batchDelete(ids: number[], userId: number) {
|
||||
if(userId >0){
|
||||
const list = await this.getRepository().find({
|
||||
where: {
|
||||
// @ts-ignore
|
||||
id: In(ids),
|
||||
userId,
|
||||
},
|
||||
})
|
||||
// @ts-ignore
|
||||
ids = list.map(item => item.id)
|
||||
}
|
||||
|
||||
await this.delete(ids);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,10 +66,19 @@ export const Constants = {
|
||||
code: 404,
|
||||
message: '页面/文件/资源不存在',
|
||||
},
|
||||
|
||||
preview: {
|
||||
code: 10001,
|
||||
message: '对不起,预览环境不允许修改此数据',
|
||||
},
|
||||
siteOff:{
|
||||
code: 10010,
|
||||
message: '站点已关闭',
|
||||
},
|
||||
need2fa:{
|
||||
code: 10020,
|
||||
message: '需要2FA认证',
|
||||
},
|
||||
openKeyError: {
|
||||
code: 20000,
|
||||
message: 'ApiToken错误',
|
||||
|
||||
@@ -1,10 +1,19 @@
|
||||
import { Constants } from '../constants.js';
|
||||
import { BaseException } from './base-exception.js';
|
||||
import { TextException } from "./common-exception.js";
|
||||
/**
|
||||
* 授权异常
|
||||
*/
|
||||
export class AuthException extends BaseException {
|
||||
constructor(message) {
|
||||
constructor(message?:string) {
|
||||
super('AuthException', Constants.res.auth.code, message ? message : Constants.res.auth.message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class Need2FAException extends TextException {
|
||||
constructor(message:string,data:any) {
|
||||
super('Need2FAException', Constants.res.need2fa.code, message ? message : Constants.res.need2fa.message,data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,9 +3,11 @@
|
||||
*/
|
||||
export class BaseException extends Error {
|
||||
code: number;
|
||||
constructor(name, code, message) {
|
||||
data?:any
|
||||
constructor(name, code, message,data?:any) {
|
||||
super(message);
|
||||
this.name = name;
|
||||
this.code = code;
|
||||
this.data = data;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,23 @@
|
||||
import { Constants } from '../constants.js';
|
||||
import { BaseException } from './base-exception.js';
|
||||
import { Constants } from "../constants.js";
|
||||
import { BaseException } from "./base-exception.js";
|
||||
|
||||
/**
|
||||
* 通用异常
|
||||
*/
|
||||
export class CommonException extends BaseException {
|
||||
constructor(message) {
|
||||
super('CommonException', Constants.res.error.code, message ? message : Constants.res.error.message);
|
||||
super("CommonException", Constants.res.error.code, message ? message : Constants.res.error.message);
|
||||
}
|
||||
}
|
||||
|
||||
export class CodeException extends BaseException {
|
||||
constructor(res: { code: number; message: string }) {
|
||||
super('CodeException', res.code, res.message);
|
||||
super("CodeException", res.code, res.message);
|
||||
}
|
||||
}
|
||||
|
||||
export class TextException extends BaseException {
|
||||
constructor(name, code,message, data?) {
|
||||
super(name, code, message, data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,3 +7,4 @@ export * from './vip-exception.js';
|
||||
export * from './common-exception.js';
|
||||
export * from './not-found-exception.js';
|
||||
export * from './param-exception.js';
|
||||
export * from './site-off-exception.js';
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
import { Constants } from '../constants.js';
|
||||
import { BaseException } from './base-exception.js';
|
||||
/**
|
||||
*/
|
||||
export class SiteOffException extends BaseException {
|
||||
constructor(message) {
|
||||
super('SiteOffException', Constants.res.siteOff.code, message ? message : Constants.res.siteOff.message);
|
||||
}
|
||||
}
|
||||
@@ -2,14 +2,15 @@ export class Result<T> {
|
||||
code: number;
|
||||
msg: string;
|
||||
data: T;
|
||||
|
||||
constructor(code, msg, data?) {
|
||||
this.code = code;
|
||||
this.msg = msg;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
static error(code = 1, msg) {
|
||||
return new Result(code, msg);
|
||||
static error(code = 1, msg, data?: any) {
|
||||
return new Result(code, msg, data);
|
||||
}
|
||||
|
||||
static success(msg, data?) {
|
||||
|
||||
@@ -171,7 +171,7 @@ export class SysSuiteSetting extends BaseSettings {
|
||||
static __key__ = 'sys.suite';
|
||||
static __access__ = 'private';
|
||||
|
||||
enabled = false;
|
||||
enabled:boolean = false;
|
||||
|
||||
registerGift?: {
|
||||
productId: number;
|
||||
@@ -180,3 +180,25 @@ export class SysSuiteSetting extends BaseSettings {
|
||||
|
||||
intro?: string;
|
||||
}
|
||||
|
||||
|
||||
export type SiteHidden = {
|
||||
enabled: boolean;
|
||||
openPath?: string;
|
||||
//md5 hash 两次后保存
|
||||
openPassword?: string;
|
||||
autoHiddenTimes?: number;
|
||||
hiddenOpenApi?: boolean
|
||||
};
|
||||
export class SysSafeSetting extends BaseSettings {
|
||||
static __title__ = '站点安全设置';
|
||||
static __key__ = 'sys.safe';
|
||||
static __access__ = 'private';
|
||||
|
||||
// 站点隐藏
|
||||
hidden:SiteHidden = {
|
||||
enabled: false,
|
||||
hiddenOpenApi:false,
|
||||
autoHiddenTimes: 5,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -140,7 +140,7 @@ export class AccessService extends BaseService<AccessEntity> {
|
||||
id: entity.id,
|
||||
...setting,
|
||||
};
|
||||
return newAccess(entity.type, input);
|
||||
return await newAccess(entity.type, input);
|
||||
}
|
||||
|
||||
async getById(id: any, userId: number): Promise<any> {
|
||||
|
||||
@@ -3,6 +3,38 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.33.7](https://github.com/certd/certd/compare/v1.33.6...v1.33.7) (2025-04-22)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
## [1.33.6](https://github.com/certd/certd/compare/v1.33.5...v1.33.6) (2025-04-20)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
## [1.33.5](https://github.com/certd/certd/compare/v1.33.4...v1.33.5) (2025-04-17)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
## [1.33.4](https://github.com/certd/certd/compare/v1.33.3...v1.33.4) (2025-04-15)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
## [1.33.3](https://github.com/certd/certd/compare/v1.33.2...v1.33.3) (2025-04-14)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
## [1.33.2](https://github.com/certd/certd/compare/v1.33.1...v1.33.2) (2025-04-12)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
## [1.33.1](https://github.com/certd/certd/compare/v1.33.0...v1.33.1) (2025-04-12)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
# [1.33.0](https://github.com/certd/certd/compare/v1.32.0...v1.33.0) (2025-04-11)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
# [1.32.0](https://github.com/certd/certd/compare/v1.31.11...v1.32.0) (2025-04-04)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@certd/midway-flyway-js",
|
||||
"version": "1.32.0",
|
||||
"version": "1.33.7",
|
||||
"description": "midway with flyway, sql upgrade way ",
|
||||
"private": false,
|
||||
"type": "module",
|
||||
@@ -46,5 +46,5 @@
|
||||
"typeorm": "^0.3.11",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "8374c3941a9d1398989b8f38fd4bfa2a2f29937b"
|
||||
"gitHead": "8abe62886ab50634b4b05abedd2981ec8ee0422e"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,48 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.33.7](https://github.com/certd/certd/compare/v1.33.6...v1.33.7) (2025-04-22)
|
||||
|
||||
**Note:** Version bump only for package @certd/plugin-cert
|
||||
|
||||
## [1.33.6](https://github.com/certd/certd/compare/v1.33.5...v1.33.6) (2025-04-20)
|
||||
|
||||
**Note:** Version bump only for package @certd/plugin-cert
|
||||
|
||||
## [1.33.5](https://github.com/certd/certd/compare/v1.33.4...v1.33.5) (2025-04-17)
|
||||
|
||||
**Note:** Version bump only for package @certd/plugin-cert
|
||||
|
||||
## [1.33.4](https://github.com/certd/certd/compare/v1.33.3...v1.33.4) (2025-04-15)
|
||||
|
||||
**Note:** Version bump only for package @certd/plugin-cert
|
||||
|
||||
## [1.33.3](https://github.com/certd/certd/compare/v1.33.2...v1.33.3) (2025-04-14)
|
||||
|
||||
**Note:** Version bump only for package @certd/plugin-cert
|
||||
|
||||
## [1.33.2](https://github.com/certd/certd/compare/v1.33.1...v1.33.2) (2025-04-12)
|
||||
|
||||
**Note:** Version bump only for package @certd/plugin-cert
|
||||
|
||||
## [1.33.1](https://github.com/certd/certd/compare/v1.33.0...v1.33.1) (2025-04-12)
|
||||
|
||||
**Note:** Version bump only for package @certd/plugin-cert
|
||||
|
||||
# [1.33.0](https://github.com/certd/certd/compare/v1.32.0...v1.33.0) (2025-04-11)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复eab授权,没有email绑定的bug ([2f1683b](https://github.com/certd/certd/commit/2f1683b26acebbfb7d6e2d751435be04a4e7cab4))
|
||||
|
||||
### Features
|
||||
|
||||
* **lego:** support set key type ([f3bf4fa](https://github.com/certd/certd/commit/f3bf4faee0be5bdbfdbcf70a502849ed4c8ed4c4))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 增加手动上传证书功能说明 ([5d083a1](https://github.com/certd/certd/commit/5d083a153637caddbc6f44e915d9fb2d1ae87b33))
|
||||
|
||||
# [1.32.0](https://github.com/certd/certd/compare/v1.31.11...v1.32.0) (2025-04-04)
|
||||
|
||||
**Note:** Version bump only for package @certd/plugin-cert
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/plugin-cert",
|
||||
"private": false,
|
||||
"version": "1.32.0",
|
||||
"version": "1.33.7",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
@@ -15,10 +15,10 @@
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@certd/acme-client": "^1.32.0",
|
||||
"@certd/basic": "^1.32.0",
|
||||
"@certd/pipeline": "^1.32.0",
|
||||
"@certd/plugin-lib": "^1.32.0",
|
||||
"@certd/acme-client": "^1.33.7",
|
||||
"@certd/basic": "^1.33.7",
|
||||
"@certd/pipeline": "^1.33.7",
|
||||
"@certd/plugin-lib": "^1.33.7",
|
||||
"@google-cloud/publicca": "^1.3.0",
|
||||
"dayjs": "^1.11.7",
|
||||
"jszip": "^3.10.1",
|
||||
@@ -41,5 +41,5 @@
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "8374c3941a9d1398989b8f38fd4bfa2a2f29937b"
|
||||
"gitHead": "8abe62886ab50634b4b05abedd2981ec8ee0422e"
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ export class EabAccess extends BaseAccess {
|
||||
component: {
|
||||
placeholder: "绑定一个邮箱",
|
||||
},
|
||||
rules: { type: "email", message: "请输入正确的邮箱" },
|
||||
rules: [{ type: "email", message: "请输入正确的邮箱" }],
|
||||
helper: "Google的EAB申请证书,更换邮箱会导致EAB失效,可以在此处绑定一个邮箱避免此问题",
|
||||
required: true,
|
||||
})
|
||||
|
||||
@@ -27,6 +27,7 @@ export type DnsProviderContext = {
|
||||
logger: ILogger;
|
||||
http: HttpClient;
|
||||
utils: typeof utils;
|
||||
domainParser: IDomainParser;
|
||||
};
|
||||
|
||||
export interface IDnsProvider<T = any> {
|
||||
@@ -35,3 +36,11 @@ export interface IDnsProvider<T = any> {
|
||||
removeRecord(options: RemoveRecordOptions<T>): Promise<void>;
|
||||
setCtx(ctx: DnsProviderContext): void;
|
||||
}
|
||||
|
||||
export interface ISubDomainsGetter {
|
||||
getSubDomains(): Promise<string[]>;
|
||||
}
|
||||
|
||||
export interface IDomainParser {
|
||||
parse(fullDomain: string): Promise<string>;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import { CreateRecordOptions, DnsProviderContext, DnsProviderDefine, IDnsProvider, RemoveRecordOptions } from "./api.js";
|
||||
//@ts-ignore
|
||||
import psl from "psl";
|
||||
import { dnsProviderRegistry } from "./registry.js";
|
||||
import { Decorator } from "@certd/pipeline";
|
||||
import { HttpClient, ILogger } from "@certd/basic";
|
||||
@@ -16,6 +14,10 @@ export abstract class AbstractDnsProvider<T = any> implements IDnsProvider<T> {
|
||||
this.http = ctx.http;
|
||||
}
|
||||
|
||||
async parseDomain(fullDomain: string) {
|
||||
return await this.ctx.domainParser.parse(fullDomain);
|
||||
}
|
||||
|
||||
abstract createRecord(options: CreateRecordOptions): Promise<T>;
|
||||
|
||||
abstract onInstance(): Promise<void>;
|
||||
@@ -23,14 +25,6 @@ export abstract class AbstractDnsProvider<T = any> implements IDnsProvider<T> {
|
||||
abstract removeRecord(options: RemoveRecordOptions<T>): Promise<void>;
|
||||
}
|
||||
|
||||
export function parseDomain(fullDomain: string) {
|
||||
const parsed = psl.parse(fullDomain) as psl.ParsedDomain;
|
||||
if (parsed.error) {
|
||||
throw new Error(`解析${fullDomain}域名失败:` + JSON.stringify(parsed.error));
|
||||
}
|
||||
return parsed.domain as string;
|
||||
}
|
||||
|
||||
export async function createDnsProvider(opts: { dnsProviderType: string; context: DnsProviderContext }): Promise<IDnsProvider> {
|
||||
const { dnsProviderType, context } = opts;
|
||||
const dnsProviderPlugin = dnsProviderRegistry.get(dnsProviderType);
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
import { IDomainParser, ISubDomainsGetter } from "./api";
|
||||
//@ts-ignore
|
||||
import psl from "psl";
|
||||
|
||||
export class DomainParser implements IDomainParser {
|
||||
subDomainsGetter: ISubDomainsGetter;
|
||||
constructor(subDomainsGetter: ISubDomainsGetter) {
|
||||
this.subDomainsGetter = subDomainsGetter;
|
||||
}
|
||||
|
||||
parseDomain(fullDomain: string) {
|
||||
const parsed = psl.parse(fullDomain) as psl.ParsedDomain;
|
||||
if (parsed.error) {
|
||||
throw new Error(`解析${fullDomain}域名失败:` + JSON.stringify(parsed.error));
|
||||
}
|
||||
return parsed.domain as string;
|
||||
}
|
||||
|
||||
async parse(fullDomain: string) {
|
||||
const subDomains = await this.subDomainsGetter.getSubDomains();
|
||||
if (subDomains && subDomains.length > 0) {
|
||||
for (const subDomain of subDomains) {
|
||||
if (fullDomain.endsWith(subDomain)) {
|
||||
//找到子域名托管
|
||||
return subDomain;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this.parseDomain(fullDomain);
|
||||
}
|
||||
}
|
||||
@@ -5,8 +5,9 @@ import * as _ from "lodash-es";
|
||||
import { Challenge } from "@certd/acme-client/types/rfc8555";
|
||||
import { IContext } from "@certd/pipeline";
|
||||
import { ILogger, utils } from "@certd/basic";
|
||||
import { IDnsProvider, parseDomain } from "../../dns-provider/index.js";
|
||||
import { IDnsProvider, IDomainParser } from "../../dns-provider/index.js";
|
||||
import { HttpChallengeUploader } from "./uploads/api.js";
|
||||
|
||||
export type CnameVerifyPlan = {
|
||||
type?: string;
|
||||
domain: string;
|
||||
@@ -61,6 +62,8 @@ type AcmeServiceOptions = {
|
||||
privateKeyType?: PrivateKeyType;
|
||||
signal?: AbortSignal;
|
||||
maxCheckRetryCount?: number;
|
||||
userId: number;
|
||||
domainParser: IDomainParser;
|
||||
};
|
||||
|
||||
export class AcmeService {
|
||||
@@ -174,7 +177,7 @@ export class AcmeService {
|
||||
this.logger.info("Triggered challengeCreateFn()");
|
||||
|
||||
const fullDomain = authz.identifier.value;
|
||||
let domain = parseDomain(fullDomain);
|
||||
let domain = await this.options.domainParser.parse(fullDomain);
|
||||
this.logger.info("主域名为:" + domain);
|
||||
|
||||
const getChallenge = (type: string) => {
|
||||
@@ -240,7 +243,7 @@ export class AcmeService {
|
||||
const cname = cnameVerifyPlan[fullDomain];
|
||||
if (cname) {
|
||||
dnsProvider = cname.dnsProvider;
|
||||
domain = parseDomain(cname.domain);
|
||||
domain = await this.options.domainParser.parse(cname.domain);
|
||||
fullRecord = cname.fullRecord;
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -27,7 +27,8 @@ export abstract class CertApplyBaseConvertPlugin extends AbstractTaskPlugin {
|
||||
"1、支持多个域名打到一个证书上,例如: foo.com,*.foo.com,*.bar.com\n" +
|
||||
"2、子域名被通配符包含的不要填写,例如:www.foo.com已经被*.foo.com包含,不要填写www.foo.com\n" +
|
||||
"3、泛域名只能通配*号那一级(*.foo.com的证书不能用于xxx.yyy.foo.com、不能用于foo.com)\n" +
|
||||
"4、输入一个,空格之后,再输入下一个",
|
||||
"4、输入一个,空格之后,再输入下一个\n" +
|
||||
"5、如果你配置了子域托管解析,请先[设置托管子域名](#/certd/pipeline/subDomain)",
|
||||
})
|
||||
domains!: string[];
|
||||
|
||||
|
||||
@@ -9,9 +9,9 @@ export type { CertInfo };
|
||||
@IsTaskPlugin({
|
||||
name: "CertApplyUpload",
|
||||
icon: "ph:certificate",
|
||||
title: "证书手动上传",
|
||||
title: "商用证书托管",
|
||||
group: pluginGroups.cert.key,
|
||||
desc: "在证书仓库手动上传后触发部署证书",
|
||||
desc: "手动上传自定义证书后,自动部署(每次证书有更新,都需要手动上传一次)",
|
||||
default: {
|
||||
strategy: {
|
||||
runStrategy: RunStrategy.AlwaysRun,
|
||||
|
||||
@@ -4,12 +4,13 @@ import { utils } from "@certd/basic";
|
||||
import type { CertInfo, CnameVerifyPlan, DomainsVerifyPlan, HttpVerifyPlan, PrivateKeyType, SSLProvider } from "./acme.js";
|
||||
import { AcmeService } from "./acme.js";
|
||||
import * as _ from "lodash-es";
|
||||
import { createDnsProvider, DnsProviderContext, IDnsProvider } from "../../dns-provider/index.js";
|
||||
import { createDnsProvider, DnsProviderContext, IDnsProvider, ISubDomainsGetter } from "../../dns-provider/index.js";
|
||||
import { CertReader } from "./cert-reader.js";
|
||||
import { CertApplyBasePlugin } from "./base.js";
|
||||
import { GoogleClient } from "../../libs/google.js";
|
||||
import { EabAccess } from "../../access";
|
||||
import { httpChallengeUploaderFactory } from "./uploads/factory.js";
|
||||
import { DomainParser } from "../../dns-provider/domain-parser.js";
|
||||
export * from "./base.js";
|
||||
export type { CertInfo };
|
||||
export * from "./cert-reader.js";
|
||||
@@ -28,6 +29,7 @@ export type DomainVerifyPlanInput = {
|
||||
domain: string;
|
||||
type: "cname" | "dns" | "http";
|
||||
dnsProviderType?: string;
|
||||
dnsProviderAccessType?: string;
|
||||
dnsProviderAccessId?: number;
|
||||
cnameVerifyPlan?: Record<string, CnameRecordInput>;
|
||||
httpVerifyPlan?: Record<string, HttpRecordInput>;
|
||||
@@ -98,7 +100,14 @@ HTTP文件验证:不支持泛域名,需要配置网站文件上传`,
|
||||
return {
|
||||
show: ctx.compute(({form})=>{
|
||||
return form.challengeType === 'dns'
|
||||
})
|
||||
}),
|
||||
component:{
|
||||
on:{
|
||||
selectedChange({form,$event}){
|
||||
form.dnsProviderAccessType = $event.accessType
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
required: true,
|
||||
@@ -106,6 +115,8 @@ HTTP文件验证:不支持泛域名,需要配置网站文件上传`,
|
||||
})
|
||||
dnsProviderType!: string;
|
||||
|
||||
dnsProviderAccessType!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: "DNS解析授权",
|
||||
component: {
|
||||
@@ -116,7 +127,7 @@ HTTP文件验证:不支持泛域名,需要配置网站文件上传`,
|
||||
mergeScript: `return {
|
||||
component:{
|
||||
type: ctx.compute(({form})=>{
|
||||
return form.dnsProviderType
|
||||
return form.dnsProviderAccessType || form.dnsProviderType
|
||||
})
|
||||
},
|
||||
show: ctx.compute(({form})=>{
|
||||
@@ -287,7 +298,7 @@ HTTP文件验证:不支持泛域名,需要配置网站文件上传`,
|
||||
if (this.sslProvider === "google") {
|
||||
if (this.googleAccessId) {
|
||||
this.logger.info("当前正在使用 google服务账号授权获取EAB");
|
||||
const googleAccess = await this.ctx.accessService.getById(this.googleAccessId);
|
||||
const googleAccess = await this.getAccess(this.googleAccessId);
|
||||
const googleClient = new GoogleClient({
|
||||
access: googleAccess,
|
||||
logger: this.logger,
|
||||
@@ -295,26 +306,29 @@ HTTP文件验证:不支持泛域名,需要配置网站文件上传`,
|
||||
eab = await googleClient.getEab();
|
||||
} else if (this.eabAccessId) {
|
||||
this.logger.info("当前正在使用 google EAB授权");
|
||||
eab = await this.ctx.accessService.getById(this.eabAccessId);
|
||||
eab = await this.getAccess(this.eabAccessId);
|
||||
} else if (this.googleCommonEabAccessId) {
|
||||
this.logger.info("当前正在使用 google公共EAB授权");
|
||||
eab = await this.ctx.accessService.getCommonById(this.googleCommonEabAccessId);
|
||||
eab = await this.getAccess(this.googleCommonEabAccessId, true);
|
||||
} else {
|
||||
throw new Error("google需要配置EAB授权或服务账号授权");
|
||||
}
|
||||
} else if (this.sslProvider === "zerossl") {
|
||||
if (this.eabAccessId) {
|
||||
this.logger.info("当前正在使用 zerossl EAB授权");
|
||||
eab = await this.ctx.accessService.getById(this.eabAccessId);
|
||||
eab = await this.getAccess(this.eabAccessId);
|
||||
} else if (this.zerosslCommonEabAccessId) {
|
||||
this.logger.info("当前正在使用 zerossl 公共EAB授权");
|
||||
eab = await this.ctx.accessService.getCommonById(this.zerosslCommonEabAccessId);
|
||||
eab = await this.getAccess(this.zerosslCommonEabAccessId, true);
|
||||
} else {
|
||||
throw new Error("zerossl需要配置EAB授权");
|
||||
}
|
||||
}
|
||||
this.eab = eab;
|
||||
const subDomainsGetter = await this.ctx.serviceGetter.get<ISubDomainsGetter>("subDomainsGetter");
|
||||
const domainParser = new DomainParser(subDomainsGetter);
|
||||
this.acme = new AcmeService({
|
||||
userId: this.ctx.user.id,
|
||||
userContext: this.userContext,
|
||||
logger: this.logger,
|
||||
sslProvider: this.sslProvider,
|
||||
@@ -325,8 +339,7 @@ HTTP文件验证:不支持泛域名,需要配置网站文件上传`,
|
||||
privateKeyType: this.privateKeyType,
|
||||
signal: this.ctx.signal,
|
||||
maxCheckRetryCount: this.maxCheckRetryCount,
|
||||
// cnameProxyService: this.ctx.cnameProxyService,
|
||||
// dnsProviderCreator: this.createDnsProvider.bind(this),
|
||||
domainParser,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -356,7 +369,7 @@ HTTP文件验证:不支持泛域名,需要配置网站文件上传`,
|
||||
domainsVerifyPlan = await this.createDomainsVerifyPlan();
|
||||
} else {
|
||||
const dnsProviderType = this.dnsProviderType;
|
||||
const access = await this.ctx.accessService.getById(this.dnsProviderAccess);
|
||||
const access = await this.getAccess(this.dnsProviderAccess);
|
||||
dnsProvider = await this.createDnsProvider(dnsProviderType, access);
|
||||
}
|
||||
|
||||
@@ -387,7 +400,8 @@ HTTP文件验证:不支持泛域名,需要配置网站文件上传`,
|
||||
}
|
||||
|
||||
async createDnsProvider(dnsProviderType: string, dnsProviderAccess: any): Promise<IDnsProvider> {
|
||||
const context: DnsProviderContext = { access: dnsProviderAccess, logger: this.logger, http: this.ctx.http, utils };
|
||||
const domainParser = this.acme.options.domainParser;
|
||||
const context: DnsProviderContext = { access: dnsProviderAccess, logger: this.logger, http: this.ctx.http, utils, domainParser };
|
||||
return await createDnsProvider({
|
||||
dnsProviderType,
|
||||
context,
|
||||
@@ -402,7 +416,7 @@ HTTP文件验证:不支持泛域名,需要配置网站文件上传`,
|
||||
const cnameVerifyPlan: Record<string, CnameVerifyPlan> = {};
|
||||
const httpVerifyPlan: Record<string, HttpVerifyPlan> = {};
|
||||
if (domainVerifyPlan.type === "dns") {
|
||||
const access = await this.ctx.accessService.getById(domainVerifyPlan.dnsProviderAccessId);
|
||||
const access = await this.getAccess(domainVerifyPlan.dnsProviderAccessId);
|
||||
dnsProvider = await this.createDnsProvider(domainVerifyPlan.dnsProviderType, access);
|
||||
} else if (domainVerifyPlan.type === "cname") {
|
||||
for (const key in domainVerifyPlan.cnameVerifyPlan) {
|
||||
@@ -426,7 +440,7 @@ HTTP文件验证:不支持泛域名,需要配置网站文件上传`,
|
||||
};
|
||||
for (const key in domainVerifyPlan.httpVerifyPlan) {
|
||||
const httpRecord = domainVerifyPlan.httpVerifyPlan[key];
|
||||
const access = await this.ctx.accessService.getById(httpRecord.httpUploaderAccess);
|
||||
const access = await this.getAccess(httpRecord.httpUploaderAccess);
|
||||
let rootDir = httpRecord.httpUploadRootDir;
|
||||
if (!rootDir.endsWith("/") && !rootDir.endsWith("\\")) {
|
||||
rootDir = rootDir + "/";
|
||||
|
||||
@@ -9,6 +9,7 @@ import JSZip from "jszip";
|
||||
|
||||
export { CertReader };
|
||||
export type { CertInfo };
|
||||
export type PrivateKeyType = "rsa2048" | "rsa3072" | "rsa4096" | "rsa8192" | "ec256" | "ec384";
|
||||
|
||||
@IsTaskPlugin({
|
||||
name: "CertApplyLego",
|
||||
@@ -90,6 +91,28 @@ export class CertApplyLegoPlugin extends CertApplyBasePlugin {
|
||||
})
|
||||
customArgs = "";
|
||||
|
||||
@TaskInput({
|
||||
title: "加密算法",
|
||||
value: "ec256",
|
||||
component: {
|
||||
name: "a-select",
|
||||
vModel: "value",
|
||||
options: [
|
||||
{ value: "rsa2048", label: "RSA 2048" },
|
||||
{ value: "rsa3072", label: "RSA 3072" },
|
||||
{ value: "rsa4096", label: "RSA 4096" },
|
||||
{ value: "rsa8192", label: "RSA 8192" },
|
||||
{ value: "ec256", label: "EC 256" },
|
||||
{ value: "ec384", label: "EC 384" },
|
||||
// { value: "ec_521", label: "EC 521" },
|
||||
],
|
||||
},
|
||||
helper: "如无特殊需求,默认即可",
|
||||
required: true,
|
||||
})
|
||||
privateKeyType!: PrivateKeyType;
|
||||
|
||||
|
||||
eab?: EabAccess;
|
||||
|
||||
async onInstance() {
|
||||
@@ -120,7 +143,7 @@ export class CertApplyLegoPlugin extends CertApplyBasePlugin {
|
||||
if (this.eab) {
|
||||
eabArgs = ` --eab --kid "${this.eab.kid}" --hmac "${this.eab.hmacKey}"`;
|
||||
}
|
||||
const keyType = "-k rsa2048";
|
||||
const keyType = `-k ${this.privateKeyType}`;
|
||||
|
||||
const saveDir = `./data/.lego/pipeline_${this.pipeline.id}/`;
|
||||
const savePathArgs = `--path "${saveDir}"`;
|
||||
|
||||
@@ -3,6 +3,43 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.33.7](https://github.com/certd/certd/compare/v1.33.6...v1.33.7) (2025-04-22)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* ssh PTY模式登录设置 ([8385bcc](https://github.com/certd/certd/commit/8385bcc2d7f2411a07748bb5c53f9eaf4d38d7cc))
|
||||
* ssh伪终端模式优化,windows下不开启 ([42dfe93](https://github.com/certd/certd/commit/42dfe936b773b7bdd82ca3378363252ffffd7b71))
|
||||
|
||||
## [1.33.6](https://github.com/certd/certd/compare/v1.33.5...v1.33.6) (2025-04-20)
|
||||
|
||||
**Note:** Version bump only for package @certd/plugin-lib
|
||||
|
||||
## [1.33.5](https://github.com/certd/certd/compare/v1.33.4...v1.33.5) (2025-04-17)
|
||||
|
||||
**Note:** Version bump only for package @certd/plugin-lib
|
||||
|
||||
## [1.33.4](https://github.com/certd/certd/compare/v1.33.3...v1.33.4) (2025-04-15)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 插件支持导入导出 ([cf8abb4](https://github.com/certd/certd/commit/cf8abb45282070c8ba91469f93fd379fabf1f74a))
|
||||
|
||||
## [1.33.3](https://github.com/certd/certd/compare/v1.33.2...v1.33.3) (2025-04-14)
|
||||
|
||||
**Note:** Version bump only for package @certd/plugin-lib
|
||||
|
||||
## [1.33.2](https://github.com/certd/certd/compare/v1.33.1...v1.33.2) (2025-04-12)
|
||||
|
||||
**Note:** Version bump only for package @certd/plugin-lib
|
||||
|
||||
## [1.33.1](https://github.com/certd/certd/compare/v1.33.0...v1.33.1) (2025-04-12)
|
||||
|
||||
**Note:** Version bump only for package @certd/plugin-lib
|
||||
|
||||
# [1.33.0](https://github.com/certd/certd/compare/v1.32.0...v1.33.0) (2025-04-11)
|
||||
|
||||
**Note:** Version bump only for package @certd/plugin-lib
|
||||
|
||||
# [1.32.0](https://github.com/certd/certd/compare/v1.31.11...v1.32.0) (2025-04-04)
|
||||
|
||||
**Note:** Version bump only for package @certd/plugin-lib
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/plugin-lib",
|
||||
"private": false,
|
||||
"version": "1.32.0",
|
||||
"version": "1.33.7",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
@@ -16,8 +16,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@alicloud/pop-core": "^1.7.10",
|
||||
"@certd/basic": "^1.32.0",
|
||||
"@certd/pipeline": "^1.32.0",
|
||||
"@certd/basic": "^1.33.7",
|
||||
"@certd/pipeline": "^1.33.7",
|
||||
"@kubernetes/client-node": "0.21.0",
|
||||
"ali-oss": "^6.21.0",
|
||||
"basic-ftp": "^5.0.5",
|
||||
@@ -48,5 +48,5 @@
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "8374c3941a9d1398989b8f38fd4bfa2a2f29937b"
|
||||
"gitHead": "8abe62886ab50634b4b05abedd2981ec8ee0422e"
|
||||
}
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
import { AccessInput, BaseAccess, IsAccess } from "@certd/pipeline";
|
||||
import { ConnectConfig } from "ssh2";
|
||||
import { SshClient } from "./ssh.js";
|
||||
|
||||
@IsAccess({
|
||||
name: "ssh",
|
||||
title: "主机登录授权",
|
||||
@@ -9,7 +6,7 @@ import { SshClient } from "./ssh.js";
|
||||
icon: "clarity:host-line",
|
||||
input: {},
|
||||
})
|
||||
export class SshAccess extends BaseAccess implements ConnectConfig {
|
||||
export class SshAccess extends BaseAccess {
|
||||
@AccessInput({
|
||||
title: "主机地址",
|
||||
component: {
|
||||
@@ -66,6 +63,16 @@ export class SshAccess extends BaseAccess implements ConnectConfig {
|
||||
})
|
||||
passphrase!: string;
|
||||
|
||||
@AccessInput({
|
||||
title: "伪终端",
|
||||
helper: "如果登录报错:all authentication methods failed,可以尝试开启伪终端模式进行keyboard-interactive方式登录\n开启后对日志输出有一定的影响",
|
||||
component: {
|
||||
name: "a-switch",
|
||||
vModel: "checked",
|
||||
},
|
||||
})
|
||||
pty!: boolean;
|
||||
|
||||
@AccessInput({
|
||||
title: "socks代理",
|
||||
helper: "socks代理配置,格式:socks5://user:password@host:port",
|
||||
@@ -125,6 +132,7 @@ export class SshAccess extends BaseAccess implements ConnectConfig {
|
||||
testRequest = true;
|
||||
|
||||
async onTestRequest() {
|
||||
const { SshClient } = await import("./ssh.js");
|
||||
const client = new SshClient(this.ctx.logger);
|
||||
|
||||
await client.exec({
|
||||
|
||||
@@ -1,22 +1,33 @@
|
||||
// @ts-ignore
|
||||
import ssh2, { ConnectConfig, ExecOptions } from "ssh2";
|
||||
|
||||
import ssh2Constants from "ssh2/lib/protocol/constants.js";
|
||||
import path from "path";
|
||||
import * as _ from "lodash-es";
|
||||
import { isArray } from "lodash-es";
|
||||
import { ILogger } from "@certd/basic";
|
||||
import { SshAccess } from "./ssh-access.js";
|
||||
import stripAnsi from "strip-ansi";
|
||||
import { SocksClient } from "socks";
|
||||
import { SocksProxy, SocksProxyType } from "socks/typings/common/constants.js";
|
||||
|
||||
import fs from "fs";
|
||||
import { SocksProxyType } from "socks/typings/common/constants";
|
||||
|
||||
export type TransportItem = { localPath: string; remotePath: string };
|
||||
export interface SocksProxy {
|
||||
ipaddress?: string;
|
||||
host?: string;
|
||||
port: number;
|
||||
type: any;
|
||||
userId?: string;
|
||||
password?: string;
|
||||
custom_auth_method?: number;
|
||||
custom_auth_request_handler?: () => Promise<Buffer>;
|
||||
custom_auth_response_size?: number;
|
||||
custom_auth_response_handler?: (data: Buffer) => Promise<boolean>;
|
||||
}
|
||||
export type SshConnectConfig = {
|
||||
sock?: any;
|
||||
};
|
||||
|
||||
export class AsyncSsh2Client {
|
||||
conn: ssh2.Client;
|
||||
conn: any;
|
||||
logger: ILogger;
|
||||
connConf: SshAccess & ssh2.ConnectConfig;
|
||||
connConf: SshAccess & SshConnectConfig;
|
||||
windows = false;
|
||||
encoding: string;
|
||||
constructor(connConf: SshAccess, logger: ILogger) {
|
||||
@@ -40,7 +51,10 @@ export class AsyncSsh2Client {
|
||||
if (typeof this.connConf.port === "string") {
|
||||
this.connConf.port = parseInt(this.connConf.port);
|
||||
}
|
||||
const proxyOption: SocksProxy = this.parseSocksProxyFromUri(this.connConf.socksProxy);
|
||||
|
||||
const { SocksClient } = await import("socks");
|
||||
|
||||
const proxyOption = this.parseSocksProxyFromUri(this.connConf.socksProxy);
|
||||
const info = await SocksClient.createConnection({
|
||||
proxy: proxyOption,
|
||||
command: "connect",
|
||||
@@ -53,10 +67,12 @@ export class AsyncSsh2Client {
|
||||
this.connConf.sock = info.socket;
|
||||
}
|
||||
|
||||
const { SUPPORTED_KEX, SUPPORTED_SERVER_HOST_KEY, SUPPORTED_CIPHER, SUPPORTED_MAC } = ssh2Constants;
|
||||
const ssh2 = await import("ssh2");
|
||||
const ssh2Constants = await import("ssh2/lib/protocol/constants.js");
|
||||
const { SUPPORTED_KEX, SUPPORTED_SERVER_HOST_KEY, SUPPORTED_CIPHER, SUPPORTED_MAC } = ssh2Constants.default;
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
const conn = new ssh2.Client();
|
||||
const conn = new ssh2.default.Client();
|
||||
conn
|
||||
.on("error", (err: any) => {
|
||||
this.logger.error("连接失败", err);
|
||||
@@ -139,6 +155,7 @@ export class AsyncSsh2Client {
|
||||
script: string,
|
||||
opts: {
|
||||
throwOnStdErr?: boolean;
|
||||
env?: any;
|
||||
} = {}
|
||||
): Promise<string> {
|
||||
if (!script) {
|
||||
@@ -153,7 +170,10 @@ export class AsyncSsh2Client {
|
||||
// }
|
||||
return new Promise((resolve, reject) => {
|
||||
this.logger.info(`执行命令:[${this.connConf.host}][exec]: \n` + script);
|
||||
this.conn.exec(script, (err: Error, stream: any) => {
|
||||
// pty 伪终端,window下的输出会带上conhost.exe之类的多余的字符串,影响返回结果判断
|
||||
// linux下 当使用keyboard-interactive 登录时,需要pty
|
||||
const pty = this.connConf.pty; //linux下开启伪终端,windows下不开启
|
||||
this.conn.exec(script, { pty, env: opts.env }, (err: Error, stream: any) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
return;
|
||||
@@ -196,6 +216,8 @@ export class AsyncSsh2Client {
|
||||
}
|
||||
|
||||
async shell(script: string | string[]): Promise<string> {
|
||||
const stripAnsiModule = await import("strip-ansi");
|
||||
const stripAnsi = stripAnsiModule.default;
|
||||
return new Promise<any>((resolve, reject) => {
|
||||
this.logger.info(`执行shell脚本:[${this.connConf.host}][shell]: ` + script);
|
||||
this.conn.shell((err: Error, stream: any) => {
|
||||
@@ -448,7 +470,7 @@ export class SshClient {
|
||||
script = script.join(" && ");
|
||||
} else {
|
||||
const newLine = isLinux ? "\n" : "\r\n";
|
||||
if (_.isArray(script)) {
|
||||
if (isArray(script)) {
|
||||
script = script as Array<string>;
|
||||
script = script.join(newLine);
|
||||
}
|
||||
@@ -456,7 +478,7 @@ export class SshClient {
|
||||
script = envScripts.join(newLine) + newLine + script;
|
||||
}
|
||||
}
|
||||
return await conn.exec(script as string);
|
||||
return await conn.exec(script as string, {});
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -464,7 +486,7 @@ export class SshClient {
|
||||
async shell(options: { connectConf: SshAccess; script: string | Array<string> }): Promise<string> {
|
||||
let { script } = options;
|
||||
const { connectConf } = options;
|
||||
if (_.isArray(script)) {
|
||||
if (isArray(script)) {
|
||||
script = script as Array<string>;
|
||||
if (connectConf.windows) {
|
||||
script = script.join("\r\n");
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
FROM node:20-alpine AS builder
|
||||
FROM node:22-alpine AS builder
|
||||
WORKDIR /workspace/
|
||||
COPY . /workspace/
|
||||
# armv7 目前只能用node18, pnpm9不支持node18,所以pnpm只能用8.15.7版本
|
||||
# https://github.com/nodejs/docker-node/issues/1946
|
||||
RUN npm install -g pnpm@8.15.7
|
||||
RUN npm install -g pnpm
|
||||
|
||||
#RUN cd /workspace/certd-client && pnpm install && npm run build
|
||||
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:20-alpine
|
||||
FROM node:22-alpine
|
||||
EXPOSE 7001
|
||||
EXPOSE 7002
|
||||
RUN apk add --no-cache openssl
|
||||
@@ -18,8 +18,8 @@ RUN apk add --no-cache openjdk8
|
||||
WORKDIR /app/
|
||||
COPY --from=builder /workspace/certd-server/ /app/
|
||||
|
||||
ENV LEGO_VERSION 4.22.2
|
||||
ENV LEGO_DOWNLOAD_DIR /app/tools/lego
|
||||
ENV LEGO_VERSION=4.22.2
|
||||
ENV LEGO_DOWNLOAD_DIR=/app/tools/lego
|
||||
RUN mkdir -p $LEGO_DOWNLOAD_DIR
|
||||
|
||||
# 根据架构下载不同的文件
|
||||
@@ -32,9 +32,9 @@ RUN ARCH=$(uname -m) && \
|
||||
echo "Unsupported architecture: $ARCH"; \
|
||||
fi
|
||||
|
||||
ENV TZ Asia/Shanghai
|
||||
ENV NODE_ENV production
|
||||
ENV MIDWAY_SERVER_ENV production
|
||||
ENV TZ=Asia/Shanghai
|
||||
ENV NODE_ENV=production
|
||||
ENV MIDWAY_SERVER_ENV=production
|
||||
CMD ["npm", "run","start"]
|
||||
|
||||
|
||||
|
||||
@@ -3,6 +3,63 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.33.7](https://github.com/certd/certd/compare/v1.33.6...v1.33.7) (2025-04-22)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 优化首页插件列表展示 ([9b8f60b](https://github.com/certd/certd/commit/9b8f60b64b5f9a3db7dfa9b3dcbd9201984358d0))
|
||||
|
||||
## [1.33.6](https://github.com/certd/certd/compare/v1.33.5...v1.33.6) (2025-04-20)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 上传商用证书,直接粘贴文本报错的问题;修复无法上传ec加密证书的bug ([5750bb7](https://github.com/certd/certd/commit/5750bb706779da274d8e7a87e71416cb64d2df79))
|
||||
* 修复下载证书时提示token已过期的问题 ([0e07ae6](https://github.com/certd/certd/commit/0e07ae6ce84dcb9279d3c44060d621566afa593c))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 更新license时同时绑定url ([78367af](https://github.com/certd/certd/commit/78367af8307f801e778c76d49f0918c21ffe032f))
|
||||
* 切换到不同的分组后再打开创建对话框,会自动选择分组 ([893dcd4](https://github.com/certd/certd/commit/893dcd4f2487891199ed3e5a3d47a79a75efc942))
|
||||
* 优化/api缓存为0 ([dc05cd4](https://github.com/certd/certd/commit/dc05cd481f186b13375192be965000e6b4b429a5))
|
||||
* 优化证书流水线创建,支持选择分组 ([d613aa8](https://github.com/certd/certd/commit/d613aa8f3e85d8dc475ef1b62d49394ce7fd7d24))
|
||||
|
||||
## [1.33.5](https://github.com/certd/certd/compare/v1.33.4...v1.33.5) (2025-04-17)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 登录支持双重认证 ([48aef25](https://github.com/certd/certd/commit/48aef25b3f6499d674ca4e4ef16f4c62399fb735))
|
||||
* 多重认证登录 ([0f82cf4](https://github.com/certd/certd/commit/0f82cf409bc60706ab07e4ca4f272b9a1ca7eecb))
|
||||
|
||||
## [1.33.4](https://github.com/certd/certd/compare/v1.33.3...v1.33.4) (2025-04-15)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 插件支持导入导出 ([cf8abb4](https://github.com/certd/certd/commit/cf8abb45282070c8ba91469f93fd379fabf1f74a))
|
||||
|
||||
## [1.33.3](https://github.com/certd/certd/compare/v1.33.2...v1.33.3) (2025-04-14)
|
||||
|
||||
**Note:** Version bump only for package @certd/ui-client
|
||||
|
||||
## [1.33.2](https://github.com/certd/certd/compare/v1.33.1...v1.33.2) (2025-04-12)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 修复内置插件分页查询逻辑 ([a2710dd](https://github.com/certd/certd/commit/a2710ddc2525e4e637fd157f0180e6d3b801c8be))
|
||||
|
||||
## [1.33.1](https://github.com/certd/certd/compare/v1.33.0...v1.33.1) (2025-04-12)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 镜像支持armv7 ([f78cbed](https://github.com/certd/certd/commit/f78cbed4d817859721fdafe7d348864848d0dfbf))
|
||||
|
||||
# [1.33.0](https://github.com/certd/certd/compare/v1.32.0...v1.33.0) (2025-04-11)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 修复tab页缓存问题 ([64e5449](https://github.com/certd/certd/commit/64e5449ab3c6b219b0e89eddad14bfb6b71a0650))
|
||||
* 隐藏运行策略选项 ([2951df0](https://github.com/certd/certd/commit/2951df0cd94c23e2efee84ff1b843055aac56cae))
|
||||
* 增加手动上传证书功能说明 ([5d083a1](https://github.com/certd/certd/commit/5d083a153637caddbc6f44e915d9fb2d1ae87b33))
|
||||
|
||||
# [1.32.0](https://github.com/certd/certd/compare/v1.31.11...v1.32.0) (2025-04-04)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@certd/ui-client",
|
||||
"version": "1.32.0",
|
||||
"version": "1.33.7",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "vite --open",
|
||||
@@ -9,7 +9,7 @@
|
||||
"debug": "vite --mode debug --open",
|
||||
"debug:pm": "vite --mode debugpm",
|
||||
"debug:force": "vite --force --mode debug",
|
||||
"build": "vite build ",
|
||||
"build": "cross-env NODE_OPTIONS=--max-old-space-size=32768 vite build ",
|
||||
"dev-build": "echo 1",
|
||||
"test:unit": "vitest",
|
||||
"serve": "vite preview",
|
||||
@@ -29,10 +29,10 @@
|
||||
"@aws-sdk/client-s3": "^3.535.0",
|
||||
"@aws-sdk/s3-request-presigner": "^3.535.0",
|
||||
"@ctrl/tinycolor": "^4.1.0",
|
||||
"@fast-crud/fast-crud": "^1.25.4",
|
||||
"@fast-crud/fast-extends": "^1.25.4",
|
||||
"@fast-crud/ui-antdv4": "^1.25.4",
|
||||
"@fast-crud/ui-interface": "^1.25.4",
|
||||
"@fast-crud/fast-crud": "^1.25.8",
|
||||
"@fast-crud/fast-extends": "^1.25.8",
|
||||
"@fast-crud/ui-antdv4": "^1.25.8",
|
||||
"@fast-crud/ui-interface": "^1.25.8",
|
||||
"@iconify/tailwind": "^1.2.0",
|
||||
"@iconify/vue": "^4.1.1",
|
||||
"@manypkg/get-packages": "^2.2.2",
|
||||
@@ -57,15 +57,19 @@
|
||||
"cos-js-sdk-v5": "^1.7.0",
|
||||
"cron-parser": "^4.9.0",
|
||||
"cropperjs": "^1.6.1",
|
||||
"cross-env": "^7.0.3",
|
||||
"cssnano": "^7.0.6",
|
||||
"dayjs": "^1.11.7",
|
||||
"defu": "^6.1.4",
|
||||
"echarts": "^5.5.1",
|
||||
"highlight.js": "^11.9.0",
|
||||
"humanize-duration": "^3.27.3",
|
||||
"js-yaml": "^4.1.0",
|
||||
"lodash-es": "^4.17.21",
|
||||
"lucide-vue-next": "^0.477.0",
|
||||
"mitt": "^3.0.1",
|
||||
"monaco-editor": "^0.52.2",
|
||||
"monaco-yaml": "^5.3.1",
|
||||
"nanoid": "^4.0.0",
|
||||
"node-forge": "^1.3.1",
|
||||
"nprogress": "^0.2.0",
|
||||
@@ -80,6 +84,7 @@
|
||||
"qrcode": "^1.5.4",
|
||||
"radix-vue": "^1.9.16",
|
||||
"sortablejs": "^1.15.3",
|
||||
"spark-md5": "^3.0.2",
|
||||
"tailwind-merge": "^3.0.2",
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
"theme-colors": "^0.1.0",
|
||||
@@ -96,8 +101,8 @@
|
||||
"zod-defaults": "^0.1.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@certd/lib-iframe": "^1.32.0",
|
||||
"@certd/pipeline": "^1.32.0",
|
||||
"@certd/lib-iframe": "^1.33.7",
|
||||
"@certd/pipeline": "^1.33.7",
|
||||
"@rollup/plugin-commonjs": "^25.0.7",
|
||||
"@rollup/plugin-node-resolve": "^15.2.3",
|
||||
"@types/chai": "^4.3.12",
|
||||
@@ -155,6 +160,9 @@
|
||||
"pre-commit": "pretty-quick --staged"
|
||||
}
|
||||
},
|
||||
"pnpm": {
|
||||
"neverBuiltDependencies": []
|
||||
},
|
||||
"gitHead": "9c2162697f3affea22c9a8cbc0ca74f4034ab27e",
|
||||
"vite": {
|
||||
"optimizeDeps": {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<template>
|
||||
<AConfigProvider :locale="locale" :theme="tokenTheme">
|
||||
<fs-form-provider>
|
||||
<FsFormProvider>
|
||||
<contextHolder />
|
||||
<router-view />
|
||||
</fs-form-provider>
|
||||
</FsFormProvider>
|
||||
</AConfigProvider>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
export default [
|
||||
{
|
||||
path: "/login",
|
||||
method: "post",
|
||||
handle() {
|
||||
return {
|
||||
code: 0,
|
||||
msg: "success",
|
||||
data: {
|
||||
token: "faker token",
|
||||
expire: 10000
|
||||
}
|
||||
};
|
||||
}
|
||||
},
|
||||
{
|
||||
path: "/sys/authority/user/mine",
|
||||
method: "get",
|
||||
handle() {
|
||||
return {
|
||||
code: 0,
|
||||
msg: "success",
|
||||
data: {
|
||||
id: 1,
|
||||
username: "username",
|
||||
nickName: "admin"
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
];
|
||||
@@ -1,9 +1,19 @@
|
||||
import axios from "axios";
|
||||
import { get } from "lodash-es";
|
||||
import Adapter from "axios-mock-adapter";
|
||||
import { errorLog, errorCreate, response } from "./tools";
|
||||
import { errorLog, errorCreate } from "./tools";
|
||||
import { env } from "/src/utils/util.env";
|
||||
import { useUserStore } from "../store/modules/user";
|
||||
import { useUserStore } from "/@/store/user";
|
||||
|
||||
export class CodeError extends Error {
|
||||
code: number;
|
||||
data?: any;
|
||||
constructor(message: string, code: number, data?: any) {
|
||||
super(message);
|
||||
this.code = code;
|
||||
this.data = data;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 创建请求实例
|
||||
*/
|
||||
@@ -12,8 +22,8 @@ function createService() {
|
||||
const service = axios.create();
|
||||
// 请求拦截
|
||||
service.interceptors.request.use(
|
||||
(config) => config,
|
||||
(error) => {
|
||||
config => config,
|
||||
error => {
|
||||
// 发送失败
|
||||
console.log(error);
|
||||
return Promise.reject(error);
|
||||
@@ -21,7 +31,7 @@ function createService() {
|
||||
);
|
||||
// 响应拦截
|
||||
service.interceptors.response.use(
|
||||
(response) => {
|
||||
response => {
|
||||
if (response.config.responseType === "blob") {
|
||||
return response;
|
||||
}
|
||||
@@ -39,35 +49,35 @@ function createService() {
|
||||
}
|
||||
|
||||
// 这个状态码是和后端约定的
|
||||
const { code } = dataAxios;
|
||||
// 根据 code 进行判断
|
||||
if (code === undefined) {
|
||||
if (dataAxios?.code === undefined) {
|
||||
// 如果没有 code 代表这不是项目后端开发的接口
|
||||
errorCreate(`非标准返回:${dataAxios}, ${response.config.url}`);
|
||||
return dataAxios;
|
||||
} else {
|
||||
// 有 code 代表这是一个后端接口 可以进行进一步的判断
|
||||
switch (code) {
|
||||
case 0:
|
||||
// [ 示例 ] code === 0 代表没有错误
|
||||
}
|
||||
const { code } = dataAxios;
|
||||
// 有 code 代表这是一个后端接口 可以进行进一步的判断
|
||||
switch (code) {
|
||||
case 0:
|
||||
// [ 示例 ] code === 0 代表没有错误
|
||||
// @ts-ignore
|
||||
return dataAxios?.data;
|
||||
default:
|
||||
// 不是正确的 code
|
||||
const errorMessage = dataAxios.msg || dataAxios.message || "未知错误";
|
||||
// @ts-ignore
|
||||
if (response?.config?.onError) {
|
||||
const err = new CodeError(errorMessage, dataAxios.code, dataAxios.data);
|
||||
// @ts-ignore
|
||||
return dataAxios.data;
|
||||
default:
|
||||
// 不是正确的 code
|
||||
const errorMessage = dataAxios.msg || dataAxios.message || "未知错误";
|
||||
// @ts-ignore
|
||||
if (response?.config?.onError) {
|
||||
// @ts-ignore
|
||||
response.config.onError(new Error(errorMessage));
|
||||
}
|
||||
//@ts-ignore
|
||||
const showErrorNotify = response?.config?.showErrorNotify;
|
||||
errorCreate(`${errorMessage}: ${response.config.url}`, showErrorNotify);
|
||||
return dataAxios;
|
||||
}
|
||||
response.config.onError(err);
|
||||
return;
|
||||
}
|
||||
//@ts-ignore
|
||||
const showErrorNotify = response?.config?.showErrorNotify;
|
||||
errorCreate(`${errorMessage}: ${response.config.url}`, showErrorNotify, dataAxios);
|
||||
return dataAxios;
|
||||
}
|
||||
},
|
||||
(error) => {
|
||||
error => {
|
||||
const status = get(error, "response.status");
|
||||
switch (status) {
|
||||
case 400:
|
||||
@@ -130,11 +140,11 @@ function createRequestFunction(service: any) {
|
||||
return function (config: any) {
|
||||
const configDefault = {
|
||||
headers: {
|
||||
"Content-Type": get(config, "headers.Content-Type", "application/json")
|
||||
"Content-Type": get(config, "headers.Content-Type", "application/json"),
|
||||
},
|
||||
timeout: 20000,
|
||||
baseURL: env.API,
|
||||
data: {}
|
||||
data: {},
|
||||
};
|
||||
const userStore = useUserStore();
|
||||
const token = userStore.getToken;
|
||||
@@ -149,10 +159,3 @@ function createRequestFunction(service: any) {
|
||||
// 用于真实网络请求的实例和请求方法
|
||||
export const service = createService();
|
||||
export const request = createRequestFunction(service);
|
||||
|
||||
// 用于模拟网络请求的实例和请求方法
|
||||
export const serviceForMock = createService();
|
||||
export const requestForMock = createRequestFunction(serviceForMock);
|
||||
|
||||
// 网络请求数据模拟工具
|
||||
export const mock = new Adapter(serviceForMock, { delayResponse: 200 });
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
* @param {String} defaultValue 默认值
|
||||
*/
|
||||
import { uiContext } from "@fast-crud/fast-crud";
|
||||
import { CodeError } from "/@/api/service";
|
||||
|
||||
export function parse(jsonString = "{}", defaultValue = {}) {
|
||||
let result = defaultValue;
|
||||
@@ -68,8 +69,8 @@ export function errorLog(error: any, notify = true) {
|
||||
* @description 创建一个错误
|
||||
* @param {String} msg 错误信息
|
||||
*/
|
||||
export function errorCreate(msg: string, notify = true) {
|
||||
const err = new Error(msg);
|
||||
export function errorCreate(msg: string, notify = true, data?: any) {
|
||||
const err = new CodeError(msg, data.code, data.data);
|
||||
console.error("errorCreate", err);
|
||||
if (notify) {
|
||||
uiContext.get().notification.error({ message: err.message });
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
export async function importJsYaml() {
|
||||
return await import("js-yaml");
|
||||
}
|
||||
|
||||
export async function importYamlContribution() {
|
||||
await import("monaco-editor/esm/vs/basic-languages/yaml/yaml.contribution");
|
||||
}
|
||||
|
||||
export async function importJsonContribution() {
|
||||
await import("monaco-editor/esm/vs/language/json/monaco.contribution");
|
||||
}
|
||||
|
||||
export async function importJavascriptContribution() {
|
||||
await import("monaco-editor/esm/vs/basic-languages/javascript/javascript.contribution");
|
||||
}
|
||||
|
||||
export async function importMonacoYaml() {
|
||||
return await import("monaco-yaml");
|
||||
}
|
||||
|
||||
export async function importWorks() {
|
||||
const editorWorker = await import("monaco-editor/esm/vs/editor/editor.worker?worker");
|
||||
const jsonWorker = await import("monaco-editor/esm/vs/language/json/json.worker?worker");
|
||||
const cssWorker = await import("monaco-editor/esm/vs/language/css/css.worker?worker");
|
||||
const htmlWorker = await import("monaco-editor/esm/vs/language/html/html.worker?worker");
|
||||
const tsWorker = await import("monaco-editor/esm/vs/language/typescript/ts.worker?worker");
|
||||
const yamlWorker = await import("./yaml.worker?worker");
|
||||
|
||||
return {
|
||||
editorWorker,
|
||||
jsonWorker,
|
||||
cssWorker,
|
||||
htmlWorker,
|
||||
tsWorker,
|
||||
yamlWorker,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
import editorWorker from "monaco-editor/esm/vs/editor/editor.worker?worker";
|
||||
import jsonWorker from "monaco-editor/esm/vs/language/json/json.worker?worker";
|
||||
import cssWorker from "monaco-editor/esm/vs/language/css/css.worker?worker";
|
||||
import htmlWorker from "monaco-editor/esm/vs/language/html/html.worker?worker";
|
||||
import tsWorker from "monaco-editor/esm/vs/language/typescript/ts.worker?worker";
|
||||
import yamlWorker from "./yaml.worker?worker";
|
||||
|
||||
const WorkerBucket: any = {};
|
||||
|
||||
/**
|
||||
* 注册自定义worker
|
||||
* @param name
|
||||
* @param worker
|
||||
*/
|
||||
export function registerWorker(name: string, worker: any) {
|
||||
WorkerBucket[name] = worker;
|
||||
}
|
||||
//@ts-ignore
|
||||
window.MonacoEnvironment = {
|
||||
//@ts-ignore
|
||||
getWorker(_, label) {
|
||||
const custom = WorkerBucket[label];
|
||||
if (custom) {
|
||||
return new custom();
|
||||
}
|
||||
if (label === "json") {
|
||||
return new jsonWorker();
|
||||
} else if (label === "css" || label === "scss" || label === "less") {
|
||||
return new cssWorker();
|
||||
} else if (label === "html" || label === "handlebars" || label === "razor") {
|
||||
return new htmlWorker();
|
||||
} else if (label === "typescript" || label === "javascript") {
|
||||
return new tsWorker();
|
||||
} else if (label === "yaml" || label === "yml") {
|
||||
//@ts-ignore
|
||||
return new yamlWorker();
|
||||
}
|
||||
return new editorWorker();
|
||||
},
|
||||
};
|
||||
261
packages/ui/certd-client/src/components/code-editor/index.vue
Normal file
@@ -0,0 +1,261 @@
|
||||
<template>
|
||||
<div ref="monacoRef" class="fs-editor-code"></div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import * as monaco from "monaco-editor";
|
||||
// import * as monaco from "monaco-editor/esm/vs/editor/editor.api";
|
||||
import { onMounted, onUnmounted, ref, watch } from "vue";
|
||||
import { cloneDeep, debounce as lodashDebounce } from "lodash-es";
|
||||
import { initWorkers } from "./workers";
|
||||
import { importJavascriptContribution, importJsonContribution, importMonacoYaml, importYamlContribution } from "./async-import";
|
||||
|
||||
/**
|
||||
* config:
|
||||
* value: '', // 编辑器初始文本
|
||||
* language: 'javascript', // 语言
|
||||
* theme: 'vs', // 主题
|
||||
* readOnly: false, // 是否只读
|
||||
* minimap: { enabled: false }, // 是否启用小地图
|
||||
* fontSize: 14, // 字体大小
|
||||
* tabSize: 2, // tab缩进长度
|
||||
* automaticLayout: true, // 自动布局
|
||||
* lineNumbers: 'off', // 是否启用行号
|
||||
* contextmenu: true, // 是否启用上下文菜单
|
||||
* folding: true, // 是否启用代码折叠
|
||||
* foldingStrategy: 'auto', // 代码折叠策略
|
||||
* wordWrap: 'on', // 自动换行设置
|
||||
* wrappingIndent: 'indent', // 换行缩进
|
||||
* formatOnPaste: true, // 粘贴时是否自动格式化
|
||||
* formatOnType: true, // 输入时是否自动格式化
|
||||
* dragAndDrop: true, // 是否允许拖放
|
||||
* cursorStyle: 'line', // 光标样式
|
||||
* cursorBlinking: 'blink', // 光标闪烁方式
|
||||
* scrollbar: {
|
||||
* vertical: 'auto', // 垂直滚动条的显示方式
|
||||
* horizontal: 'auto', // 水平滚动条的显示方式
|
||||
* verticalScrollbarSize: 2, // 垂直滚动条的宽
|
||||
* horizontalScrollbarSize: 2, // 水平滚动条的高度
|
||||
* }
|
||||
*/
|
||||
const props = defineProps<{
|
||||
language?: string;
|
||||
modelValue?: string;
|
||||
config?: any;
|
||||
schema?: any;
|
||||
debounce?: number;
|
||||
init?: any;
|
||||
readonly?: boolean;
|
||||
disabled?: boolean;
|
||||
id?: string;
|
||||
}>();
|
||||
|
||||
export type EditorCodeCtx = {
|
||||
// monaco对象
|
||||
monaco: any;
|
||||
//语言
|
||||
language: string;
|
||||
//配置
|
||||
config: any;
|
||||
//editor实例对象
|
||||
instance?: any;
|
||||
|
||||
schema?: any;
|
||||
};
|
||||
|
||||
const monacoRef = ref();
|
||||
|
||||
let instanceRef: any = null;
|
||||
|
||||
function disposeEditor() {
|
||||
if (instanceRef) {
|
||||
instanceRef.dispose(); //使用完成销毁实例
|
||||
}
|
||||
}
|
||||
|
||||
onUnmounted(() => {
|
||||
disposeEditor();
|
||||
});
|
||||
|
||||
const emits = defineEmits(["update:modelValue", "change", "ready", "save"]);
|
||||
|
||||
const emitValue = lodashDebounce((value: any) => {
|
||||
emits("update:modelValue", value);
|
||||
}, props.debounce || 500);
|
||||
|
||||
async function createEditor(ctx: EditorCodeCtx) {
|
||||
disposeEditor();
|
||||
const instance = monaco.editor.create(monacoRef.value, {
|
||||
automaticLayout: true,
|
||||
value: props.modelValue,
|
||||
language: ctx.language,
|
||||
theme: "vs-dark",
|
||||
minimap: { enabled: false },
|
||||
insertSpaces: true,
|
||||
tabSize: 2,
|
||||
autoIndent: true, // 自动布局
|
||||
renderWhitespace: true,
|
||||
readOnly: props.readonly || props.disabled,
|
||||
hover: {
|
||||
enabled: true,
|
||||
},
|
||||
...ctx.config,
|
||||
});
|
||||
|
||||
// @event `change`
|
||||
instance.onDidChangeModelContent(event => {
|
||||
const value = instance.getValue();
|
||||
if (props.modelValue !== value) {
|
||||
emits("change", value);
|
||||
emitValue(value);
|
||||
}
|
||||
});
|
||||
|
||||
instanceRef = instance;
|
||||
ctx.instance = instance;
|
||||
emits("ready", ctx);
|
||||
if (props.modelValue) {
|
||||
instanceRef.setValue(props.modelValue);
|
||||
}
|
||||
|
||||
instance.addAction({
|
||||
id: "custom_save",
|
||||
label: "save",
|
||||
contextMenuOrder: 1, // 菜单项的排序权重 越小,越靠前
|
||||
contextMenuGroupId: "customCommand", // 菜单项的分组
|
||||
keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyS],
|
||||
run: async () => {
|
||||
await instanceRef.getAction("editor.action.formatDocument").run();
|
||||
emits("save", {
|
||||
value: props.modelValue,
|
||||
});
|
||||
}, //方法
|
||||
});
|
||||
return instance;
|
||||
}
|
||||
|
||||
async function initJavascript(ctx: EditorCodeCtx) {
|
||||
await importJavascriptContribution();
|
||||
monaco.languages.register({ id: "javascript" });
|
||||
}
|
||||
|
||||
async function initJson(ctx: EditorCodeCtx) {
|
||||
await importJsonContribution();
|
||||
monaco.languages.register({ id: "json" });
|
||||
|
||||
const schemas = [];
|
||||
if (ctx.schema) {
|
||||
schemas.push({
|
||||
uri: "http://myserver/foo-schema.json", // id of the first schema
|
||||
fileMatch: ["*"], // associate with our model
|
||||
schema: {
|
||||
...ctx.schema,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
monaco.languages.json.jsonDefaults.setDiagnosticsOptions({
|
||||
validate: true,
|
||||
enableSchemaRequest: false,
|
||||
schemas,
|
||||
});
|
||||
}
|
||||
|
||||
async function initYaml(ctx: EditorCodeCtx) {
|
||||
await importYamlContribution();
|
||||
const { configureMonacoYaml } = await importMonacoYaml();
|
||||
monaco.languages.register({ id: "yaml" });
|
||||
const id = `fs-editor-code-${props.id || ""}.yaml`;
|
||||
const uri = monaco.Uri.parse(id);
|
||||
const schemas = [];
|
||||
if (ctx.schema) {
|
||||
schemas.push({
|
||||
fileMatch: ["*"], // associate with our model
|
||||
schema: {
|
||||
...ctx.schema,
|
||||
},
|
||||
uri: id,
|
||||
});
|
||||
}
|
||||
configureMonacoYaml(monaco, {
|
||||
schemas,
|
||||
format: true,
|
||||
hover: true,
|
||||
completion: true,
|
||||
validate: true,
|
||||
isKubernetes: false,
|
||||
enableSchemaRequest: false,
|
||||
});
|
||||
|
||||
const oldModel = monaco.editor.getModel(uri);
|
||||
if (oldModel) {
|
||||
oldModel.dispose();
|
||||
}
|
||||
ctx.config.model = monaco.editor.createModel(props.modelValue, "yaml", uri);
|
||||
}
|
||||
|
||||
async function doInit() {
|
||||
await initWorkers();
|
||||
const ctx: EditorCodeCtx = {
|
||||
monaco,
|
||||
language: props.language || "javascript",
|
||||
config: cloneDeep(props.config || {}),
|
||||
schema: props.schema,
|
||||
};
|
||||
if (ctx.language === "javascript") {
|
||||
await initJavascript(ctx);
|
||||
} else if (ctx.language === "yaml") {
|
||||
await initYaml(ctx);
|
||||
} else if (ctx.language === "json") {
|
||||
await initJson(ctx);
|
||||
}
|
||||
|
||||
await createEditor(ctx);
|
||||
}
|
||||
// watch(
|
||||
// () => {
|
||||
// return {
|
||||
// language: props.language,
|
||||
// config: props.config,
|
||||
// };
|
||||
// },
|
||||
// (value: any) => {
|
||||
// doInit();
|
||||
// }
|
||||
// );
|
||||
|
||||
watch(
|
||||
() => {
|
||||
return props.modelValue;
|
||||
},
|
||||
newValue => {
|
||||
if (instanceRef) {
|
||||
const editor = instanceRef;
|
||||
if (newValue !== editor.getValue()) {
|
||||
editor.setValue(newValue);
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
}
|
||||
);
|
||||
|
||||
onMounted(async () => {
|
||||
await doInit();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.fs-editor-code {
|
||||
min-height: 100px;
|
||||
width: 100%;
|
||||
border: 1px solid #eee;
|
||||
border-radius: 5px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.monaco-editor .hover-content {
|
||||
z-index: 1000 !important;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,37 @@
|
||||
import { importJsYaml } from "./async-import";
|
||||
|
||||
const jsonRule = {
|
||||
validator: async (rule: any, value: any) => {
|
||||
//校验value json的有效性
|
||||
if (value) {
|
||||
try {
|
||||
JSON.parse(value);
|
||||
} catch (e: any) {
|
||||
console.error(e);
|
||||
throw new Error("json格式错误:" + e.message);
|
||||
}
|
||||
}
|
||||
},
|
||||
message: "json格式错误",
|
||||
};
|
||||
|
||||
const yamlRule = {
|
||||
validator: async (rule: any, value: any) => {
|
||||
//校验value yaml的有效性
|
||||
if (value) {
|
||||
try {
|
||||
const yaml = await importJsYaml();
|
||||
yaml.load(value, { schema: yaml.JSON_SCHEMA });
|
||||
} catch (e: any) {
|
||||
console.error(e);
|
||||
throw new Error("yaml格式错误:" + e.message);
|
||||
}
|
||||
}
|
||||
},
|
||||
message: "yaml格式错误",
|
||||
};
|
||||
|
||||
export const FsEditorCodeValidators = {
|
||||
jsonRule,
|
||||
yamlRule,
|
||||
};
|
||||
@@ -0,0 +1,56 @@
|
||||
const WorkerBucket: any = {};
|
||||
|
||||
/**
|
||||
* 注册自定义worker
|
||||
* @param name
|
||||
* @param worker
|
||||
*/
|
||||
export function registerWorker(name: string, worker: any) {
|
||||
WorkerBucket[name] = worker;
|
||||
}
|
||||
|
||||
export async function initWorkers() {
|
||||
if (window.MonacoEnvironment) {
|
||||
return;
|
||||
}
|
||||
|
||||
// const { editorWorker, jsonWorker, cssWorker, htmlWorker, tsWorker } = await importWorks();
|
||||
//
|
||||
// // const editorWorker = new Worker(new URL("monaco-editor/esm/vs/editor/editor.worker.js", import.meta.url));
|
||||
// // const jsonWorker = new Worker(new URL("monaco-editor/esm/vs/language/json/json.worker.js", import.meta.url));
|
||||
// // const cssWorker = new Worker(new URL("monaco-editor/esm/vs/language/css/css.worker.js", import.meta.url));
|
||||
// // const htmlWorker = new Worker(new URL("monaco-editor/esm/vs/language/html/html.worker.js", import.meta.url));
|
||||
// // const tsWorker = new Worker(new URL("monaco-editor/esm/vs/language/typescript/ts.worker.js", import.meta.url));
|
||||
// // const yamlWorker = new Worker(new URL("./yaml.worker.js", import.meta.url));
|
||||
|
||||
const editorWorker = await import("monaco-editor/esm/vs/editor/editor.worker?worker");
|
||||
const jsonWorker = await import("monaco-editor/esm/vs/language/json/json.worker?worker");
|
||||
const cssWorker = await import("monaco-editor/esm/vs/language/css/css.worker?worker");
|
||||
const htmlWorker = await import("monaco-editor/esm/vs/language/html/html.worker?worker");
|
||||
const tsWorker = await import("monaco-editor/esm/vs/language/typescript/ts.worker?worker");
|
||||
const yamlWorker = await import("./yaml.worker?worker");
|
||||
|
||||
//@ts-ignore
|
||||
window.MonacoEnvironment = {
|
||||
//@ts-ignore
|
||||
getWorker(_, label) {
|
||||
const custom = WorkerBucket[label];
|
||||
if (custom) {
|
||||
return new custom();
|
||||
}
|
||||
if (label === "json") {
|
||||
return new jsonWorker.default();
|
||||
} else if (label === "css" || label === "scss" || label === "less") {
|
||||
return new cssWorker.default();
|
||||
} else if (label === "html" || label === "handlebars" || label === "razor") {
|
||||
return new htmlWorker.default();
|
||||
} else if (label === "typescript" || label === "javascript") {
|
||||
return new tsWorker.default();
|
||||
} else if (label === "yaml" || label === "yml") {
|
||||
//@ts-ignore
|
||||
return new yamlWorker.default();
|
||||
}
|
||||
return new editorWorker.default();
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export * from "monaco-yaml/yaml.worker.js";
|
||||
@@ -8,7 +8,7 @@
|
||||
</a-input>
|
||||
</div>
|
||||
<div v-else class="view" @click="edit">
|
||||
<span> {{ modelValue }}</span>
|
||||
<span class="ellipsis"> {{ modelValue }}</span>
|
||||
<fs-icon class="edit-icon" icon="ant-design:edit-outlined"></fs-icon>
|
||||
</div>
|
||||
</div>
|
||||
@@ -22,19 +22,19 @@ export default {
|
||||
props: {
|
||||
modelValue: {
|
||||
type: String,
|
||||
default: ""
|
||||
default: "",
|
||||
},
|
||||
input: {
|
||||
type: Object
|
||||
type: Object,
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
default: false,
|
||||
},
|
||||
hoverShow: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
emits: ["update:modelValue"],
|
||||
setup(props, ctx) {
|
||||
@@ -44,7 +44,7 @@ export default {
|
||||
() => {
|
||||
return props.modelValue;
|
||||
},
|
||||
(value) => {
|
||||
value => {
|
||||
valueRef.value = value;
|
||||
}
|
||||
);
|
||||
@@ -66,9 +66,9 @@ export default {
|
||||
isEdit,
|
||||
save,
|
||||
edit,
|
||||
inputRef
|
||||
inputRef,
|
||||
};
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
|
||||
@@ -12,12 +12,18 @@ import IconSelect from "./icon-select.vue";
|
||||
import ExpiresTimeText from "./expires-time-text.vue";
|
||||
import FileInput from "./file-input.vue";
|
||||
import PemInput from "./pem-input.vue";
|
||||
import { defineAsyncComponent } from "vue";
|
||||
export default {
|
||||
install(app: any) {
|
||||
app.component(
|
||||
"CodeEditor",
|
||||
defineAsyncComponent(() => import("./code-editor/index.vue"))
|
||||
);
|
||||
app.component("PiContainer", PiContainer);
|
||||
app.component("TextEditable", TextEditable);
|
||||
app.component("FileInput", FileInput);
|
||||
app.component("PemInput", PemInput);
|
||||
// app.component("CodeEditor", CodeEditor);
|
||||
|
||||
app.component("CronLight", CronLight);
|
||||
app.component("CronEditor", CronEditor);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="pem-input">
|
||||
<FileInput v-bind="fileInput" class="mb-5" type="primary" text="选择文件" @change="onChange" />
|
||||
<a-textarea v-bind="textarea" v-model:value="textRef"></a-textarea>
|
||||
<a-textarea v-bind="textarea" :value="modelValue" @update:value="emitValue"></a-textarea>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -17,7 +17,6 @@ const props = defineProps<{
|
||||
}>();
|
||||
|
||||
const emit = defineEmits(["update:modelValue"]);
|
||||
const textRef = ref();
|
||||
|
||||
function emitValue(value: string) {
|
||||
emit("update:modelValue", value);
|
||||
@@ -39,16 +38,6 @@ function onChange(e: any) {
|
||||
};
|
||||
fileReader.readAsText(file); // 以文本形式读取文件
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
value => {
|
||||
textRef.value = value;
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
|
||||
@@ -5,6 +5,6 @@ const apiPrefix = "/pi/dnsProvider";
|
||||
export async function GetList() {
|
||||
return await request({
|
||||
url: apiPrefix + "/list",
|
||||
method: "post"
|
||||
method: "post",
|
||||
});
|
||||
}
|
||||
|
||||