Compare commits

...

92 Commits

Author SHA1 Message Date
xiaojunnuo
be69244e8d v1.33.2 2025-04-13 01:31:52 +08:00
xiaojunnuo
617f74a225 build: prepare to build 2025-04-13 01:29:05 +08:00
xiaojunnuo
a2710ddc25 perf: 修复内置插件分页查询逻辑
- 在前端添加 lastType 变量,用于判断类型变化并重置分页偏移量
- 在后端修改内置插件查询逻辑,支持分页请求
- 优化后端返回数据结构,使其与前端请求一致
2025-04-13 01:28:10 +08:00
xiaojunnuo
70101bfa7a fix: 修复某些情况下无法输出日志的bug 2025-04-13 01:17:52 +08:00
xiaojunnuo
203f2984d7 chore: 1.33.1 2025-04-13 01:05:51 +08:00
xiaojunnuo
1d510e76b8 build: trigger build image 2025-04-13 01:02:07 +08:00
xiaojunnuo
64244af2cc v1.33.1 2025-04-13 00:49:14 +08:00
xiaojunnuo
35e109882e build: prepare to build 2025-04-13 00:45:32 +08:00
xiaojunnuo
18a32ffb0b chore: 修复一些小问题 2025-04-13 00:45:01 +08:00
xiaojunnuo
a5af3ba0cb build: prepare to build 2025-04-13 00:19:38 +08:00
xiaojunnuo
83bd39a9a8 chore: 1 2025-04-13 00:10:23 +08:00
xiaojunnuo
cc0657aaa8 pref: 优化插件store 2025-04-12 23:59:03 +08:00
xiaojunnuo
965dc2cb47 fix: 修复阿里云cdn证书部署失败问题,增加certname参数传入
- 添加证书所在地域选择功能,默认为 cn-hangzhou(杭州)
- 国际站用户可选择 ap-southeast-1(新加坡)地域
- 优化证书上传和设置流程,增加证书名称和地域参数
2025-04-12 23:58:38 +08:00
xiaojunnuo
9c4cbe17a2 fix: 修复ssh插件报length空指针的bug
- 在数据加密判断中增加非空检查,避免对未定义或空值进行加密判断- 提高了代码的健壮性和安全性
2025-04-12 22:04:14 +08:00
xiaojunnuo
835fcfa4ea pref: 优化mysql版的插件脚本字段为longtext 2025-04-12 22:02:54 +08:00
xiaojunnuo
932780c578 pref: 优化部署到腾讯云任意资源插件,支持region,和资源类型选择
- 添加资源类型选择输入,支持多种腾讯云产品
-增加证书上传功能,支持直接上传证书到腾讯云
- 优化证书 ID 输入,支持选择上传任务或申请任务的输出- 添加 Region 输入,用于指定云资源所在地域
- 更新文档链接,提供更详细的参考信息
2025-04-12 22:02:16 +08:00
xiaojunnuo
37f160a452 pref: 增加又拍云 CDN 部署时的 HTTPS 配置选项
- 在插件中添加了两个新的配置项:强制 HTTPS 和开启 HTTPS- 用户可以在部署证书时选择是否强制 HTTPS 或开启 HTTPS
-根据用户选择,插件会相应地设置 CDN 域名的 HTTPS 配置
2025-04-12 22:01:29 +08:00
xiaojunnuo
f80b706fc3 chore: 2025-04-12 03:29:02 +08:00
xiaojunnuo
f78cbed4d8 perf: 镜像支持armv7 2025-04-12 03:25:43 +08:00
xiaojunnuo
e0b12c78ff chore: build 1.33.0 2025-04-12 03:13:31 +08:00
xiaojunnuo
e7cf814a59 build: prepare to build 2025-04-12 03:13:06 +08:00
xiaojunnuo
865c45593b chore: build 1.33.0 2025-04-12 03:12:53 +08:00
xiaojunnuo
62e6f109c7 chore: build 1.33.0 2025-04-12 03:03:26 +08:00
xiaojunnuo
60be8ed022 chore: build 1.33.0 2025-04-12 02:58:19 +08:00
xiaojunnuo
c157882900 chore: build 1.33.0 2025-04-12 02:55:28 +08:00
xiaojunnuo
a23c211a65 build: publish 2025-04-12 02:40:33 +08:00
xiaojunnuo
293ed6bd7e build: trigger build image 2025-04-12 02:40:15 +08:00
xiaojunnuo
13ddd7c5f9 v1.33.0 2025-04-12 02:38:31 +08:00
xiaojunnuo
0de015fc8b build: prepare to build 2025-04-12 02:35:34 +08:00
xiaojunnuo
d34fedae01 build: prepare to build 2025-04-12 02:34:03 +08:00
xiaojunnuo
7c623fc467 chore: 新增插件编辑页面跳转
- 在插件创建成功后跳转到编辑页面
- 优化了插件管理功能,提高了用户操作的便捷性
2025-04-12 02:33:44 +08:00
xiaojunnuo
359079c3e6 chore: v21适配多数据库 2025-04-12 02:24:38 +08:00
xiaojunnuo
ba72fa3f05 chore: 2025-04-12 02:10:17 +08:00
xiaojunnuo
23caab5b06 chore: 添加子域名托管解析设置并更新相关提示
- 在证书申请页面添加子域名托管解析设置入口
- 更新域名输入提示,增加子域名托管解析相关说明
- 更改子域名托管解析页面图标
2025-04-12 02:00:40 +08:00
xiaojunnuo
b506bd15a5 chore: 2025-04-12 01:48:08 +08:00
xiaojunnuo
d0d9d68fe6 feat: 支持在线自定义插件,无需源码开发 2025-04-12 01:38:48 +08:00
xiaojunnuo
88134ac130 refactor(plugin): 优化插件配置界面和功能
-调整插件配置界面布局和样式
- 增加插件类型和图标字段
- 修改字段显示逻辑,根据不同插件类型显示相应字段
- 优化插件服务端处理逻辑,支持不同类型的插件配置
2025-04-12 01:34:48 +08:00
xiaojunnuo
3d8a5196a0 refactor(core): 重构访问控制和插件实例化逻辑
- 修改访问控制和插件注册方式,使用异步函数统一实例化逻辑
- 更新相关组件和控制器以适应新的异步实例化方式
- 优化 DNS 提供商选择器,增加访问类型支持
2025-04-12 01:21:50 +08:00
xiaojunnuo
c4fb138ae8 chore: 2025-04-12 00:21:19 +08:00
xiaojunnuo
759cfdaabd pref: 日志中加密授权信息输出替换成星号 2025-04-12 00:14:55 +08:00
xiaojunnuo
3d9620abb0 refactor(plugin): 重构插件定义和安装流程
- 更新插件配置格式,增加依赖库和插件类型字段
- 修改插件安装流程,支持安装依赖插件和第三方库
- 优化插件列表过滤逻辑,按类型筛选插件
- 调整 Dockerfile,使用 Node.js22 镜像并更新 pnpm 安装方式
2025-04-11 23:39:40 +08:00
xiaojunnuo
420b0394a7 Merge remote-tracking branch 'origin/v2-plugin' into v2-plugin 2025-04-11 22:38:16 +08:00
xiaojunnuo
84bb4c8b07 Merge branch 'v2-dev' into v2-plugin 2025-04-11 22:35:35 +08:00
greper
310dbb61ee 发布镜像到 GitHub Packages @5aaee9
发布镜像到 GitHub Packages
2025-04-11 16:53:00 +08:00
Indexyz
9b536af9e6 feat: release image to ghcr 2025-04-11 16:37:31 +08:00
xiaojunnuo
c2ca1ea1e5 chore: 新增插件额外配置功能
- 在插件管理中添加 extra 字段,用于存储额外配置信息
- 实现插件编辑页面的额外配置编辑功能
- 更新数据库结构,增加 extra 列
- 优化代码编辑器的导入方式
- 更新 fast-crud 相关包版本
2025-04-11 14:00:28 +08:00
greper
ada4b226de Lego 支持设定加密算法 @5aaee9
Lego 支持设定加密算法
2025-04-11 12:17:37 +08:00
xiaojunnuo
67f956d4a0 pref: 支持子域名托管的域名证书申请 2025-04-11 12:14:09 +08:00
xiaojunnuo
f68af7dcf2 chore: 2025-04-10 23:44:11 +08:00
xiaojunnuo
be1b6f8edc chore: 2025-04-10 13:30:56 +08:00
xiaojunnuo
1150f62927 Merge branch 'v2-dev' into v2-plugin 2025-04-10 11:48:45 +08:00
xiaojunnuo
b4c7a521b4 chore: 2025-04-10 11:38:51 +08:00
xiaojunnuo
5d083a1536 perf: 增加手动上传证书功能说明 2025-04-10 10:34:10 +08:00
xiaojunnuo
2f5ed3aead fix: 升级mysql驱动,支持mysql8最新版本的认证 2025-04-10 10:24:34 +08:00
xiaojunnuo
2951df0cd9 perf: 隐藏运行策略选项 2025-04-10 09:35:50 +08:00
xiaojunnuo
ec22070957 Merge branch 'v2-dev' into v2-plugin 2025-04-10 00:22:51 +08:00
xiaojunnuo
0e36f03954 chore: plugin default 2025-04-10 00:22:05 +08:00
xiaojunnuo
57309ae3d5 Merge remote-tracking branch 'origin/v2-dev' into v2-dev 2025-04-09 10:07:14 +08:00
xiaojunnuo
7545194f97 chore: 2025-04-09 00:00:53 +08:00
xiaojunnuo
4bb0918e27 chore: 2025-04-08 23:36:50 +08:00
xiaojunnuo
64e5449ab3 perf: 修复tab页缓存问题 2025-04-08 23:31:25 +08:00
xiaojunnuo
a0eeb17d73 chore: 插件编辑与运行测试beta 2025-04-08 22:56:38 +08:00
xiaojunnuo
c021dd03d3 Merge branch 'v2-dev' into v2-plugin 2025-04-08 21:14:54 +08:00
xiaojunnuo
2f1683b26a fix: 修复eab授权,没有email绑定的bug 2025-04-08 19:54:25 +08:00
xiaojunnuo
c99939f435 chore: 2025-04-08 18:06:12 +08:00
xiaojunnuo
efad8bac3c chore: 2025-04-08 13:53:54 +08:00
xiaojunnuo
eaf68fa463 chore: 2025-04-08 13:40:58 +08:00
xiaojunnuo
9475f2e56c chore: code-editor 2025-04-07 23:52:21 +08:00
xiaojunnuo
2e0c067cd2 chore: 2025-04-07 18:22:39 +08:00
xiaojunnuo
59a6043549 chore: 2025-04-06 23:16:54 +08:00
xiaojunnuo
840a7b7c73 chore: 插件编辑器 2025-04-06 18:06:21 +08:00
xiaojunnuo
61e322678b chore: 2025-04-06 00:20:05 +08:00
xiaojunnuo
04acd08ad2 Merge branch 'v2-dev' into v2-plugin 2025-04-05 19:01:23 +08:00
5aaee9
f3bf4faee0 feat(lego): support set key type 2025-04-05 17:01:41 +08:00
xiaojunnuo
c3603ba220 build: publish 2025-04-05 01:37:41 +08:00
xiaojunnuo
a3a52fd12c build: trigger build image 2025-04-05 01:37:22 +08:00
xiaojunnuo
7c4756da81 v1.32.0 2025-04-05 01:35:54 +08:00
xiaojunnuo
f4fe03c790 build: prepare to build 2025-04-05 01:33:15 +08:00
xiaojunnuo
a748bb9352 build: prepare to build 2025-04-05 01:14:24 +08:00
xiaojunnuo
d24fb6ed48 chore: 2025-04-05 01:13:46 +08:00
xiaojunnuo
021dc5b82c Merge branch 'v2-dev' into v2-plugin 2025-04-05 00:48:23 +08:00
xiaojunnuo
9339b78f80 perf: 又拍云支持云存储 2025-04-05 00:47:34 +08:00
xiaojunnuo
8449f8580d perf: 又拍云支持云存储 2025-04-05 00:46:56 +08:00
xiaojunnuo
0948c5bc69 perf: 优化华为dns解析记录创建和删除问题 2025-04-05 00:24:57 +08:00
xiaojunnuo
857589b365 feat: 优化证书申请速度,修复某些情况下letsencrypt 校验失败的问题 2025-04-04 23:17:05 +08:00
xiaojunnuo
c39b1bf823 fix: 修复从本地dns获取记录报错的bug 2025-04-04 20:46:48 +08:00
xiaojunnuo
545aa50898 Merge branch 'v2-dev' into v2-plugin 2025-04-04 20:14:24 +08:00
xiaojunnuo
298006a4b9 Merge remote-tracking branch 'origin/v2-dev' into v2-dev 2025-04-03 11:40:56 +08:00
xiaojunnuo
903a4131ab fix: 创建cname记录移除域名两端的空格 2025-04-03 11:39:36 +08:00
xiaojunnuo
a0ec0ddb14 build: publish 2025-04-03 00:33:32 +08:00
xiaojunnuo
46eb876f9b build: trigger build image 2025-04-03 00:33:07 +08:00
xiaojunnuo
071ef281c1 chore: 2025-04-01 22:34:15 +08:00
262 changed files with 5223 additions and 2043 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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.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

View File

@@ -85,6 +85,9 @@ 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)

View File

@@ -1 +1 @@
1
2

View File

@@ -1 +1 @@
01:49
01:02

View File

@@ -61,6 +61,7 @@ export default defineConfig({
nav: [
{ text: "首页", link: "/" },
{ text: "指南", link: "/guide/" },
{ text: "插件", link: "/deploy/" },
{ text: "商业版", link: "/comm/" },
{ text: "Demo体验", link: "https://certd.handfree.work" }
],
@@ -126,8 +127,9 @@ export default defineConfig({
],
"/deploy/":[
{
text: "部署任务",
text: "部署证书插件",
items: [
{ text: "插件说明", link: "/deploy/index.md" },
{ text: "部署到ESXi", link: "/deploy/ESXi/index.md" },
]
}

4
docs/deploy/index.md Normal file
View File

@@ -0,0 +1,4 @@
# 部署插件说明
## 待完善

View File

@@ -3,6 +3,64 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [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
* 修复ssh支持键盘事件登录 ([8145808](https://github.com/certd/certd/commit/8145808c4370364377b4ffe3ae88ff465b49f20b))
### Performance Improvements
* 支持部署到京东云cdn ([6f17c70](https://github.com/certd/certd/commit/6f17c700b84965baa01b40fe2abaa0a91bcbaffd))
* 支持京东云dns申请证书 ([04d79f9](https://github.com/certd/certd/commit/04d79f9117670be504960b018fd49ae3bf7c1c11))
## [1.31.10](https://github.com/certd/certd/compare/v1.31.9...v1.31.10) (2025-03-29)
### Performance Improvements

View File

@@ -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)

View File

@@ -9,5 +9,5 @@
}
},
"npmClient": "pnpm",
"version": "1.31.11"
"version": "1.33.2"
}

View File

@@ -3,6 +3,32 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [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
* 修复从本地dns获取记录报错的bug ([c39b1bf](https://github.com/publishlab/node-acme-client/commit/c39b1bf823ddc6216bed2049e4c87e6107def08a))
### Features
* 优化证书申请速度修复某些情况下letsencrypt 校验失败的问题 ([857589b](https://github.com/publishlab/node-acme-client/commit/857589b365c6f709e0ae67914d2f50ce182e6dd6))
### Performance Improvements
* 优化华为dns解析记录创建和删除问题 ([0948c5b](https://github.com/publishlab/node-acme-client/commit/0948c5bc691d2ee6eb47c72a85da1b7453361878))
## [1.31.11](https://github.com/publishlab/node-acme-client/compare/v1.31.10...v1.31.11) (2025-04-02)
**Note:** Version bump only for package @certd/acme-client

View File

@@ -3,7 +3,7 @@
"description": "Simple and unopinionated ACME client",
"private": false,
"author": "nmorsman",
"version": "1.31.11",
"version": "1.33.2",
"type": "module",
"module": "scr/index.js",
"main": "src/index.js",
@@ -18,7 +18,7 @@
"types"
],
"dependencies": {
"@certd/basic": "^1.31.11",
"@certd/basic": "^1.33.2",
"@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": "2e30fff221c19e46e098b0dc3250a6b7c5e6a5e0"
"gitHead": "64244af2cce396be5e2831937e5e3024a22899ed"
}

View File

@@ -1,10 +1,10 @@
/**
* ACME auto helper
*/
import { readCsrDomains } from './crypto/index.js';
import { log } from './logger.js';
import { wait } from './wait.js';
import { CancelError } from './error.js';
import { readCsrDomains } from "./crypto/index.js";
import { log } from "./logger.js";
import { wait } from "./wait.js";
import { CancelError } from "./error.js";
const defaultOpts = {
@@ -13,13 +13,13 @@ const defaultOpts = {
preferredChain: null,
termsOfServiceAgreed: false,
skipChallengeVerification: false,
challengePriority: ['http-01', 'dns-01'],
challengePriority: ["http-01", "dns-01"],
challengeCreateFn: async () => {
throw new Error('Missing challengeCreateFn()');
throw new Error("Missing challengeCreateFn()");
},
challengeRemoveFn: async () => {
throw new Error('Missing challengeRemoveFn()');
},
throw new Error("Missing challengeRemoveFn()");
}
};
/**
@@ -30,7 +30,7 @@ const defaultOpts = {
* @returns {Promise<buffer>} Certificate
*/
export default async (client, userOpts) => {
export default async (client, userOpts) => {
const opts = { ...defaultOpts, ...userOpts };
const accountPayload = { termsOfServiceAgreed: opts.termsOfServiceAgreed };
@@ -49,14 +49,13 @@ export default async (client, userOpts) => {
* Register account
*/
log('[auto] Checking account');
log("[auto] Checking account");
try {
client.getAccountUrl();
log('[auto] Account URL already exists, skipping account registration 证书申请账户已存在,跳过注册 ');
}
catch (e) {
log('[auto] Registering account (注册证书申请账户)');
log("[auto] Account URL already exists, skipping account registration 证书申请账户已存在,跳过注册 ");
} catch (e) {
log("[auto] Registering account (注册证书申请账户)");
await client.createAccount(accountPayload);
}
@@ -64,7 +63,7 @@ export default async (client, userOpts) => {
* Parse domains from CSR
*/
log('[auto] Parsing domains from Certificate Signing Request ');
log("[auto] Parsing domains from Certificate Signing Request ");
const { commonName, altNames } = readCsrDomains(opts.csr);
const uniqueDomains = Array.from(new Set([commonName].concat(altNames).filter((d) => d)));
@@ -74,8 +73,8 @@ export default async (client, userOpts) => {
* Place order
*/
log('[auto] Placing new certificate order with ACME provider');
const orderPayload = { identifiers: uniqueDomains.map((d) => ({ type: 'dns', value: d })) };
log("[auto] Placing new certificate order with ACME provider");
const orderPayload = { identifiers: uniqueDomains.map((d) => ({ type: "dns", value: d })) };
const order = await client.createOrder(orderPayload);
const authorizations = await client.getAuthorizations(order);
@@ -85,82 +84,81 @@ export default async (client, userOpts) => {
* Resolve and satisfy challenges
*/
log('[auto] Resolving and satisfying authorization challenges');
log("[auto] Resolving and satisfying authorization challenges");
const clearTasks = [];
const localVerifyTasks = [];
const completeChallengeTasks = [];
const challengeFunc = async (authz) => {
const d = authz.identifier.value;
let challengeCompleted = false;
/* Skip authz that already has valid status */
if (authz.status === 'valid') {
if (authz.status === "valid") {
log(`[auto] [${d}] Authorization already has valid status, no need to complete challenges`);
return;
}
const keyAuthorizationGetter = async (challenge) => {
return await client.getChallengeKeyAuthorization(challenge);
}
};
try {
log(`[auto] [${d}] Trigger challengeCreateFn()`);
async function deactivateAuth(e) {
log(`[auto] [${d}] Unable to complete challenge: ${e.message}`);
try {
const { recordReq, recordRes, dnsProvider,challenge ,keyAuthorization} = await opts.challengeCreateFn(authz, keyAuthorizationGetter);
clearTasks.push(async () => {
/* Trigger challengeRemoveFn(), suppress errors */
log(`[auto] [${d}] Trigger challengeRemoveFn()`);
try {
await opts.challengeRemoveFn(authz, challenge, keyAuthorization, recordReq, recordRes, dnsProvider);
}
catch (e) {
log(`[auto] [${d}] challengeRemoveFn threw error: ${e.message}`);
}
});
// throw new Error('测试异常');
/* Challenge verification */
if (opts.skipChallengeVerification === true) {
log(`[auto] [${d}] 跳过本地验证skipChallengeVerification=true等待 60s`);
await wait(60 * 1000);
}
else {
log(`[auto] [${d}] 开始本地验证, type = ${challenge.type}`);
try {
await client.verifyChallenge(authz, challenge);
}
catch (e) {
log(`[auto] [${d}] 本地验证失败尝试请求ACME提供商获取状态: ${e.message}`);
}
}
/* Complete challenge and wait for valid status */
log(`[auto] [${d}] 请求ACME提供商完成验证等待返回valid状态`);
await client.completeChallenge(challenge);
challengeCompleted = true;
await client.waitForValidStatus(challenge);
}
catch (e) {
log(`[auto] [${d}] challengeCreateFn threw error: ${e.message}`);
throw e;
log(`[auto] [${d}] Deactivating failed authorization`);
await client.deactivateAuthorization(authz);
} catch (f) {
/* Suppress deactivateAuthorization() errors */
log(`[auto] [${d}] Authorization deactivation threw error: ${f.message}`);
}
}
catch (e) {
/* Deactivate pending authz when unable to complete challenge */
if (!challengeCompleted) {
log(`[auto] [${d}] Unable to complete challenge: ${e.message}`);
log(`[auto] [${d}] Trigger challengeCreateFn()`);
try {
const { recordReq, recordRes, dnsProvider, challenge, keyAuthorization } = await opts.challengeCreateFn(authz, keyAuthorizationGetter);
clearTasks.push(async () => {
/* Trigger challengeRemoveFn(), suppress errors */
log(`[auto] [${d}] Trigger challengeRemoveFn()`);
try {
log(`[auto] [${d}] Deactivating failed authorization`);
await client.deactivateAuthorization(authz);
await opts.challengeRemoveFn(authz, challenge, keyAuthorization, recordReq, recordRes, dnsProvider);
} catch (e) {
log(`[auto] [${d}] challengeRemoveFn threw error: ${e.message}`);
}
catch (f) {
/* Suppress deactivateAuthorization() errors */
log(`[auto] [${d}] Authorization deactivation threw error: ${f.message}`);
}
}
});
localVerifyTasks.push(async () => {
/* Challenge verification */
log(`[auto] [${d}] 开始本地验证, type = ${challenge.type}`);
try {
await client.verifyChallenge(authz, challenge);
} catch (e) {
log(`[auto] [${d}] 本地验证失败尝试请求ACME提供商获取状态: ${e.message}`);
}
});
completeChallengeTasks.push(async () => {
/* Complete challenge and wait for valid status */
log(`[auto] [${d}] 请求ACME提供商完成验证`);
try{
await client.completeChallenge(challenge);
}catch (e) {
await deactivateAuth(e);
throw e;
}
challengeCompleted = true;
log(`[auto] [${d}] 等待返回valid状态`);
await client.waitForValidStatus(challenge,d);
});
} catch (e) {
log(`[auto] [${d}] challengeCreateFn threw error: ${e.message}`);
await deactivateAuth(e);
throw e;
}
};
const domainSets = [];
@@ -168,7 +166,7 @@ export default async (client, userOpts) => {
const d = authz.identifier.value;
log(`authorization:domain = ${d}, value = ${JSON.stringify(authz)}`);
if (authz.status === 'valid') {
if (authz.status === "valid") {
log(`[auto] [${d}] Authorization already has valid status, no need to complete challenges`);
return;
}
@@ -192,8 +190,9 @@ export default async (client, userOpts) => {
const allChallengePromises = [];
// eslint-disable-next-line no-restricted-syntax
const challengePromises = [];
allChallengePromises.push(challengePromises);
for (const domainSet of domainSets) {
const challengePromises = [];
// eslint-disable-next-line guard-for-in,no-restricted-syntax
for (const domain in domainSet) {
const authz = domainSet[domain];
@@ -202,12 +201,11 @@ export default async (client, userOpts) => {
await challengeFunc(authz);
});
}
allChallengePromises.push(challengePromises);
}
log(`[auto] challengeGroups:${allChallengePromises.length}`);
function runAllPromise(tasks) {
async function runAllPromise(tasks) {
let promise = Promise.resolve();
tasks.forEach((task) => {
promise = promise.then(task);
@@ -215,73 +213,60 @@ export default async (client, userOpts) => {
return promise;
}
async function runPromisePa(tasks) {
async function runPromisePa(tasks, waitTime = 5000) {
const results = [];
// eslint-disable-next-line no-await-in-loop,no-restricted-syntax
for (const task of tasks) {
results.push(task());
// eslint-disable-next-line no-await-in-loop
await wait(10000);
await wait(waitTime);
}
return Promise.all(results);
}
try {
log(`开始challenge${allChallengePromises.length}`);
let i = 0;
// eslint-disable-next-line no-restricted-syntax
for (const challengePromises of allChallengePromises) {
i += 1;
log(`开始第${i}`);
if (opts.signal && opts.signal.aborted) {
throw new CancelError('用户取消');
log(`开始challenge${allChallengePromises.length}`);
let i = 0;
// eslint-disable-next-line no-restricted-syntax
for (const challengePromises of allChallengePromises) {
i += 1;
log(`开始第${i}`);
if (opts.signal && opts.signal.aborted) {
throw new CancelError("用户取消");
}
try {
// eslint-disable-next-line no-await-in-loop
await runPromisePa(challengePromises);
if (opts.skipChallengeVerification === true) {
log(`跳过本地验证skipChallengeVerification=true等待 60s`);
await wait(60 * 1000);
} else {
await runPromisePa(localVerifyTasks, 1000);
log("本地校验完成等待30s")
await wait(30 * 1000)
}
try {
// eslint-disable-next-line no-await-in-loop
await runPromisePa(challengePromises);
}
catch (e) {
log(`证书申请失败${e.message}`);
throw e;
}
finally {
if (client.opts.sslProvider !== 'google') {
// letsencrypt 如果同时检出两个TXT记录会以第一个为准就会校验失败所以需要提前删除
// zerossl 此方式测试无问题
log(`清理challenge痕迹length:${clearTasks.length}`);
try {
// eslint-disable-next-line no-await-in-loop
await runAllPromise(clearTasks);
}
catch (e) {
log('清理challenge失败');
log(e);
}
}
}
}
}
finally {
if (client.opts.sslProvider === 'google') {
// google 相同的域名txt记录是一样的不能提前删除否则校验失败报错如下
// Error: The TXT record retrieved from _acme-challenge.bbc.handsfree.work.
// at the time the challenge was validated did not contain JshHVu7dt_DT6uYILWhokHefFVad2Q6Mw1L-fNZFcq8
// (the base64url-encoded SHA-256 digest of RlJZNBR0LWnxNK_xd2zqtYVvCiNJOKJ3J1NmCjU_9BjaUJgL3k-qSpIhQ-uF4FBS.NRyqT8fRiq6THzzrvkgzgR5Xai2LsA2SyGLAq_wT3qc).
// See https://tools.ietf.org/html/rfc8555#section-8.4 for more information.
log("开始向提供商请求挑战验证");
await runPromisePa(completeChallengeTasks, 1000);
} catch (e) {
log(`证书申请失败${e.message}`);
throw e;
} finally {
// letsencrypt 如果同时检出两个TXT记录会以第一个为准就会校验失败所以需要提前删除
// zerossl 此方式测试无问题
log(`清理challenge痕迹length:${clearTasks.length}`);
try {
// eslint-disable-next-line no-await-in-loop
// eslint-disable-next-line no-await-in-loop
await runAllPromise(clearTasks);
}
catch (e) {
log('清理challenge失败');
} catch (e) {
log("清理challenge失败");
log(e);
}
}
}
log('challenge结束');
log("challenge结束");
// log('[auto] Waiting for challenge valid status');
// await Promise.all(challengePromises);
@@ -289,7 +274,7 @@ export default async (client, userOpts) => {
* Finalize order and download certificate
*/
log('[auto] Finalizing order and downloading certificate');
log("[auto] Finalizing order and downloading certificate");
const finalized = await client.finalizeOrder(order, opts.csr);
const res = await client.getCertificate(finalized, opts.preferredChain);
return res;

View File

@@ -554,9 +554,9 @@ class AcmeClient {
* ```
*/
async waitForValidStatus(item) {
async waitForValidStatus(item,d) {
if (!item.url) {
throw new Error('Unable to verify status of item, URL not found');
throw new Error(`[${d}] Unable to verify status of item, URL not found`);
}
const verifyFn = async (abort) => {
@@ -568,23 +568,23 @@ class AcmeClient {
const resp = await this.api.apiRequest(item.url, null, [200]);
/* Verify status */
log(`Item has status挑战状态: ${resp.data.status}`);
log(`[${d}] Item has status挑战状态: ${resp.data.status}`);
if (invalidStates.includes(resp.data.status)) {
abort();
throw new Error(util.formatResponseError(resp));
}
else if (pendingStates.includes(resp.data.status)) {
throw new Error('Operation is pending or processing当前仍然在等待状态');
throw new Error(`[${d}] Operation is pending or processing当前仍然在等待状态`);
}
else if (validStates.includes(resp.data.status)) {
return resp.data;
}
throw new Error(`Unexpected item status: ${resp.data.status}`);
throw new Error(`[${d}] Unexpected item status: ${resp.data.status}`);
};
log(`Waiting for valid status 等待valid状态: ${item.url}`, this.backoffOpts);
log(`[${d}] Waiting for valid status 等待valid状态: ${item.url}`, this.backoffOpts);
return util.retry(verifyFn, this.backoffOpts);
}

View File

@@ -98,7 +98,7 @@ export async function walkTxtRecord(recordName,deep = 0) {
try {
/* Default DNS resolver first */
log('从本地DNS服务器获取TXT解析记录');
const res = await walkDnsChallengeRecord(recordName,null,deep);
const res = await walkDnsChallengeRecord(recordName,dns,deep);
if (res && res.length > 0) {
for (const item of res) {
txtRecords.push(item)
@@ -147,12 +147,12 @@ async function verifyDnsChallenge(authz, challenge, keyAuthorization, prefix = '
let recordValues = await walkTxtRecord(recordName);
//去重
recordValues = [...new Set(recordValues)];
log(`DNS查询成功, 找到 ${recordValues.length} 条TXT记录`);
log(`DNS查询成功, 找到 ${recordValues.length} 条TXT记录${recordValues}`);
if (!recordValues.length || !recordValues.includes(keyAuthorization)) {
throw new Error(`没有找到需要的DNS TXT记录: ${recordName},期望:${keyAuthorization},结果:${recordValues}`);
}
log(`关键授权匹配成功(${challenge.type}/${recordName},校验成功, ACME challenge verified`);
log(`关键授权匹配成功(${challenge.type}/${recordName}:${keyAuthorization}校验成功 ACME challenge verified`);
return true;
}

View File

@@ -3,6 +3,24 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [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.31.11](https://github.com/certd/certd/compare/v1.31.10...v1.31.11) (2025-04-02)
**Note:** Version bump only for package @certd/basic

View File

@@ -1 +1 @@
00:28
01:29

View File

@@ -1,7 +1,7 @@
{
"name": "@certd/basic",
"private": false,
"version": "1.31.11",
"version": "1.33.2",
"type": "module",
"main": "./dist/index.js",
"module": "./dist/index.js",
@@ -44,5 +44,5 @@
"tslib": "^2.8.1",
"typescript": "^5.4.2"
},
"gitHead": "2e30fff221c19e46e098b0dc3250a6b7c5e6a5e0"
"gitHead": "64244af2cce396be5e2831937e5e3024a22899ed"
}

View File

@@ -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;
}

View File

@@ -3,6 +3,26 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [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.31.11](https://github.com/certd/certd/compare/v1.31.10...v1.31.11) (2025-04-02)
### Performance Improvements

View File

@@ -1,7 +1,7 @@
{
"name": "@certd/pipeline",
"private": false,
"version": "1.31.11",
"version": "1.33.2",
"type": "module",
"main": "./dist/index.js",
"module": "./dist/index.js",
@@ -16,8 +16,8 @@
"test": "mocha --loader=ts-node/esm"
},
"dependencies": {
"@certd/basic": "^1.31.11",
"@certd/plus-core": "^1.31.11",
"@certd/basic": "^1.33.2",
"@certd/plus-core": "^1.33.2",
"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": "2e30fff221c19e46e098b0dc3250a6b7c5e6a5e0"
"gitHead": "64244af2cce396be5e2831937e5e3024a22899ed"
}

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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;
});
}

View File

@@ -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");

View File

@@ -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;
}

View File

@@ -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;
},
});
};
}

View File

@@ -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);

View File

@@ -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> = {

View File

@@ -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>;
};

View File

@@ -3,6 +3,22 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.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.31.11](https://github.com/certd/certd/compare/v1.31.10...v1.31.11) (2025-04-02)
### Performance Improvements

View File

@@ -1,7 +1,7 @@
{
"name": "@certd/lib-huawei",
"private": false,
"version": "1.31.11",
"version": "1.33.2",
"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": "2e30fff221c19e46e098b0dc3250a6b7c5e6a5e0"
"gitHead": "64244af2cce396be5e2831937e5e3024a22899ed"
}

View File

@@ -3,6 +3,22 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.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.31.11](https://github.com/certd/certd/compare/v1.31.10...v1.31.11) (2025-04-02)
**Note:** Version bump only for package @certd/lib-iframe

View File

@@ -1,7 +1,7 @@
{
"name": "@certd/lib-iframe",
"private": false,
"version": "1.31.11",
"version": "1.33.2",
"type": "module",
"main": "./dist/index.js",
"module": "./dist/index.js",
@@ -30,5 +30,5 @@
"tslib": "^2.8.1",
"typescript": "^5.4.2"
},
"gitHead": "2e30fff221c19e46e098b0dc3250a6b7c5e6a5e0"
"gitHead": "64244af2cce396be5e2831937e5e3024a22899ed"
}

View File

@@ -3,6 +3,22 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.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.31.11](https://github.com/certd/certd/compare/v1.31.10...v1.31.11) (2025-04-02)
### Performance Improvements

View File

@@ -1,6 +1,6 @@
{
"name": "@certd/jdcloud",
"version": "1.31.11",
"version": "1.33.2",
"description": "jdcloud openApi sdk",
"main": "./dist/bundle.js",
"module": "./dist/bundle.js",
@@ -59,5 +59,6 @@
"Headers",
"fetch"
]
}
},
"gitHead": "64244af2cce396be5e2831937e5e3024a22899ed"
}

View File

@@ -3,6 +3,22 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.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.31.11](https://github.com/certd/certd/compare/v1.31.10...v1.31.11) (2025-04-02)
**Note:** Version bump only for package @certd/lib-k8s

View File

@@ -1,7 +1,7 @@
{
"name": "@certd/lib-k8s",
"private": false,
"version": "1.31.11",
"version": "1.33.2",
"type": "module",
"main": "./dist/index.js",
"module": "./dist/index.js",
@@ -16,7 +16,7 @@
"preview": "vite preview"
},
"dependencies": {
"@certd/basic": "^1.31.11",
"@certd/basic": "^1.33.2",
"@kubernetes/client-node": "0.21.0"
},
"devDependencies": {
@@ -31,5 +31,5 @@
"tslib": "^2.8.1",
"typescript": "^5.4.2"
},
"gitHead": "2e30fff221c19e46e098b0dc3250a6b7c5e6a5e0"
"gitHead": "64244af2cce396be5e2831937e5e3024a22899ed"
}

View File

@@ -3,6 +3,22 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.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.31.11](https://github.com/certd/certd/compare/v1.31.10...v1.31.11) (2025-04-02)
**Note:** Version bump only for package @certd/lib-server

View File

@@ -1,6 +1,6 @@
{
"name": "@certd/lib-server",
"version": "1.31.11",
"version": "1.33.2",
"description": "midway with flyway, sql upgrade way ",
"private": false,
"type": "module",
@@ -27,10 +27,10 @@
],
"license": "AGPL",
"dependencies": {
"@certd/acme-client": "^1.31.11",
"@certd/basic": "^1.31.11",
"@certd/pipeline": "^1.31.11",
"@certd/plus-core": "^1.31.11",
"@certd/acme-client": "^1.33.2",
"@certd/basic": "^1.33.2",
"@certd/pipeline": "^1.33.2",
"@certd/plus-core": "^1.33.2",
"@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": "2e30fff221c19e46e098b0dc3250a6b7c5e6a5e0"
"gitHead": "64244af2cce396be5e2831937e5e3024a22899ed"
}

View File

@@ -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);
}
}

View File

@@ -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> {

View File

@@ -3,6 +3,22 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.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.31.11](https://github.com/certd/certd/compare/v1.31.10...v1.31.11) (2025-04-02)
**Note:** Version bump only for package @certd/midway-flyway-js

View File

@@ -1,6 +1,6 @@
{
"name": "@certd/midway-flyway-js",
"version": "1.31.11",
"version": "1.33.2",
"description": "midway with flyway, sql upgrade way ",
"private": false,
"type": "module",
@@ -46,5 +46,5 @@
"typeorm": "^0.3.11",
"typescript": "^5.4.2"
},
"gitHead": "2e30fff221c19e46e098b0dc3250a6b7c5e6a5e0"
"gitHead": "64244af2cce396be5e2831937e5e3024a22899ed"
}

View File

@@ -3,6 +3,32 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [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.31.11](https://github.com/certd/certd/compare/v1.31.10...v1.31.11) (2025-04-02)
### Performance Improvements

View File

@@ -1,7 +1,7 @@
{
"name": "@certd/plugin-cert",
"private": false,
"version": "1.31.11",
"version": "1.33.2",
"type": "module",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
@@ -15,10 +15,10 @@
"preview": "vite preview"
},
"dependencies": {
"@certd/acme-client": "^1.31.11",
"@certd/basic": "^1.31.11",
"@certd/pipeline": "^1.31.11",
"@certd/plugin-lib": "^1.31.11",
"@certd/acme-client": "^1.33.2",
"@certd/basic": "^1.33.2",
"@certd/pipeline": "^1.33.2",
"@certd/plugin-lib": "^1.33.2",
"@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": "2e30fff221c19e46e098b0dc3250a6b7c5e6a5e0"
"gitHead": "64244af2cce396be5e2831937e5e3024a22899ed"
}

View File

@@ -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,
})

View File

@@ -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>;
}

View File

@@ -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);

View File

@@ -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);
}
}

View File

@@ -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 {

View File

@@ -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[];

View File

@@ -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,

View File

@@ -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 + "/";

View File

@@ -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}"`;

View File

@@ -3,6 +3,22 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.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.31.11](https://github.com/certd/certd/compare/v1.31.10...v1.31.11) (2025-04-02)
### Bug Fixes

View File

@@ -1,7 +1,7 @@
{
"name": "@certd/plugin-lib",
"private": false,
"version": "1.31.11",
"version": "1.33.2",
"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.31.11",
"@certd/pipeline": "^1.31.11",
"@certd/basic": "^1.33.2",
"@certd/pipeline": "^1.33.2",
"@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": "2e30fff221c19e46e098b0dc3250a6b7c5e6a5e0"
"gitHead": "64244af2cce396be5e2831937e5e3024a22899ed"
}

View File

@@ -139,6 +139,7 @@ export class AsyncSsh2Client {
script: string,
opts: {
throwOnStdErr?: boolean;
env?: any;
} = {}
): Promise<string> {
if (!script) {
@@ -153,7 +154,7 @@ 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) => {
this.conn.exec(script, { pty: true, env: opts.env }, (err: Error, stream: any) => {
if (err) {
reject(err);
return;
@@ -456,7 +457,7 @@ export class SshClient {
script = envScripts.join(newLine) + newLine + script;
}
}
return await conn.exec(script as string);
return await conn.exec(script as string, { env: options.env });
},
});
}

View File

@@ -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"]

View File

@@ -3,6 +3,32 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [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
* 优化华为dns解析记录创建和删除问题 ([0948c5b](https://github.com/certd/certd/commit/0948c5bc691d2ee6eb47c72a85da1b7453361878))
## [1.31.11](https://github.com/certd/certd/compare/v1.31.10...v1.31.11) (2025-04-02)
**Note:** Version bump only for package @certd/ui-client

View File

@@ -1,6 +1,6 @@
{
"name": "@certd/ui-client",
"version": "1.31.11",
"version": "1.33.2",
"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",
@@ -96,8 +100,8 @@
"zod-defaults": "^0.1.3"
},
"devDependencies": {
"@certd/lib-iframe": "^1.31.11",
"@certd/pipeline": "^1.31.11",
"@certd/lib-iframe": "^1.33.2",
"@certd/pipeline": "^1.33.2",
"@rollup/plugin-commonjs": "^25.0.7",
"@rollup/plugin-node-resolve": "^15.2.3",
"@types/chai": "^4.3.12",
@@ -155,6 +159,9 @@
"pre-commit": "pretty-quick --staged"
}
},
"pnpm": {
"neverBuiltDependencies": []
},
"gitHead": "9c2162697f3affea22c9a8cbc0ca74f4034ab27e",
"vite": {
"optimizeDeps": {

View File

@@ -1,9 +1,9 @@
<template>
<AConfigProvider :locale="locale" :theme="tokenTheme">
<fs-form-provider>
<FsFormProvider>
<contextHolder />
<router-view />
</fs-form-provider>
</FsFormProvider>
</AConfigProvider>
</template>

View File

@@ -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"
}
};
}
}
];

View File

@@ -1,9 +1,8 @@
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";
/**
* @description 创建请求实例
*/
@@ -12,8 +11,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 +20,7 @@ function createService() {
);
// 响应拦截
service.interceptors.response.use(
(response) => {
response => {
if (response.config.responseType === "blob") {
return response;
}
@@ -67,7 +66,7 @@ function createService() {
}
}
},
(error) => {
error => {
const status = get(error, "response.status");
switch (status) {
case 400:
@@ -130,11 +129,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 +148,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 });

View File

@@ -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,
};
}

View File

@@ -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();
},
};

View 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>

View File

@@ -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,
};

View File

@@ -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();
},
};
}

View File

@@ -0,0 +1 @@
export * from "monaco-yaml/yaml.worker.js";

View File

@@ -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>

View File

@@ -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);

View File

@@ -5,6 +5,6 @@ const apiPrefix = "/pi/dnsProvider";
export async function GetList() {
return await request({
url: apiPrefix + "/list",
method: "post"
method: "post",
});
}

View File

@@ -11,10 +11,10 @@ export default {
props: {
modelValue: {
type: String,
default: undefined
}
default: undefined,
},
},
emits: ["update:modelValue"],
emits: ["update:modelValue", "selected-change"],
setup(props: any, ctx: any) {
const options = ref<any[]>([]);
@@ -25,24 +25,36 @@ export default {
array.push({
value: item.name,
label: item.title,
icon: item.icon
icon: item.icon,
accessType: item.accessType,
});
}
options.value = array;
// if (props.modelValue == null && options.value.length > 0) {
// ctx.emit("update:modelValue", options.value[0].value);
// }
onSelectedChange(props.modelValue);
}
onCreate();
function onChanged(value: any) {
ctx.emit("update:modelValue", value);
onSelectedChange(value);
}
function onSelectedChange(value: any) {
if (value) {
const option = options.value.find(item => item.value == value);
if (option) {
ctx.emit("selected-change", option);
return;
}
}
}
return {
options,
onChanged
onChanged,
};
}
},
};
</script>

View File

@@ -1,6 +1,7 @@
import { request } from "/src/api/service";
const apiPrefix = "/cname/record";
const subDomainApiPrefix = "/pi/subDomain";
export type CnameRecord = {
id?: number;
@@ -18,7 +19,7 @@ export type DomainGroupItem = {
export async function GetList() {
return await request({
url: apiPrefix + "/list",
method: "post"
method: "post",
});
}
@@ -28,8 +29,8 @@ export async function GetByDomain(domain: string) {
method: "post",
data: {
domain,
createOnNotFound: true
}
createOnNotFound: true,
},
});
}
@@ -38,7 +39,17 @@ export async function DoVerify(id: number) {
url: apiPrefix + "/verify",
method: "post",
data: {
id
}
id,
},
});
}
export async function ParseDomain(fullDomain: string) {
return await request({
url: subDomainApiPrefix + "/parseDomain",
method: "post",
data: {
fullDomain,
},
});
}

View File

@@ -35,7 +35,7 @@ import { HttpRecord } from "/@/components/plugins/cert/domains-verify-plan-edito
import { dict } from "@fast-crud/fast-crud";
defineOptions({
name: "HttpVerifyPlan"
name: "HttpVerifyPlan",
});
const emit = defineEmits(["update:modelValue", "change"]);
@@ -53,12 +53,12 @@ watch(
(value: any) => {
if (value) {
records.value = {
...value
...value,
};
}
},
{
immediate: true
immediate: true,
}
);
@@ -75,8 +75,8 @@ const uploaderTypeDict = dict({
{ label: "阿里云OSS", value: "alioss" },
{ label: "腾讯云COS", value: "tencentcos" },
{ label: "七牛OSS", value: "qiniuoss" },
{ label: "SSH(已废弃请选择SFTP方式)", value: "ssh", disabled: true }
]
{ label: "SSH(已废弃请选择SFTP方式)", value: "ssh", disabled: true },
],
});
</script>

View File

@@ -38,6 +38,7 @@
:dict="dnsProviderTypeDict"
placeholder="DNS提供商"
@change="onPlanChanged"
@selected-change="onDnsProviderChange(item, $event)"
></fs-dict-select>
</span>
</div>
@@ -45,13 +46,7 @@
<div class="form-item">
<span class="label">DNS授权</span>
<span class="input">
<access-selector
v-model="item.dnsProviderAccessId"
size="small"
:type="item.dnsProviderType"
placeholder="请选择"
@change="onPlanChanged"
></access-selector>
<access-selector v-model="item.dnsProviderAccessId" size="small" :type="item.dnsProviderAccessType || item.dnsProviderType" placeholder="请选择" @change="onPlanChanged"></access-selector>
</span>
</div>
</div>
@@ -80,28 +75,27 @@ import { dict, FsDictSelect } from "@fast-crud/fast-crud";
import AccessSelector from "/@/views/certd/access/access-selector/index.vue";
import CnameVerifyPlan from "./cname-verify-plan.vue";
import HttpVerifyPlan from "./http-verify-plan.vue";
//@ts-ignore
import psl from "psl";
import { Form } from "ant-design-vue";
import { DomainsVerifyPlanInput } from "./type";
import { CnameRecord, DomainGroupItem } from "./api";
import { DomainGroupItem, ParseDomain } from "./api";
defineOptions({
name: "DomainsVerifyPlanEditor"
name: "DomainsVerifyPlanEditor",
});
const challengeTypeOptions = ref<any[]>([
{
label: "DNS验证",
value: "dns"
value: "dns",
},
{
label: "CNAME验证",
value: "cname"
value: "cname",
},
{
label: "HTTP验证",
value: "http"
}
value: "http",
},
]);
const props = defineProps<{
@@ -114,6 +108,10 @@ const emit = defineEmits<{
"update:modelValue": any;
}>();
function onDnsProviderChange(item: any, option: any) {
item.dnsProviderAccessType = option.accessType;
}
const fullscreen = ref(false);
function fullscreenExit() {
if (fullscreen.value) {
@@ -122,7 +120,7 @@ function fullscreenExit() {
}
const planRef = ref<DomainsVerifyPlanInput>(props.modelValue || {});
const dnsProviderTypeDict = dict({
url: "pi/dnsProvider/dnsProviderTypeDict"
url: "pi/dnsProvider/dnsProviderTypeDict",
});
const formItemContext = Form.useInjectFormItemContext();
@@ -139,7 +137,7 @@ function showError(error: string) {
type DomainGroup = Record<string, DomainGroupItem>;
function onDomainsChanged(domains: string[]) {
async function onDomainsChanged(domains: string[]) {
if (domains == null) {
return;
}
@@ -147,12 +145,7 @@ function onDomainsChanged(domains: string[]) {
const domainGroups: DomainGroup = {};
for (let domain of domains) {
const keyDomain = domain.replace("*.", "");
const parsed = psl.parse(keyDomain);
if (parsed.error) {
showError(`域名${domain}解析失败: ${JSON.stringify(parsed.error)}`);
continue;
}
const mainDomain = parsed.domain;
const mainDomain = await ParseDomain(keyDomain);
if (mainDomain == null) {
continue;
}
@@ -161,7 +154,7 @@ function onDomainsChanged(domains: string[]) {
group = {
domain: mainDomain,
domains: [],
keySubDomains: []
keySubDomains: [],
} as DomainGroupItem;
domainGroups[mainDomain] = group;
}
@@ -180,7 +173,7 @@ function onDomainsChanged(domains: string[]) {
//@ts-ignore
cnameVerifyPlan: {},
//@ts-ignore
httpVerifyPlan: {}
httpVerifyPlan: {},
};
planRef.value[domain] = planItem;
}
@@ -196,7 +189,7 @@ function onDomainsChanged(domains: string[]) {
if (!cnameOrigin[subDomain]) {
//@ts-ignore
planItem.cnameVerifyPlan[subDomain] = {
id: 0
id: 0,
};
} else {
planItem.cnameVerifyPlan[subDomain] = cnameOrigin[subDomain];
@@ -205,14 +198,14 @@ function onDomainsChanged(domains: string[]) {
if (!cnamePlan[subDomain]) {
//@ts-ignore
cnamePlan[subDomain] = {
id: 0
id: 0,
};
}
if (!httpOrigin[subDomain]) {
//@ts-ignore
planItem.httpVerifyPlan[subDomain] = {
domain: subDomain
domain: subDomain,
};
} else {
planItem.httpVerifyPlan[subDomain] = httpOrigin[subDomain];
@@ -221,7 +214,7 @@ function onDomainsChanged(domains: string[]) {
if (!httpPlan[subDomain]) {
//@ts-ignore
httpPlan[subDomain] = {
domain: subDomain
domain: subDomain,
};
}
}
@@ -255,7 +248,7 @@ watch(
},
{
immediate: true,
deep: true
deep: true,
}
);
</script>

View File

@@ -12,6 +12,7 @@ export type DomainVerifyPlanInput = {
domains: string[];
type: "cname" | "dns" | "http";
dnsProviderType?: string;
dnsProviderAccessType?: string;
dnsProviderAccessId?: number;
cnameVerifyPlan?: Record<string, CnameRecord>;
httpVerifyPlan?: Record<string, HttpRecord>;

View File

@@ -9,9 +9,10 @@
<script setup lang="ts">
import { inject, ref, watch } from "vue";
import { CertApplyPluginNames } from "/@/constants";
defineOptions({
name: "CertDomainsGetter"
name: "CertDomainsGetter",
});
const props = defineProps<{
@@ -52,7 +53,8 @@ function getDomainFromPipeline(inputKey: string) {
errorRef.value = "找不到目标步骤,请先选择域名证书";
return;
}
if (certStep.type !== "CertApply" && certStep.type !== "CertApplyLego") {
if (!CertApplyPluginNames.includes(certStep.type)) {
targetStepId = getStepIdFromInputKey(certStep.input?.cert);
certStep = findStepFromPipeline(targetStepId);
if (!certStep) {
@@ -73,7 +75,7 @@ watch(
getDomainFromPipeline(inputKey);
},
{
immediate: true
immediate: true,
}
);
</script>

View File

@@ -1,5 +1,5 @@
import { notification } from "ant-design-vue";
import { useSettingStore } from "/@/store/modules/settings";
import { useSettingStore } from "/@/store/settings";
export default {
mounted(el: any, binding: any, vnode: any) {

View File

@@ -16,9 +16,9 @@ import { computed, onMounted, reactive } from "vue";
import dayjs from "dayjs";
import { message, Modal } from "ant-design-vue";
import * as api from "./api";
import { useSettingStore } from "/@/store/modules/settings";
import { useSettingStore } from "/@/store/settings";
import { useRouter } from "vue-router";
import { useUserStore } from "/@/store/modules/user";
import { useUserStore } from "/@/store/user";
import { mitter } from "/@/utils/util.mitt";
const settingStore = useSettingStore();

View File

@@ -0,0 +1 @@
export const CertApplyPluginNames = ["CertApply", "CertApplyLego", "CertApplyUpload"];

View File

@@ -23,7 +23,7 @@
</template>
<script setup lang="ts">
import { computed, onMounted, ref } from "vue";
import { useSettingStore } from "/@/store/modules/settings";
import { useSettingStore } from "/@/store/settings";
defineOptions({
name: "PageFooter"

View File

@@ -10,7 +10,7 @@
<script lang="ts">
import { ref, defineComponent } from "vue";
import FsThemeColorPicker from "./color-picker.vue";
import { useSettingStore } from "/@/store/modules/settings";
import { useSettingStore } from "/@/store/settings";
export default defineComponent({
name: "FsTheme",

View File

@@ -13,7 +13,7 @@
<script lang="ts">
import { ref, defineComponent } from "vue";
import { useSettingStore } from "/@/store/modules/settings";
import { useSettingStore } from "/@/store/settings";
export default defineComponent({
name: "FsThemeModeSet",

View File

@@ -14,7 +14,7 @@
</a-dropdown>
</template>
<script lang="ts" setup>
import { useUserStore } from "/src/store/modules/user";
import { useUserStore } from "/src/store/user";
import { Modal } from "ant-design-vue";
import { useI18n } from "vue-i18n";
import { useRouter } from "vue-router";

View File

@@ -4,10 +4,10 @@ import { BasicLayout, LockScreen, UserDropdown } from "/@/vben/layouts";
import { computed, onErrorCaptured, onMounted } from "vue";
import { preferences } from "/@/vben/preferences";
import { useAccessStore } from "/@/vben/stores";
import { useUserStore } from "/@/store/modules/user";
import { useUserStore } from "/@/store/user";
import VipButton from "/@/components/vip-button/index.vue";
import TutorialButton from "/@/components/tutorial/index.vue";
import { useSettingStore } from "/@/store/modules/settings";
import { useSettingStore } from "/@/store/settings";
import PageFooter from "./components/footer/index.vue";
import { useRouter } from "vue-router";
const userStore = useUserStore();

View File

@@ -110,8 +110,8 @@ import FsThemeSet from "/@/layout/components/theme/index.vue";
import { env } from "../utils/util.env";
import VipButton from "/@/components/vip-button/index.vue";
import TutorialButton from "/@/components/tutorial/index.vue";
import { useUserStore } from "/@/store/modules/user";
import { useSettingStore } from "/@/store/modules/settings";
import { useUserStore } from "/@/store/user";
import { useSettingStore } from "/@/store/settings";
import { routerUtils } from "/@/utils/util.router";
import { theme } from "ant-design-vue";

View File

@@ -40,8 +40,8 @@
<script lang="ts" setup>
import { env } from "/@/utils/util.env";
import { computed, ref, Ref } from "vue";
import { useSettingStore } from "/@/store/modules/settings";
import { SiteInfo, SysPublicSetting } from "/@/api/modules/api.basic";
import { useSettingStore } from "/@/store/settings";
import { SiteInfo, SysPublicSetting } from "/@/store/settings/api.basic";
const envRef = ref(env);
const settingStore = useSettingStore();

View File

@@ -13,6 +13,7 @@ import plugin from "./plugin/";
import { setupVben } from "./vben";
import { util } from "/@/utils";
import { initPreferences } from "/@/vben/preferences";
// import "./components/code-editor/import-works";
// @ts-ignore
async function bootstrap() {
const app = createApp(App);
@@ -33,9 +34,9 @@ async function bootstrap() {
namespace,
overrides: {
app: {
name: import.meta.env.VITE_APP_TITLE
}
}
name: import.meta.env.VITE_APP_TITLE,
},
},
});
app.mount("#app");

View File

@@ -222,5 +222,5 @@ export default {
"AResult",
defineAsyncComponent(() => import("ant-design-vue/es/result"))
);
}
},
};

View File

@@ -2,5 +2,5 @@ import antdv from "ant-design-vue";
export default {
install(app: any) {
app.use(antdv);
}
},
};

View File

@@ -1,4 +1,4 @@
import { request, requestForMock } from "/src/api/service";
import { request } from "/src/api/service";
// import "/src/mock";
import { ColumnCompositionProps, CrudOptions, FastCrud, PageQuery, PageRes, setLogger, TransformResProps, useColumns, UseCrudProps, UserPageQuery, useTypes, utils } from "@fast-crud/fast-crud";
import "@fast-crud/fast-crud/dist/style.css";
@@ -51,10 +51,6 @@ function install(app: App, options: any = {}) {
app.use(FastCrud, {
i18n: options.i18n,
async dictRequest({ url }: any) {
if (url && url.startsWith("/mock")) {
//如果是crud开头的dict请求视为mock
return await requestForMock({ url, method: "post" });
}
return await request({ url, method: "post" });
},
/**

View File

@@ -1,5 +1,5 @@
import router from "/src/router";
import { useUserStore } from "/@/store/modules/user";
import { useUserStore } from "/@/store/user";
import { usePermissionStore } from "./store.permission";
import util from "./util.permission";
import { message } from "ant-design-vue";

View File

@@ -5,10 +5,10 @@ import { preferences } from "/@/vben/preferences";
import { useAccessStore } from "/@/vben/stores";
import { generateMenus, startProgress, stopProgress } from "/@/vben/utils";
import { frameworkRoutes } from "/@/router/resolve";
import { useSettingStore } from "/@/store/modules/settings";
import { useSettingStore } from "/@/store/settings";
import { usePermissionStore } from "/@/plugin/permission/store.permission";
import util from "/@/plugin/permission/util.permission";
import { useUserStore } from "/@/store/modules/user";
import { useUserStore } from "/@/store/user";
function buildAccessedMenus(menus: any) {
if (menus == null) {
@@ -22,7 +22,7 @@ function buildAccessedMenus(menus: any) {
}
}
const item: any = {
...sub
...sub,
};
list.push(item);
@@ -40,7 +40,7 @@ export function setupCommonGuard(router: Router) {
// 记录已经加载的页面
const loadedPaths = new Set<string>();
router.beforeEach(async (to) => {
router.beforeEach(async to => {
const settingStore = useSettingStore();
await settingStore.initOnce();
@@ -53,7 +53,7 @@ export function setupCommonGuard(router: Router) {
return true;
});
router.afterEach((to) => {
router.afterEach(to => {
// 记录页面是否加载,如果已经加载,后续的页面切换动画等效果不在重复执行
loadedPaths.add(to.path);
@@ -71,6 +71,10 @@ export function setupCommonGuard(router: Router) {
*/
function setupAccessGuard(router: Router) {
router.beforeEach(async (to, from) => {
if (to.matched && to.matched.length > 2) {
to.matched.splice(1, to.matched.length - 2);
}
const accessStore = useAccessStore();
// 是否已经生成过动态路由
if (!accessStore.isAccessChecked) {
@@ -93,7 +97,7 @@ function setupAccessGuard(router: Router) {
}
// 基本路由,这些路由不需要进入权限拦截
const needAuth = to.matched.some((r) => {
const needAuth = to.matched.some(r => {
return r.meta?.auth || r.meta?.permission;
});
@@ -108,7 +112,7 @@ function setupAccessGuard(router: Router) {
// 如不需要,直接删除 query
query: to.fullPath === DEFAULT_HOME_PATH ? {} : { redirect: encodeURIComponent(to.fullPath) },
// 携带当前跳转的页面,登录后重新跳转该页面
replace: true
replace: true,
};
}
return true;

View File

@@ -40,11 +40,11 @@ function transformOneResource(resource: any, parent: any) {
if (route.component == null) {
route.component = LayoutPass;
}
if (route?.meta?.cache !== true) {
if (route?.meta?.keepAlive !== true) {
if (route.meta == null) {
route.meta = {};
}
route.meta.cache = false;
route.meta.keepAlive = false;
}
}
if (resource.children) {
@@ -58,7 +58,7 @@ function transformOneResource(resource: any, parent: any) {
}
return {
menu,
route
route,
};
}
@@ -79,7 +79,7 @@ export const buildMenusAndRouters = (resources: any, parent: any = null) => {
setIndex(menus);
return {
routes,
menus
menus,
};
};

View File

@@ -4,7 +4,7 @@ import type { RouteRecordRaw } from "vue-router";
import { mergeRouteModules } from "/@/vben/utils";
const dynamicRouteFiles = import.meta.glob("./modules/**/*.ts*", {
eager: true
eager: true,
});
/** 动态路由 */
@@ -18,7 +18,7 @@ export const frameworkResource = [
component: LayoutBasic,
meta: {
icon: "ion:accessibility",
hideInBreadcrumb: true
hideInBreadcrumb: true,
},
children: [
{
@@ -30,13 +30,13 @@ export const frameworkResource = [
fixedAside: true,
showOnHeader: false,
icon: "ion:home-outline",
auth: true
}
auth: true,
},
},
// @ts-ignore
...dynamicRoutes
]
}
...dynamicRoutes,
],
},
];
console.assert(frameworkResource.length === 1, "frameworkResource数组长度只能为1你只能配置framework路由的子路由");

View File

@@ -1,5 +1,5 @@
import { IFrameView } from "/@/vben/layouts";
import { useSettingStore } from "/@/store/modules/settings";
import { useSettingStore } from "/@/store/settings";
import { computed } from "vue";
import TutorialButton from "/@/components/tutorial/index.vue";
export const aboutResource = [

View File

@@ -1,4 +1,4 @@
import { useSettingStore } from "/@/store/modules/settings";
import { useSettingStore } from "/@/store/settings";
import aboutResource from "/@/router/source/modules/about";
export const certdResources = [
@@ -10,7 +10,7 @@ export const certdResources = [
meta: {
icon: "ion:key-outline",
auth: true,
order: 0
order: 0,
},
children: [
{
@@ -20,8 +20,8 @@ export const certdResources = [
component: "/certd/pipeline/index.vue",
meta: {
icon: "ion:analytics-sharp",
cache: true
}
keepAlive: true,
},
},
{
title: "编辑流水线",
@@ -29,8 +29,8 @@ export const certdResources = [
path: "/certd/pipeline/detail",
component: "/certd/pipeline/detail.vue",
meta: {
isMenu: false
}
isMenu: false,
},
},
{
title: "执行历史记录",
@@ -39,8 +39,8 @@ export const certdResources = [
component: "/certd/history/index.vue",
meta: {
icon: "ion:timer-outline",
cache: true
}
keepAlive: true,
},
},
{
title: "证书仓库",
@@ -50,8 +50,9 @@ export const certdResources = [
meta: {
icon: "ion:shield-checkmark-outline",
auth: true,
isMenu: true
}
isMenu: true,
keepAlive: true,
},
},
{
title: "站点证书监控",
@@ -60,8 +61,9 @@ export const certdResources = [
component: "/certd/monitor/site/index.vue",
meta: {
icon: "ion:videocam-outline",
auth: true
}
auth: true,
keepAlive: true,
},
},
{
title: "设置",
@@ -71,7 +73,7 @@ export const certdResources = [
meta: {
icon: "ion:settings-outline",
auth: true,
cache: true
keepAlive: true,
},
children: [
{
@@ -82,8 +84,8 @@ export const certdResources = [
meta: {
icon: "ion:disc-outline",
auth: true,
cache: true
}
keepAlive: true,
},
},
{
title: "CNAME记录管理",
@@ -92,8 +94,20 @@ export const certdResources = [
component: "/certd/cname/record/index.vue",
meta: {
icon: "ion:link-outline",
auth: true
}
auth: true,
keepAlive: true,
},
},
{
title: "子域名托管设置",
name: "SubDomain",
path: "/certd/pipeline/subDomain",
component: "/certd/pipeline/sub-domain/index.vue",
meta: {
icon: "material-symbols:approval-delegation-outline",
auth: true,
keepAlive: true,
},
},
{
title: "流水线分组管理",
@@ -102,8 +116,9 @@ export const certdResources = [
component: "/certd/pipeline/group/index.vue",
meta: {
icon: "mdi:format-list-group",
auth: true
}
auth: true,
keepAlive: true,
},
},
{
@@ -114,8 +129,8 @@ export const certdResources = [
meta: {
icon: "hugeicons:api",
auth: true,
cache: true
}
keepAlive: true,
},
},
{
title: "通知设置",
@@ -125,8 +140,8 @@ export const certdResources = [
meta: {
icon: "ion:megaphone-outline",
auth: true,
cache: true
}
keepAlive: true,
},
},
{
title: "账号信息",
@@ -136,10 +151,10 @@ export const certdResources = [
meta: {
icon: "ion:person-outline",
auth: true,
isMenu: false
}
}
]
isMenu: false,
},
},
],
},
{
@@ -153,7 +168,7 @@ export const certdResources = [
return settingStore.isComm && settingStore.isSuiteEnabled;
},
icon: "ion:cart-outline",
auth: true
auth: true,
},
children: [
{
@@ -167,8 +182,8 @@ export const certdResources = [
return settingStore.isComm;
},
icon: "ion:gift-outline",
auth: true
}
auth: true,
},
},
{
title: "套餐购买",
@@ -181,8 +196,8 @@ export const certdResources = [
return settingStore.isComm;
},
icon: "ion:cart-outline",
auth: true
}
auth: true,
},
},
{
title: "我的订单",
@@ -195,8 +210,9 @@ export const certdResources = [
return settingStore.isComm;
},
icon: "ion:bag-check-outline",
auth: true
}
auth: true,
keepAlive: true,
},
},
{
title: "支付返回",
@@ -206,11 +222,11 @@ export const certdResources = [
meta: {
icon: "ant-design:pay-circle-outlined",
auth: false,
isMenu: false
}
}
]
}
isMenu: false,
},
},
],
},
// {
// title: "邮箱设置",
@@ -222,8 +238,8 @@ export const certdResources = [
// auth: true
// }
// },
]
}
],
},
];
export default certdResources;

Some files were not shown because too many files have changed in this diff Show More