Compare commits

...

194 Commits

Author SHA1 Message Date
xiaojunnuo
9749fc817d v1.34.0 2025-04-28 17:27:05 +08:00
xiaojunnuo
e6600f2c43 build: prepare to build 2025-04-28 17:24:37 +08:00
xiaojunnuo
a664931e7a build: prepare to build 2025-04-28 17:14:39 +08:00
xiaojunnuo
a2ba965600 chore: 2025-04-28 17:12:25 +08:00
xiaojunnuo
65255dbb50 chore: 恢复加载插件方式为注解方式 2025-04-28 17:05:14 +08:00
xiaojunnuo
a5cb8761a5 build: prepare to build 2025-04-28 16:58:59 +08:00
xiaojunnuo
e3930e0717 fix: 修复二次认证登录进入错误账号的bug 2025-04-28 16:57:30 +08:00
xiaojunnuo
afd59e9933 perf: 优化cdnfly插件,支持自动匹配域名部署 2025-04-28 00:55:39 +08:00
xiaojunnuo
8087524bef chore: product info 2025-04-27 22:51:47 +08:00
xiaojunnuo
605440812f Merge remote-tracking branch 'refs/remotes/origin/v2-dev-plugin-yaml' into v2-dev
# Conflicts:
#	packages/ui/certd-server/export-plugin-yaml.js
2025-04-27 22:50:19 +08:00
xiaojunnuo
b10c6eb615 Merge branch 'v2-dev-yaml' into v2-dev 2025-04-27 21:35:36 +08:00
xiaojunnuo
a96264ff6a chore: 2025-04-27 15:50:38 +08:00
xiaojunnuo
deb3893820 feat: 从yaml文件注册插件 2025-04-27 15:11:50 +08:00
xiaojunnuo
9b1d822b5b chore: 2025-04-27 11:05:01 +08:00
xiaojunnuo
5cd61c4c02 build: publish 2025-04-27 01:58:54 +08:00
xiaojunnuo
586fa70eac build: trigger build image 2025-04-27 01:58:37 +08:00
xiaojunnuo
9b420ad33f v1.33.8 2025-04-27 01:56:54 +08:00
xiaojunnuo
5891290672 build: prepare to build 2025-04-27 01:54:19 +08:00
xiaojunnuo
72a7b51d47 fix: 修复http上传方式无法清除记录文件的bug 2025-04-27 01:52:42 +08:00
xiaojunnuo
2943e0e58d chore: oss 库 完善 2025-04-27 01:31:46 +08:00
xiaojunnuo
5abce916a8 chore: 2025-04-25 18:45:42 +08:00
xiaojunnuo
89d4be8a0a chore: 2025-04-25 18:37:29 +08:00
xiaojunnuo
b7113bda23 perf: 七牛oss支持删除过期备份 2025-04-25 18:36:49 +08:00
xiaojunnuo
0088929622 perf: 支持反向代理增加contextPath路径 2025-04-25 18:04:59 +08:00
xiaojunnuo
b3468cf7f2 perf: 支持阿里云中文域名申请 2025-04-25 18:04:24 +08:00
xiaojunnuo
f88c5c8528 chore: 2025-04-25 02:11:23 +08:00
xiaojunnuo
687fdda7f7 chore: 2025-04-25 02:11:08 +08:00
xiaojunnuo
aec51e514c chore: 2025-04-25 01:44:15 +08:00
xiaojunnuo
308d4600ef perf: 数据库备份支持oss 2025-04-25 01:26:04 +08:00
xiaojunnuo
50a5fa15bb fix: 修复token过期后,疯狂打印token过期信息的bug 2025-04-24 23:54:09 +08:00
xiaojunnuo
7d96a57d73 chore: 2025-04-24 17:27:13 +08:00
xiaojunnuo
162ebfd4e0 perf: 支持中文域名 2025-04-24 11:55:14 +08:00
xiaojunnuo
a586a92d5e perf: 从域名的soa获取主域名,子域名托管无需额外配置 2025-04-24 11:54:54 +08:00
xiaojunnuo
3df20a924f fix: 修复复制流水线无效的bug 2025-04-24 09:09:38 +08:00
xiaojunnuo
ddcf466e4e docs: 升级前切记备份数据 2025-04-23 17:59:48 +08:00
xiaojunnuo
5d10cbf18d fix: 服务器时间获取不准确的bug 2025-04-23 14:55:51 +08:00
xiaojunnuo
8d9afa7592 build: publish 2025-04-22 22:32:56 +08:00
xiaojunnuo
95e05336c2 build: trigger build image 2025-04-22 22:32:18 +08:00
xiaojunnuo
a188385817 v1.33.7 2025-04-22 22:27:50 +08:00
xiaojunnuo
0a6baf331b build: prepare to build 2025-04-22 22:12:51 +08:00
xiaojunnuo
0e29e052d5 Merge remote-tracking branch 'origin/v2-dev' into v2-dev 2025-04-22 22:11:32 +08:00
xiaojunnuo
d8d255980e chore: 2025-04-22 15:53:19 +08:00
xiaojunnuo
dc5a5fa543 chore: 2025-04-22 11:41:45 +08:00
xiaojunnuo
8638fc91ff perf: 证书申请支持51dns 2025-04-22 11:39:09 +08:00
xiaojunnuo
96a0900edc perf: 支持51dns 2025-04-22 11:39:07 +08:00
xiaojunnuo
abea80e3ab perf: 添加部署证书至火山 Live
- 新增 VolcengineDeployToLive 插件,用于将证书部署到火山引擎视频直播
- 新增 VolcengineDeployToVOD 插件,用于将证书部署到火山引擎视频点播
- 更新 ve-client.ts,增加对 Live 和 VOD 服务的支持
2025-04-21 23:39:33 +08:00
xiaojunnuo
42dfe936b7 perf: ssh伪终端模式优化,windows下不开启 2025-04-21 17:34:26 +08:00
xiaojunnuo
8385bcc2d7 perf: ssh PTY模式登录设置 2025-04-21 17:26:42 +08:00
xiaojunnuo
9b8f60b64b perf: 优化首页插件列表展示 2025-04-21 12:13:01 +08:00
xiaojunnuo
474114236e build: publish 2025-04-21 00:08:56 +08:00
xiaojunnuo
238b0b421a build: trigger build image 2025-04-21 00:08:38 +08:00
xiaojunnuo
8abe62886a v1.33.6 2025-04-21 00:06:48 +08:00
xiaojunnuo
78cc9cffe4 build: prepare to build 2025-04-21 00:04:13 +08:00
xiaojunnuo
59a5dd713f chore: 2025-04-20 23:58:02 +08:00
xiaojunnuo
a39024ff03 build: prepare to build 2025-04-20 23:55:30 +08:00
xiaojunnuo
72bfbd93a8 chore: 2025-04-20 23:55:05 +08:00
xiaojunnuo
c9a3e3d9d2 perf: 新增部署到火山引擎ALB/CLB、上传到证书中心 2025-04-20 23:53:27 +08:00
xiaojunnuo
8387708901 docs: 2025-04-20 21:23:59 +08:00
xiaojunnuo
b565b4b3b9 perf: 优化华为cdn插件引用ccm证书 2025-04-20 20:16:36 +08:00
xiaojunnuo
893dcd4f24 perf: 切换到不同的分组后再打开创建对话框,会自动选择分组 2025-04-19 17:08:44 +08:00
xiaojunnuo
d613aa8f3e perf: 优化证书流水线创建,支持选择分组 2025-04-19 16:05:24 +08:00
xiaojunnuo
5750bb7067 fix: 上传商用证书,直接粘贴文本报错的问题;修复无法上传ec加密证书的bug 2025-04-19 15:00:34 +08:00
xiaojunnuo
0e07ae6ce8 fix: 修复下载证书时提示token已过期的问题 2025-04-19 14:25:56 +08:00
xiaojunnuo
02b6351e13 docs: 宝塔network 2025-04-19 12:14:19 +08:00
xiaojunnuo
78367af830 perf: 更新license时同时绑定url 2025-04-19 11:48:40 +08:00
xiaojunnuo
dc05cd481f perf: 优化/api缓存为0 2025-04-18 15:23:51 +08:00
xiaojunnuo
7daad5477a Merge remote-tracking branch 'origin/v2-dev' into v2-dev 2025-04-18 10:17:48 +08:00
xiaojunnuo
45cdfbfae8 chore: 2025-04-18 10:17:24 +08:00
xiaojunnuo
3fb5c38571 build: publish 2025-04-17 23:37:26 +08:00
xiaojunnuo
59f80ebc47 build: trigger build image 2025-04-17 23:37:09 +08:00
xiaojunnuo
198a97b00c v1.33.5 2025-04-17 23:35:14 +08:00
xiaojunnuo
3ea4e917e8 build: prepare to build 2025-04-17 23:32:08 +08:00
xiaojunnuo
60ad077172 pref: 任务日志查看页面,增加强制重新运行按钮 2025-04-17 23:31:43 +08:00
xiaojunnuo
356ad28e41 chore: 2025-04-17 23:11:04 +08:00
xiaojunnuo
e241141220 build: prepare to build 2025-04-17 23:07:14 +08:00
xiaojunnuo
14bb1b467a chore: 2025-04-17 23:06:17 +08:00
xiaojunnuo
2bbea6fd3f chore: 2025-04-17 23:05:52 +08:00
xiaojunnuo
48aef25b3f perf: 登录支持双重认证 2025-04-17 22:34:21 +08:00
xiaojunnuo
8e50e5dee3 chore: plus 2025-04-17 13:41:08 +08:00
xiaojunnuo
d5d54d4d3b chore: 2FA 2025-04-17 01:15:55 +08:00
xiaojunnuo
412e8a32dd Merge remote-tracking branch 'origin/v2-dev' into v2-dev 2025-04-17 00:06:58 +08:00
xiaojunnuo
0f82cf409b perf: 多重认证登录 2025-04-17 00:06:49 +08:00
xiaojunnuo
79df39acab perf: 优化部署到华为云CDN,支持先上传到ccm,再使用证书id部署,修复offline状态下导致部署报错的bug 2025-04-16 09:34:04 +08:00
xiaojunnuo
8786bae7dc chore: 2025-04-16 00:03:13 +08:00
xiaojunnuo
4b3f8ca361 chore: 2025-04-16 00:02:58 +08:00
xiaojunnuo
03183218f7 chore: 2025-04-16 00:01:52 +08:00
xiaojunnuo
95b6db57e1 chore: 2025-04-15 23:57:50 +08:00
xiaojunnuo
bbe0c2457b build: publish 2025-04-15 23:50:06 +08:00
xiaojunnuo
c894c53e69 build: trigger build image 2025-04-15 23:49:48 +08:00
xiaojunnuo
5b3fb7387d v1.33.4 2025-04-15 23:48:00 +08:00
xiaojunnuo
feac310caf build: prepare to build 2025-04-15 23:45:18 +08:00
xiaojunnuo
d67ec3feb3 chore: 2025-04-15 23:45:11 +08:00
xiaojunnuo
cf8abb4528 perf: 插件支持导入导出 2025-04-15 23:43:01 +08:00
xiaojunnuo
d66de26de4 Merge branch 'v2' into v2-dev 2025-04-15 21:34:13 +08:00
xiaojunnuo
e5a7ada3cf Merge branch 'v2' into v2-dev-yaml 2025-04-15 21:19:39 +08:00
xiaojunnuo
b76fdd7fe4 Merge branch 'v2-dev' into v2-dev-yaml 2025-04-15 21:19:36 +08:00
greper
7edf3f6147 fix: 修复腾讯云部署到任意资源插件,无法使用之前已上传的腾讯云证书问题 from xinghejd/dev @xinghejd
fix: 修复腾讯云部署到任意资源插件,无法使用之前已上传的腾讯云证书问题
2025-04-15 21:16:49 +08:00
xinghejd
2143dff2ae fix: 补充类型断言 2025-04-15 08:54:28 +00:00
xinghejd
32c714d1b6 fix: 修复腾讯云部署到任意资源插件,无法使用之前已上传的腾讯云证书问题 2025-04-15 08:47:57 +00:00
xiaojunnuo
84e699ee24 chore: 思维导图 2025-04-15 11:22:42 +08:00
xiaojunnuo
7fdb572b8b chore: 思维导图 2025-04-15 11:07:27 +08:00
xiaojunnuo
91ffb0820a chore: plugin元数据换成yaml格式 2025-04-15 00:16:57 +08:00
xiaojunnuo
cfd3b66be9 perf: 支持上传证书到华为云CCM 2025-04-14 23:31:59 +08:00
xiaojunnuo
75c4f9dea8 build: publish 2025-04-14 22:27:24 +08:00
xiaojunnuo
a76a32230d build: trigger build image 2025-04-14 22:26:59 +08:00
xiaojunnuo
0730f5ff4f v1.33.3 2025-04-14 22:25:16 +08:00
xiaojunnuo
c43d0a684c build: prepare to build 2025-04-14 22:22:17 +08:00
xiaojunnuo
66f1eda6cf chore: 2025-04-14 22:22:01 +08:00
xiaojunnuo
bf4d191c8b fix: 修复登录错误次数过多阻止再次登录逻辑 2025-04-14 18:09:54 +08:00
xiaojunnuo
d76d56fcce pref: 安全特性支持,站点隐藏功能 2025-04-14 17:40:23 +08:00
xiaojunnuo
251b0c58de chore: 2025-04-14 10:06:58 +08:00
xiaojunnuo
073cca4e8e chore: 2025-04-14 09:54:24 +08:00
xiaojunnuo
a4ad99f189 build: publish 2025-04-13 01:33:57 +08:00
xiaojunnuo
d37b910889 build: trigger build image 2025-04-13 01:33:28 +08:00
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
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
545aa50898 Merge branch 'v2-dev' into v2-plugin 2025-04-04 20:14:24 +08:00
xiaojunnuo
071ef281c1 chore: 2025-04-01 22:34:15 +08:00
478 changed files with 17693 additions and 3530 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,131 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [1.34.0](https://github.com/certd/certd/compare/v1.33.8...v1.34.0) (2025-04-28)
### Bug Fixes
* 修复二次认证登录进入错误账号的bug ([e3930e0](https://github.com/certd/certd/commit/e3930e07172dd7903cb0f6ff26e0e3e828ba3e77))
### Features
* 从yaml文件注册插件 ([deb3893](https://github.com/certd/certd/commit/deb38938204b29543f36d3266249958faaaa6b66))
### Performance Improvements
* 优化cdnfly插件支持自动匹配域名部署 ([afd59e9](https://github.com/certd/certd/commit/afd59e9933b2650f41c5d47684c171b93b962065))
## [1.33.8](https://github.com/certd/certd/compare/v1.33.7...v1.33.8) (2025-04-26)
### Bug Fixes
* 服务器时间获取不准确的bug ([5d10cbf](https://github.com/certd/certd/commit/5d10cbf18daf94a90a7551641a3b13e3c5fec611))
* 修复复制流水线无效的bug ([3df20a9](https://github.com/certd/certd/commit/3df20a924f32970b052e2588ea20de095f0ea693))
* 修复http上传方式无法清除记录文件的bug ([72a7b51](https://github.com/certd/certd/commit/72a7b51d479602b2c54c6c3ac8d8a0dcb9664e73))
* 修复token过期后疯狂打印token过期信息的bug ([50a5fa1](https://github.com/certd/certd/commit/50a5fa15bb240a125bbc91d2ce1ff3c835888a77))
### Performance Improvements
* 从域名的soa获取主域名子域名托管无需额外配置 ([a586a92](https://github.com/certd/certd/commit/a586a92d5e32ea846ac37be52a7ad8c328d89966))
* 七牛oss支持删除过期备份 ([b7113bd](https://github.com/certd/certd/commit/b7113bda2378116d6c116dc583f563cce7cf9f00))
* 数据库备份支持oss ([308d460](https://github.com/certd/certd/commit/308d4600efe2002f199c33b4594d3071784e58ea))
* 支持阿里云中文域名申请 ([b3468cf](https://github.com/certd/certd/commit/b3468cf7f28228d7c9cf68de6b5a9bbeb67f2c6d))
* 支持反向代理增加contextPath路径 ([0088929](https://github.com/certd/certd/commit/0088929622160cc922995de9a563e8061686ff34))
* 支持中文域名 ([162ebfd](https://github.com/certd/certd/commit/162ebfd4e0c25727efb33952d3bbf7420a02e2c3))
## [1.33.7](https://github.com/certd/certd/compare/v1.33.6...v1.33.7) (2025-04-22)
### Performance Improvements
* 添加部署证书至火山 Live ([abea80e](https://github.com/certd/certd/commit/abea80e3ab9b1672aebe1c5d5e856693b29931a8))
* 优化首页插件列表展示 ([9b8f60b](https://github.com/certd/certd/commit/9b8f60b64b5f9a3db7dfa9b3dcbd9201984358d0))
* 证书申请支持51dns ([8638fc9](https://github.com/certd/certd/commit/8638fc91ff34fccaf12ff9874fd3fa9d2a8c18b7))
* 支持51dns ([96a0900](https://github.com/certd/certd/commit/96a0900edc95dcfd9acccf9d13592f12f5a09b3d))
* ssh PTY模式登录设置 ([8385bcc](https://github.com/certd/certd/commit/8385bcc2d7f2411a07748bb5c53f9eaf4d38d7cc))
* ssh伪终端模式优化windows下不开启 ([42dfe93](https://github.com/certd/certd/commit/42dfe936b773b7bdd82ca3378363252ffffd7b71))
## [1.33.6](https://github.com/certd/certd/compare/v1.33.5...v1.33.6) (2025-04-20)
### Bug Fixes
* 上传商用证书直接粘贴文本报错的问题修复无法上传ec加密证书的bug ([5750bb7](https://github.com/certd/certd/commit/5750bb706779da274d8e7a87e71416cb64d2df79))
* 修复下载证书时提示token已过期的问题 ([0e07ae6](https://github.com/certd/certd/commit/0e07ae6ce84dcb9279d3c44060d621566afa593c))
### Performance Improvements
* 更新license时同时绑定url ([78367af](https://github.com/certd/certd/commit/78367af8307f801e778c76d49f0918c21ffe032f))
* 切换到不同的分组后再打开创建对话框,会自动选择分组 ([893dcd4](https://github.com/certd/certd/commit/893dcd4f2487891199ed3e5a3d47a79a75efc942))
* 新增部署到火山引擎ALB/CLB、上传到证书中心 ([c9a3e3d](https://github.com/certd/certd/commit/c9a3e3d9d26f964c7af7b56667936f1414fbf42a))
* 优化/api缓存为0 ([dc05cd4](https://github.com/certd/certd/commit/dc05cd481f186b13375192be965000e6b4b429a5))
* 优化华为cdn插件引用ccm证书 ([b565b4b](https://github.com/certd/certd/commit/b565b4b3b919b71b98ea2517670bc1ef00e00dc9))
* 优化证书流水线创建,支持选择分组 ([d613aa8](https://github.com/certd/certd/commit/d613aa8f3e85d8dc475ef1b62d49394ce7fd7d24))
## [1.33.5](https://github.com/certd/certd/compare/v1.33.4...v1.33.5) (2025-04-17)
### Performance Improvements
* 登录支持双重认证 ([48aef25](https://github.com/certd/certd/commit/48aef25b3f6499d674ca4e4ef16f4c62399fb735))
* 多重认证登录 ([0f82cf4](https://github.com/certd/certd/commit/0f82cf409bc60706ab07e4ca4f272b9a1ca7eecb))
* 优化部署到华为云CDN支持先上传到ccm再使用证书id部署修复offline状态下导致部署报错的bug ([79df39a](https://github.com/certd/certd/commit/79df39acabab10ae7e1864dadcdc186bb007a3c5))
## [1.33.4](https://github.com/certd/certd/compare/v1.33.3...v1.33.4) (2025-04-15)
### Bug Fixes
* 补充类型断言 ([2143dff](https://github.com/certd/certd/commit/2143dff2ae96e6a78bef9f0498e36f8cd9e6941f))
* 修复腾讯云部署到任意资源插件,无法使用之前已上传的腾讯云证书问题 ([32c714d](https://github.com/certd/certd/commit/32c714d1b6e68c71a74a7452115040c87ac4bfdc))
### Performance Improvements
* 插件支持导入导出 ([cf8abb4](https://github.com/certd/certd/commit/cf8abb45282070c8ba91469f93fd379fabf1f74a))
* 支持上传证书到华为云CCM ([cfd3b66](https://github.com/certd/certd/commit/cfd3b66be9ebf53a26693057e70ed60c3f116be9))
## [1.33.3](https://github.com/certd/certd/compare/v1.33.2...v1.33.3) (2025-04-14)
### Bug Fixes
* 修复登录错误次数过多阻止再次登录逻辑 ([bf4d191](https://github.com/certd/certd/commit/bf4d191c8bd2f9209eb6768f662b9c77de99e998))
## [1.33.2](https://github.com/certd/certd/compare/v1.33.1...v1.33.2) (2025-04-12)
### Bug Fixes
* 修复某些情况下无法输出日志的bug ([70101bf](https://github.com/certd/certd/commit/70101bfa7ade65678d9202c804bbae2cb808b594))
### Performance Improvements
* 修复内置插件分页查询逻辑 ([a2710dd](https://github.com/certd/certd/commit/a2710ddc2525e4e637fd157f0180e6d3b801c8be))
## [1.33.1](https://github.com/certd/certd/compare/v1.33.0...v1.33.1) (2025-04-12)
### Bug Fixes
* 修复阿里云cdn证书部署失败问题增加certname参数传入 ([965dc2c](https://github.com/certd/certd/commit/965dc2cb476f690af716f291c6b20ba98be0c8f0))
* 修复ssh插件报length空指针的bug ([9c4cbe1](https://github.com/certd/certd/commit/9c4cbe17a22b548611cf1fbefecc83a421788e42))
### Performance Improvements
* 镜像支持armv7 ([f78cbed](https://github.com/certd/certd/commit/f78cbed4d817859721fdafe7d348864848d0dfbf))
# [1.33.0](https://github.com/certd/certd/compare/v1.32.0...v1.33.0) (2025-04-11)
### Bug Fixes
* 升级mysql驱动支持mysql8最新版本的认证 ([2f5ed3a](https://github.com/certd/certd/commit/2f5ed3aead97641f2c80d692a50226839016df0b))
* 修复eab授权没有email绑定的bug ([2f1683b](https://github.com/certd/certd/commit/2f1683b26acebbfb7d6e2d751435be04a4e7cab4))
### Features
* 支持在线自定义插件,无需源码开发 ([d0d9d68](https://github.com/certd/certd/commit/d0d9d68fe6740f6ff49fe40b7c9917c5a2e4b442))
* **lego:** support set key type ([f3bf4fa](https://github.com/certd/certd/commit/f3bf4faee0be5bdbfdbcf70a502849ed4c8ed4c4))
* release image to ghcr ([9b536af](https://github.com/certd/certd/commit/9b536af9e656dc89e2a87078c129cad6f591e467))
### Performance Improvements
* 修复tab页缓存问题 ([64e5449](https://github.com/certd/certd/commit/64e5449ab3c6b219b0e89eddad14bfb6b71a0650))
* 隐藏运行策略选项 ([2951df0](https://github.com/certd/certd/commit/2951df0cd94c23e2efee84ff1b843055aac56cae))
* 增加手动上传证书功能说明 ([5d083a1](https://github.com/certd/certd/commit/5d083a153637caddbc6f44e915d9fb2d1ae87b33))
# [1.32.0](https://github.com/certd/certd/compare/v1.31.11...v1.32.0) (2025-04-04)
### Bug Fixes

131
README.md
View File

@@ -9,13 +9,16 @@ Certd 是一个免费全自动申请和自动部署更新SSL证书的管理系
本项目不仅支持证书申请过程自动化,还可以自动化部署更新证书,让你的证书永不过期。
* 全自动申请证书(支持所有注册商注册的域名)
* 全自动部署更新证书(目前支持部署到主机、阿里云、腾讯云等目前已支持60+部署插件)
* 全自动部署更新证书(目前支持部署到主机、阿里云、腾讯云等70+部署插件)
* 支持DNS-01、HTTP-01、CNAME代理等多种域名验证方式
* 支持通配符域名/泛域名支持多个域名打到一个证书上支持pem、pfx、der、jks等多种证书格式
* 邮件通知、webhook通知
* 私有化部署数据保存本地授权信息加密存储镜像由Github Actions构建过程公开透明
* 支持SQLitePostgreSQL、MySQL数据库
![](./docs/images/intro/intro.svg)
>
> 流水线数量现已调整为无限制,欢迎大家使用
>
@@ -23,7 +26,7 @@ Certd 是一个免费全自动申请和自动部署更新SSL证书的管理系
> 关于证书续期:
>* 实际上没有办法不改变证书文件本身情况下直接续期或者续签。
>* 我们所说的续期,其实就是按照全套流程重新申请一份新证书,然后重新部署上去。
>* 免费证书过期时间90天以后可能还会缩短所以自动化部署必不可少
## 二、在线体验
@@ -62,7 +65,7 @@ https://certd.handfree.work/
-------> [点我查看详细使用步骤演示](./step.md) <--------
↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
更多教程请访问文档网站 [certd.docmirror.cn](https://certd.docmirror.cn/)
更多教程请访问官方文档 [certd.docmirror.cn](https://certd.docmirror.cn/guide/)
@@ -72,10 +75,10 @@ https://certd.handfree.work/
您可以根据实际情况从如下方式中选择一种方式进行私有化部署:
1. [宝塔面板方式部署](https://certd.docmirror.cn/guide/install/docker/)
2. [1Panel面板方式部署](https://certd.docmirror.cn/guide/install/1panel/)
3. [Docker方式部署](https://certd.docmirror.cn/guide/install/docker/)
4. [源码方式部署](https://certd.docmirror.cn/guide/install/source/)
1. [宝塔面板方式部署 推荐](https://certd.docmirror.cn/guide/install/docker/)
2. [1Panel面板方式部署 推荐](https://certd.docmirror.cn/guide/install/1panel/)
3. [Docker方式部署 推荐](https://certd.docmirror.cn/guide/install/docker/)
4. [源码方式部署 不建议](https://certd.docmirror.cn/guide/install/source/)
#### Docker镜像说明
* 国内镜像地址:
@@ -85,93 +88,36 @@ https://certd.handfree.work/
* `https://hub.docker.com/r/greper/certd`
* `greper/certd:latest`
* `greper/certd:armv7``greper/certd:[version]-armv7`
* GitHub Packages地址:
* `ghcr.io/certd/certd:latest`
* `ghcr.io/certd/certd:armv7``ghcr.io/certd/certd:[version]-armv7`
* 镜像构建通过`Actions`自动执行,过程公开透明,请放心使用
* [点我查看镜像构建日志](https://github.com/certd/certd/actions/workflows/build-image.yml)
![](./docs/images/action/action-build.jpg)
## 五、 升级
### docker-compose方式部署
#### 1. 如果使用固定版本号
1. 修改`docker-compose.yaml`中的镜像版本号
2. 运行`docker compose up -d` 即可
#### 2. 如果需要使用最新版本
```shell
#重新拉取镜像
docker pull registry.cn-shenzhen.aliyuncs.com/handsfree/certd:latest
# 重新启动容器
docker compose down
docker compose up -d
```
> 数据默认存在`/data/certd`目录下,不用担心数据丢失
### 自动升级(仅限尝鲜建议非生产使用)
```yaml
version: '3.3'
services:
certd:
image: registry.cn-shenzhen.aliyuncs.com/handsfree/certd:latest
container_name: certd
restart: unless-stopped
volumes:
- /data/certd:/app/data
ports:
- "7001:7001"
- "7002:7002"
environment:
- certd_system_resetAdminPasswd=false
labels:
com.centurylinklabs.watchtower.enable: "true"
certd-updater: # 添加 Watchtower 服务
image: containrrr/watchtower:latest
container_name: certd-updater
restart: unless-stopped
volumes:
- /var/run/docker.sock:/var/run/docker.sock
# 配置 自动更新
environment:
- WATCHTOWER_CLEANUP=true # 自动清理旧版本容器
- WATCHTOWER_INCLUDE_STOPPED=false # 不更新已停止的容器
- WATCHTOWER_LABEL_ENABLE=true # 根据容器标签进行更新
- WATCHTOWER_POLL_INTERVAL=300 # 每 5 分钟检查一次更新
```
### 其他部署方式升级方法
请参考 https://certd.docmirror.cn/guide/install/upgrade.html
> 注意:
> * 本应用存储的证书、授权信息等属于高度敏感数据,请做好安全防护
> * 请务必使用HTTPS协议访问本应用避免被中间人攻击
> * 请务必使用web应用防火墙防护本应用防止XSS、SQL注入等攻击
> * 请务必做好服务器本身的安全防护,防止数据库泄露
> * 请务必做好数据备份,避免数据丢失
### 更新日志:
[CHANGELOG](./CHANGELOG.md)
## 五、更多帮助
请访问官方文档:[https://certd.docmirror.cn/](https://certd.docmirror.cn/guide/)
* 升级方法:[升级方法](https://certd.docmirror.cn/guide/install/upgrade/)
* 常见问题:[忘记密码](https://certd.docmirror.cn/guide/use/forgotpasswd/)
* 多数据库:[多数据库配置](https://certd.docmirror.cn/guide/install/database/)
* 站点安全:[站点安全特性](https://certd.docmirror.cn/guide/feature/safe/)
* 更新日志:[CHANGELOG](./CHANGELOG.md)
## 六、一些说明
* 本项目ssl证书提供商为letencrypt/Google/ZeroSSL
* 申请过程遵循acme协议
* 证书续期:
* 实际上没有办法不改变证书文件本身情况下直接续期或者续签。
* 我们所说的续期,其实就是按照全套流程重新申请一份新证书,然后重新部署上去。
* 免费证书过期时间90天以后可能还会缩短所以自动化部署必不可少
* 设置每天自动运行当证书过期前35天会自动重新申请证书并部署
## 七、不同平台的设置说明
* 已迁移到新的文档网站,请到常见问题章节查看
* [最新文档站链接 https://certd.docmirror.cn](https://certd.docmirror.cn/)
## 八、问题处理
### 7.1 忘记管理员密码
[重置管理员密码方法](https://certd.docmirror.cn/guide/use/forgotpasswd/)
## 九、联系作者
## 六、联系作者
如有疑问欢迎加入群聊请备注certd
| 加群 | 微信群 | QQ群 |
@@ -185,7 +131,7 @@ services:
| 二维码 | <img height="230" src="./docs/guide/contact/images/me.png"> |
## 、捐赠
## 、捐赠
************************
支持开源,为爱发电,我已入驻爱发电
https://afdian.com/a/greper
@@ -194,8 +140,6 @@ https://afdian.com/a/greper
1. 可加入发电专属群,可以获得作者一对一技术支持
2. 您的需求我们将优先实现,并且将作为专业版功能提供
3. 一年期专业版激活码
4. 赠送国外免费服务器部署方案0成本使用Certd可能需要翻墙不过现在性能越来越差了
专业版特权对比
@@ -211,33 +155,26 @@ https://afdian.com/a/greper
************************
## 十一、贡献代码
## 、贡献代码
1. 本地开发 [贡献插件](https://certd.docmirror.cn/guide/development/)
1. 本地开发请参考 [贡献插件向导](https://certd.docmirror.cn/guide/development/)
2. 作为贡献者,代表您同意您贡献的代码如下许可:
1. 可以调整开源协议以使其更严格或更宽松。
2. 可以用于商业用途。
## 十二、 开源许可
## 、 开源许可
* 本项目遵循 GNU Affero General Public LicenseAGPL开源协议。
* 允许个人和公司内部自由使用、复制、修改和分发本项目,未获得商业授权情况下禁止任何形式的商业用途
* 未获得商业授权情况下禁止任何对logo、版权信息及授权许可相关代码的修改。
* 如需商业授权,请联系作者。
## 十三、我的其他项目求Star
## 十、我的其他项目求Star
| 项目名称 | stars | 项目描述 |
|---------------------------------------------------------|-------------------------------------------------------------------------------------------------------|-----------------------------------|
| [袖手AI](https://ai.handsfree.work/) | | 袖手GPT国内可用无需FQ每日免费额度 |
| [fast-crud](https://gitee.com/fast-crud/fast-crud/) | <img alt="GitHub stars" src="https://img.shields.io/github/stars/fast-crud/fast-crud?logo=github"/> | 基于vue3的crud快速开发框架 |
| [dev-sidecar](https://github.com/docmirror/dev-sidecar/) | <img alt="GitHub stars" src="https://img.shields.io/github/stars/docmirror/dev-sidecar?logo=github"/> | 直连访问github工具无需FQ解决github无法访问的问题 |
## 十四、更新日志
更新日志:[CHANGELOG](./CHANGELOG.md)

View File

@@ -1 +1 @@
1
2

View File

@@ -1 +1 @@
00:33
01:58

View File

@@ -1,156 +1,166 @@
import { defineConfig } from "vitepress";
import {defineConfig} from "vitepress";
// Import lightbox plugin
import lightbox from "vitepress-plugin-lightbox";
// https://vitepress.dev/reference/site-config
export default defineConfig({
title: "Certd",
titleTemplate: "开源SSL证书管理工具证书自动化申请部署让你的网站证书永不过期",
description: "Certd帮助文档,Certd是一款开源免费的全自动SSL证书管理工具证书自动化申请部署流水线自动证书申请、更新、续期通配符证书泛域名证书申请证书自动化部署到阿里云、腾讯云、主机、群晖、宝塔。",
markdown: {
config: (md) => {
// Use lightbox plugin
md.use(lightbox, {});
}
},
sitemap: {
hostname: 'https://certd.docmirror.cn'
},
head: [
// [
// 'meta',
// {
// name: 'viewport',
// content:
// 'width=device-width,initial-scale=1,minimfast-cum-scale=1.0,maximum-scale=1.0,user-scalable=no',
// },
// ],
["meta", {
name: "keywords",
content: "证书自动申请、证书自动更新、证书自动续期、证书自动续签、证书管理工具、Certd、SSL证书自动部署、证书自动化https证书pfx证书der证书TLS证书nginx证书自动续签自动部署,SSL平台证书管理平台证书流水线"
}],
// ["meta", { name: "google-site-verification",content: "V5XLTSnXoT15uQotwpxJoQolUo2d5UbSL-TacsyOsC0"}],
//<meta name="baidu-site-verification" content="codeva-MiWN8Y07Ua" />
// ["meta", {name: "baidu-site-verification",content: "codeva-MiWN8Y07Ua"}],
["link", { rel: "icon", href: "/static/logo/logo.svg" }]
],
themeConfig: {
logo: "/static/logo/logo.svg",
search: {
provider: "local",
options: {
detailedView: true,
translations: {
button: {
buttonText: "搜索文档",
buttonAriaLabel: "搜索文档"
},
modal: {
noResultsText: "无法找到相关结果",
resetButtonTitle: "清除查询条件",
footer: {
selectText: "选择",
closeText: "关闭",
navigateText: "切换"
title: "Certd",
titleTemplate: "开源SSL证书管理工具证书自动化申请部署让你的网站证书永不过期",
description: "Certd帮助文档,Certd是一款开源免费的全自动SSL证书管理工具证书自动化申请部署流水线自动证书申请、更新、续期通配符证书泛域名证书申请证书自动化部署到阿里云、腾讯云、主机、群晖、宝塔。",
markdown: {
config: (md) => {
// Use lightbox plugin
md.use(lightbox, {});
}
},
sitemap: {
hostname: 'https://certd.docmirror.cn'
},
head: [
// [
// 'meta',
// {
// name: 'viewport',
// content:
// 'width=device-width,initial-scale=1,minimfast-cum-scale=1.0,maximum-scale=1.0,user-scalable=no',
// },
// ],
["meta", {
name: "keywords",
content: "证书自动申请、证书自动更新、证书自动续期、证书自动续签、证书管理工具、Certd、SSL证书自动部署、证书自动化https证书pfx证书der证书TLS证书nginx证书自动续签自动部署,SSL平台证书管理平台证书流水线"
}],
// ["meta", { name: "google-site-verification",content: "V5XLTSnXoT15uQotwpxJoQolUo2d5UbSL-TacsyOsC0"}],
//<meta name="baidu-site-verification" content="codeva-MiWN8Y07Ua" />
// ["meta", {name: "baidu-site-verification",content: "codeva-MiWN8Y07Ua"}],
["link", {rel: "icon", href: "/static/logo/logo.svg"}]
],
themeConfig: {
logo: "/static/logo/logo.svg",
search: {
provider: "local",
options: {
detailedView: true,
translations: {
button: {
buttonText: "搜索文档",
buttonAriaLabel: "搜索文档"
},
modal: {
noResultsText: "无法找到相关结果",
resetButtonTitle: "清除查询条件",
footer: {
selectText: "选择",
closeText: "关闭",
navigateText: "切换"
}
}
}
}
}
}
}
},
// https://vitepress.dev/reference/default-theme-config
nav: [
{ text: "首页", link: "/" },
{ text: "指南", link: "/guide/" },
{ text: "商业版", link: "/comm/" },
{ text: "Demo体验", link: "https://certd.handfree.work" }
],
sidebar: {
"/guide/": [
{
text: "入门",
items: [
{ text: "简介", link: "/guide/" },
{ text: "快速开始", link: "/guide/start.md" },
{
text: "私有化部署",
items: [
{ text: "docker部署", link: "/guide/install/docker/" },
{ text: "宝塔面板部署", link: "/guide/install/baota/" },
{ text: "1Panel部署", link: "/guide/install/1panel/" },
{ text: "群晖部署", link: "/guide/use/synology/" },
{ text: "源码部署", link: "/guide/install/source/" }
]
},
{ text: "演示教程", link: "/guide/tutorial.md" },
{ text: "版本升级", link: "/guide/install/upgrade.md" }
]
},
{
text: "特性",
items: [
{ text: "CNAME代理校验", link: "/guide/feature/cname/index.md" },
{ text: "插件列表", link: "/guide/plugins.md" },
{ text: "多数据库支持", link: "/guide/install/database.md" },
{ text: "开放接口", link: "/guide/open/index.md" }
]
},
{
text: "常见问题",
items: [
{ text: "群晖证书部署", link: "/guide/use/synology/" },
{ text: "腾讯云密钥获取", link: "/guide/use/tencent/" },
{ text: "连接windows主机", link: "/guide/use/host/windows.md" },
{ text: "Google EAB获取", link: "/guide/use/google/" },
{ text: "阿里云相关", link: "/guide/use/aliyun/" },
{ text: "忘记密码", link: "/guide/use/forgotpasswd/" },
{ text: "数据备份", link: "/guide/use/backup/" },
{ text: "Certd本身的证书更新", link: "/guide/use/https/index.md" },
{ text: "js脚本插件使用", link: "/guide/use/custom-script/index.md" },
{ text: "邮箱配置", link: "/guide/use/email/index.md" },
{ text: "IPv6支持", link: "/guide/use/setting/ipv6.md" },
]
},
{
text: "其他",
items: [
{ text: "贡献代码", link: "/guide/development/index.md" },
{ text: "更新日志", link: "/guide/changelogs/CHANGELOG.md" },
{ text: "镜像说明", link: "/guide/image.md" },
{ text: "联系我们", link: "/guide/contact/" },
{ text: "捐赠", link: "/guide/donate/" },
{ text: "开源协议", link: "/guide/license/" },
{ text: "我的其他开源项目", link: "/guide/link/" },
// https://vitepress.dev/reference/default-theme-config
nav: [
{text: "首页", link: "/"},
{text: "指南", link: "/guide/"},
{text: "Demo体验", link: "https://certd.handfree.work"}
],
sidebar: {
"/guide/": [
{
text: "入门",
items: [
{text: "简介", link: "/guide/"},
{text: "快速开始", link: "/guide/start.md"},
{
text: "私有化部署",
items: [
{text: "docker部署", link: "/guide/install/docker/"},
{text: "宝塔面板部署", link: "/guide/install/baota/"},
{text: "1Panel部署", link: "/guide/install/1panel/"},
{text: "群晖部署", link: "/guide/use/synology/"},
{text: "源码部署", link: "/guide/install/source/"}
]
},
{text: "演示教程", link: "/guide/tutorial.md"},
{text: "版本升级", link: "/guide/install/upgrade.md"}
]
},
{
text: "特性",
items: [
{text: "CNAME代理校验", link: "/guide/feature/cname/index.md"},
{text: "插件列表", link: "/guide/plugins.md"},
{text: "多数据库支持", link: "/guide/install/database.md"},
{text: "开放接口", link: "/guide/open/index.md"},
{
text: "站点安全", items: [
{text: "安全特性", link: "/guide/feature/safe"},
{text: "站点隐藏", link: "/guide/feature/safe/hidden"},
{text: "安全生产建议", link: "/guide/feature/safe/suggest"},
]
},
]
}
],
"/deploy/":[
{
text: "部署任务",
items: [
{ text: "部署到ESXi", link: "/deploy/ESXi/index.md" },
]
}
],
"/comm/": [
{
text: "商业版",
items: [
{ text: "支付宝配置", link: "/comm/payments/alipay.md" },
{ text: "微信支付配置", link: "/comm/payments/wxpay.md" },
{ text: "彩虹易支付配置", link: "/comm/payments/yizhifu.md" },
]
}
]
,
},
]
},
{
text: "常见问题",
items: [
{text: "群晖证书部署", link: "/guide/use/synology/"},
{text: "腾讯云密钥获取", link: "/guide/use/tencent/"},
{text: "连接windows主机", link: "/guide/use/host/windows.md"},
{text: "Google EAB获取", link: "/guide/use/google/"},
{text: "阿里云相关", link: "/guide/use/aliyun/"},
{text: "忘记密码", link: "/guide/use/forgotpasswd/"},
{text: "数据备份", link: "/guide/use/backup/"},
{text: "Certd本身的证书更新", link: "/guide/use/https/index.md"},
{text: "js脚本插件使用", link: "/guide/use/custom-script/index.md"},
{text: "邮箱配置", link: "/guide/use/email/index.md"},
{text: "IPv6支持", link: "/guide/use/setting/ipv6.md"},
{text: "其他插件使用", link: "/deploy/"},
{text: "商业版说明", link: "/comm/"},
]
},
{
text: "其他",
items: [
{text: "贡献代码", link: "/guide/development/index.md"},
{text: "更新日志", link: "/guide/changelogs/CHANGELOG.md"},
{text: "镜像说明", link: "/guide/image.md"},
{text: "联系我们", link: "/guide/contact/"},
{text: "捐赠", link: "/guide/donate/"},
{text: "开源协议", link: "/guide/license/"},
{text: "我的其他开源项目", link: "/guide/link/"},
socialLinks: [
{ icon: "github", link: "https://github.com/certd/certd" }
],
footer: {
message: "Certd帮助文档 | <a href='https://beian.miit.gov.cn/' target='_blank'>粤ICP备14088435号</a> ",
copyright: "Copyright © 2021-present <a href='https://handfree.work/' target='_blank'>handfree.work</a> "
]
}
],
"/deploy/": [
{
text: "部署证书插件",
items: [
{text: "插件说明", link: "/deploy/index.md"},
{text: "部署到ESXi", link: "/deploy/ESXi/index.md"},
]
}
],
"/comm/": [
{
text: "商业版",
items: [
{text: "支付宝配置", link: "/comm/payments/alipay.md"},
{text: "微信支付配置", link: "/comm/payments/wxpay.md"},
{text: "彩虹易支付配置", link: "/comm/payments/yizhifu.md"},
]
}
]
,
},
socialLinks: [
{icon: "github", link: "https://github.com/certd/certd"}
],
footer: {
message: "Certd帮助文档 | <a href='https://beian.miit.gov.cn/' target='_blank'>粤ICP备14088435号</a> ",
copyright: "Copyright © 2021-present <a href='https://handfree.work/' target='_blank'>handfree.work</a> "
}
}
}
});

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

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

View File

@@ -3,6 +3,134 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.33.8](https://github.com/certd/certd/compare/v1.33.7...v1.33.8) (2025-04-26)
### Bug Fixes
* 服务器时间获取不准确的bug ([5d10cbf](https://github.com/certd/certd/commit/5d10cbf18daf94a90a7551641a3b13e3c5fec611))
* 修复复制流水线无效的bug ([3df20a9](https://github.com/certd/certd/commit/3df20a924f32970b052e2588ea20de095f0ea693))
* 修复http上传方式无法清除记录文件的bug ([72a7b51](https://github.com/certd/certd/commit/72a7b51d479602b2c54c6c3ac8d8a0dcb9664e73))
* 修复token过期后疯狂打印token过期信息的bug ([50a5fa1](https://github.com/certd/certd/commit/50a5fa15bb240a125bbc91d2ce1ff3c835888a77))
### Performance Improvements
* 从域名的soa获取主域名子域名托管无需额外配置 ([a586a92](https://github.com/certd/certd/commit/a586a92d5e32ea846ac37be52a7ad8c328d89966))
* 七牛oss支持删除过期备份 ([b7113bd](https://github.com/certd/certd/commit/b7113bda2378116d6c116dc583f563cce7cf9f00))
* 数据库备份支持oss ([308d460](https://github.com/certd/certd/commit/308d4600efe2002f199c33b4594d3071784e58ea))
* 支持阿里云中文域名申请 ([b3468cf](https://github.com/certd/certd/commit/b3468cf7f28228d7c9cf68de6b5a9bbeb67f2c6d))
* 支持反向代理增加contextPath路径 ([0088929](https://github.com/certd/certd/commit/0088929622160cc922995de9a563e8061686ff34))
* 支持中文域名 ([162ebfd](https://github.com/certd/certd/commit/162ebfd4e0c25727efb33952d3bbf7420a02e2c3))
## [1.33.7](https://github.com/certd/certd/compare/v1.33.6...v1.33.7) (2025-04-22)
### Performance Improvements
* 添加部署证书至火山 Live ([abea80e](https://github.com/certd/certd/commit/abea80e3ab9b1672aebe1c5d5e856693b29931a8))
* 优化首页插件列表展示 ([9b8f60b](https://github.com/certd/certd/commit/9b8f60b64b5f9a3db7dfa9b3dcbd9201984358d0))
* 证书申请支持51dns ([8638fc9](https://github.com/certd/certd/commit/8638fc91ff34fccaf12ff9874fd3fa9d2a8c18b7))
* 支持51dns ([96a0900](https://github.com/certd/certd/commit/96a0900edc95dcfd9acccf9d13592f12f5a09b3d))
* ssh PTY模式登录设置 ([8385bcc](https://github.com/certd/certd/commit/8385bcc2d7f2411a07748bb5c53f9eaf4d38d7cc))
* ssh伪终端模式优化windows下不开启 ([42dfe93](https://github.com/certd/certd/commit/42dfe936b773b7bdd82ca3378363252ffffd7b71))
## [1.33.6](https://github.com/certd/certd/compare/v1.33.5...v1.33.6) (2025-04-20)
### Bug Fixes
* 上传商用证书直接粘贴文本报错的问题修复无法上传ec加密证书的bug ([5750bb7](https://github.com/certd/certd/commit/5750bb706779da274d8e7a87e71416cb64d2df79))
* 修复下载证书时提示token已过期的问题 ([0e07ae6](https://github.com/certd/certd/commit/0e07ae6ce84dcb9279d3c44060d621566afa593c))
### Performance Improvements
* 更新license时同时绑定url ([78367af](https://github.com/certd/certd/commit/78367af8307f801e778c76d49f0918c21ffe032f))
* 切换到不同的分组后再打开创建对话框,会自动选择分组 ([893dcd4](https://github.com/certd/certd/commit/893dcd4f2487891199ed3e5a3d47a79a75efc942))
* 新增部署到火山引擎ALB/CLB、上传到证书中心 ([c9a3e3d](https://github.com/certd/certd/commit/c9a3e3d9d26f964c7af7b56667936f1414fbf42a))
* 优化/api缓存为0 ([dc05cd4](https://github.com/certd/certd/commit/dc05cd481f186b13375192be965000e6b4b429a5))
* 优化华为cdn插件引用ccm证书 ([b565b4b](https://github.com/certd/certd/commit/b565b4b3b919b71b98ea2517670bc1ef00e00dc9))
* 优化证书流水线创建,支持选择分组 ([d613aa8](https://github.com/certd/certd/commit/d613aa8f3e85d8dc475ef1b62d49394ce7fd7d24))
## [1.33.5](https://github.com/certd/certd/compare/v1.33.4...v1.33.5) (2025-04-17)
### Performance Improvements
* 登录支持双重认证 ([48aef25](https://github.com/certd/certd/commit/48aef25b3f6499d674ca4e4ef16f4c62399fb735))
* 多重认证登录 ([0f82cf4](https://github.com/certd/certd/commit/0f82cf409bc60706ab07e4ca4f272b9a1ca7eecb))
* 优化部署到华为云CDN支持先上传到ccm再使用证书id部署修复offline状态下导致部署报错的bug ([79df39a](https://github.com/certd/certd/commit/79df39acabab10ae7e1864dadcdc186bb007a3c5))
## [1.33.4](https://github.com/certd/certd/compare/v1.33.3...v1.33.4) (2025-04-15)
### Bug Fixes
* 补充类型断言 ([2143dff](https://github.com/certd/certd/commit/2143dff2ae96e6a78bef9f0498e36f8cd9e6941f))
* 修复腾讯云部署到任意资源插件,无法使用之前已上传的腾讯云证书问题 ([32c714d](https://github.com/certd/certd/commit/32c714d1b6e68c71a74a7452115040c87ac4bfdc))
### Performance Improvements
* 插件支持导入导出 ([cf8abb4](https://github.com/certd/certd/commit/cf8abb45282070c8ba91469f93fd379fabf1f74a))
* 支持上传证书到华为云CCM ([cfd3b66](https://github.com/certd/certd/commit/cfd3b66be9ebf53a26693057e70ed60c3f116be9))
## [1.33.3](https://github.com/certd/certd/compare/v1.33.2...v1.33.3) (2025-04-14)
### Bug Fixes
* 修复登录错误次数过多阻止再次登录逻辑 ([bf4d191](https://github.com/certd/certd/commit/bf4d191c8bd2f9209eb6768f662b9c77de99e998))
## [1.33.2](https://github.com/certd/certd/compare/v1.33.1...v1.33.2) (2025-04-12)
### Bug Fixes
* 修复某些情况下无法输出日志的bug ([70101bf](https://github.com/certd/certd/commit/70101bfa7ade65678d9202c804bbae2cb808b594))
### Performance Improvements
* 修复内置插件分页查询逻辑 ([a2710dd](https://github.com/certd/certd/commit/a2710ddc2525e4e637fd157f0180e6d3b801c8be))
## [1.33.1](https://github.com/certd/certd/compare/v1.33.0...v1.33.1) (2025-04-12)
### Bug Fixes
* 修复阿里云cdn证书部署失败问题增加certname参数传入 ([965dc2c](https://github.com/certd/certd/commit/965dc2cb476f690af716f291c6b20ba98be0c8f0))
* 修复ssh插件报length空指针的bug ([9c4cbe1](https://github.com/certd/certd/commit/9c4cbe17a22b548611cf1fbefecc83a421788e42))
### Performance Improvements
* 镜像支持armv7 ([f78cbed](https://github.com/certd/certd/commit/f78cbed4d817859721fdafe7d348864848d0dfbf))
# [1.33.0](https://github.com/certd/certd/compare/v1.32.0...v1.33.0) (2025-04-11)
### Bug Fixes
* 升级mysql驱动支持mysql8最新版本的认证 ([2f5ed3a](https://github.com/certd/certd/commit/2f5ed3aead97641f2c80d692a50226839016df0b))
* 修复eab授权没有email绑定的bug ([2f1683b](https://github.com/certd/certd/commit/2f1683b26acebbfb7d6e2d751435be04a4e7cab4))
### Features
* 支持在线自定义插件,无需源码开发 ([d0d9d68](https://github.com/certd/certd/commit/d0d9d68fe6740f6ff49fe40b7c9917c5a2e4b442))
* **lego:** support set key type ([f3bf4fa](https://github.com/certd/certd/commit/f3bf4faee0be5bdbfdbcf70a502849ed4c8ed4c4))
* release image to ghcr ([9b536af](https://github.com/certd/certd/commit/9b536af9e656dc89e2a87078c129cad6f591e467))
### Performance Improvements
* 修复tab页缓存问题 ([64e5449](https://github.com/certd/certd/commit/64e5449ab3c6b219b0e89eddad14bfb6b71a0650))
* 隐藏运行策略选项 ([2951df0](https://github.com/certd/certd/commit/2951df0cd94c23e2efee84ff1b843055aac56cae))
* 增加手动上传证书功能说明 ([5d083a1](https://github.com/certd/certd/commit/5d083a153637caddbc6f44e915d9fb2d1ae87b33))
# [1.32.0](https://github.com/certd/certd/compare/v1.31.11...v1.32.0) (2025-04-04)
### Bug Fixes
* 创建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

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

@@ -0,0 +1,25 @@
# 站点隐藏
* 一般来说Certd设置好之后很少需要访问。
* 所以我们`平时`可以把`站点访问关闭`,需要的时候再打开,减少站点被攻击的风险
## 1、开启站点隐藏
`系统管理->系统设置->安全设置->站点隐藏 `
![](./images/hidden1.png)
:::warning
注意保存好`解除地址``解除密码`
:::
## 2、临时关闭站点隐藏
访问上面的`解除地址`,输入`解除密码``临时解除`站点隐藏
![](./images/hidden2.png)
## 3、忘记解除地址和解除密码怎么办
登录服务器,在数据库平级的目录下创建`.unhidden`文件即可`临时解除`站点隐藏

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View File

@@ -0,0 +1,36 @@
# 站点安全特性
Certd 存储了证书以及授权等敏感数据,所以需要严格保障安全。
我们非常重视您的数据安全,提供了以下安全特性
## 1、 授权数据加密存储【默认开启】
* 所有的授权敏感字段会加密后存储
* 每个用户独立维护授权数据,连管理员都无权查看
![星号部分为加密数据](./images/access.png)
星号部分为加密数据
## 2、 密码防爆破【默认开启】
* 登录失败次数过多账号将被锁定最高24小时(重启服务可解除锁定)
* 用户登录密码加密hash后存储无法计算出密码明文
![](./images/login.png)
## 3、站点隐藏【建议开启】
* 一般来说Certd设置好之后后续很少需要访问修改。
* 所以我们平时可以把站点访问关闭,需要的时候再打开,减少站点被攻击的风险
* 请前往 `系统管理->系统设置->安全设置->开启站点隐藏`
* [站点隐藏设置说明](./hidden/)
![](./images/hidden.png)
## 4、登录双重验证
支持2FA双重认证
![](./images/2fa.png)
## 5、数据库自动备份【建议开启】
* [自动备份设置说明](../../use/backup/)
## 更多安全生产建议
[安全生产建议](./suggest.md)

View File

@@ -0,0 +1,10 @@
# 安全生产建议
尽管`Cert`本身实现了很多安全特性,但`外部环境的安全`仍需要您来确保。
`务必`遵循如下建议做好安全防护
*`务必`使用`HTTPS协议`访问本应用,避免被中间人攻击
*`务必`使用`web应用防火墙`防护本应用防止XSS、SQL注入等攻击
*`务必`做好`服务器本身`的安全防护,防止数据库泄露
*`务必`做好[`数据备份`](../../use/backup/),避免数据丢失
* 建议开启[`站点隐藏`](./hidden/)功能

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

@@ -17,6 +17,8 @@ Certd 是一款开源、免费、全自动申请和部署更新SSL证书的工
* 支持SQLite、Postgresql、MySQL数据库
![](../images/intro/intro.svg)
## 二、一些说明
* 本项目申请证书过程遵循acme协议
* 需要验证域名所有权,一般有两种方式

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

View File

@@ -13,7 +13,7 @@
#### 2.1 应用商店一键部署【推荐】
* 在应用商店中找到`certd`(要先点右上角更新应用)
*宝塔Docker应用商店中找到`certd`(要先点右上角更新应用)
* 点击安装,配置域名等基本信息即可完成安装
> 需要宝塔9.2.0及以上版本才支持
@@ -70,3 +70,12 @@ admin/123456
## 五、备份恢复
将备份的`db.sqlite`及同目录下的其他文件一起覆盖到原来的位置重启certd即可
## 六、宝塔部署相关问题排查
### 1. 无法访问Certd
1. 确认服务器的安全规则,是否放开了对应端口
2. 确认宝塔防火墙是否放开对应端口
3. 尝试将Certd容器加入宝塔的`bridge`网络
![](./images/network.png)

View File

@@ -55,6 +55,11 @@ https://your_server_ip:7002
## 二、升级
::: warning
如果您是第一次升级certd版本切记切记先备份一下数据
:::
### 如果使用固定版本号
1. 修改`docker-compose.yaml`中的镜像版本号
2. 运行`docker compose up -d` 即可

View File

@@ -44,6 +44,11 @@ kill -9 $(lsof -t -i:7001)
./start.sh
```
::: warning
升级certd版本前切记切记先备份一下数据
:::
## 三、数据备份
> 数据默认保存在 `./packages/ui/certd-server/data` 目录下
> 建议配置一条[数据库备份流水线](../../use/backup/) 自动备份

View File

@@ -8,5 +8,9 @@
3. [1Panel面板方式部署升级](./1panel/#三、升级)
4. [源码方式部署](./source/#二、升级)
::: warning
如果您是第一次升级certd版本切记切记先备份一下数据
:::
## 升级日志
[CHANGELOG](../changelogs/CHANGELOG.md)

View File

@@ -1,5 +1,6 @@
# 数据库自动备份
# 数据库备份
* 两种备份方法: 1、手动备份 2、自动备份
* 本文仅限sqlite数据库。
## 一、手动备份
数据库文件根据不同的部署方式保存的位置不一样,您可以手动复制出来进行备份

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 60 KiB

View File

@@ -9,5 +9,5 @@
}
},
"npmClient": "pnpm",
"version": "1.32.0"
"version": "1.34.0"
}

View File

@@ -3,6 +3,53 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [1.34.0](https://github.com/publishlab/node-acme-client/compare/v1.33.8...v1.34.0) (2025-04-28)
**Note:** Version bump only for package @certd/acme-client
## [1.33.8](https://github.com/publishlab/node-acme-client/compare/v1.33.7...v1.33.8) (2025-04-26)
### Bug Fixes
* 修复http上传方式无法清除记录文件的bug ([72a7b51](https://github.com/publishlab/node-acme-client/commit/72a7b51d479602b2c54c6c3ac8d8a0dcb9664e73))
### Performance Improvements
* 从域名的soa获取主域名子域名托管无需额外配置 ([a586a92](https://github.com/publishlab/node-acme-client/commit/a586a92d5e32ea846ac37be52a7ad8c328d89966))
* 七牛oss支持删除过期备份 ([b7113bd](https://github.com/publishlab/node-acme-client/commit/b7113bda2378116d6c116dc583f563cce7cf9f00))
## [1.33.7](https://github.com/publishlab/node-acme-client/compare/v1.33.6...v1.33.7) (2025-04-22)
**Note:** Version bump only for package @certd/acme-client
## [1.33.6](https://github.com/publishlab/node-acme-client/compare/v1.33.5...v1.33.6) (2025-04-20)
**Note:** Version bump only for package @certd/acme-client
## [1.33.5](https://github.com/publishlab/node-acme-client/compare/v1.33.4...v1.33.5) (2025-04-17)
**Note:** Version bump only for package @certd/acme-client
## [1.33.4](https://github.com/publishlab/node-acme-client/compare/v1.33.3...v1.33.4) (2025-04-15)
**Note:** Version bump only for package @certd/acme-client
## [1.33.3](https://github.com/publishlab/node-acme-client/compare/v1.33.2...v1.33.3) (2025-04-14)
**Note:** Version bump only for package @certd/acme-client
## [1.33.2](https://github.com/publishlab/node-acme-client/compare/v1.33.1...v1.33.2) (2025-04-12)
**Note:** Version bump only for package @certd/acme-client
## [1.33.1](https://github.com/publishlab/node-acme-client/compare/v1.33.0...v1.33.1) (2025-04-12)
**Note:** Version bump only for package @certd/acme-client
# [1.33.0](https://github.com/publishlab/node-acme-client/compare/v1.32.0...v1.33.0) (2025-04-11)
**Note:** Version bump only for package @certd/acme-client
# [1.32.0](https://github.com/publishlab/node-acme-client/compare/v1.31.11...v1.32.0) (2025-04-04)
### Bug Fixes

View File

@@ -3,7 +3,7 @@
"description": "Simple and unopinionated ACME client",
"private": false,
"author": "nmorsman",
"version": "1.32.0",
"version": "1.34.0",
"type": "module",
"module": "scr/index.js",
"main": "src/index.js",
@@ -18,7 +18,7 @@
"types"
],
"dependencies": {
"@certd/basic": "^1.32.0",
"@certd/basic": "^1.34.0",
"@peculiar/x509": "^1.11.0",
"asn1js": "^3.0.5",
"axios": "^1.7.2",
@@ -26,7 +26,8 @@
"http-proxy-agent": "^7.0.2",
"https-proxy-agent": "^7.0.5",
"lodash-es": "^4.17.21",
"node-forge": "^1.3.1"
"node-forge": "^1.3.1",
"punycode": "^2.3.1"
},
"devDependencies": {
"@types/node": "^20.14.10",
@@ -67,5 +68,5 @@
"bugs": {
"url": "https://github.com/publishlab/node-acme-client/issues"
},
"gitHead": "8374c3941a9d1398989b8f38fd4bfa2a2f29937b"
"gitHead": "9b420ad33ff4c36fc99d643c18be9ec7e29f220d"
}

View File

@@ -117,12 +117,12 @@ export default async (client, userOpts) => {
log(`[auto] [${d}] Trigger challengeCreateFn()`);
try {
const { recordReq, recordRes, dnsProvider, challenge, keyAuthorization } = await opts.challengeCreateFn(authz, keyAuthorizationGetter);
const { recordReq, recordRes, dnsProvider, challenge, keyAuthorization ,httpUploader} = 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);
await opts.challengeRemoveFn(authz, challenge, keyAuthorization, recordReq, recordRes, dnsProvider,httpUploader);
} catch (e) {
log(`[auto] [${d}] challengeRemoveFn threw error: ${e.message}`);
}

View File

@@ -46,3 +46,5 @@ export * from './axios.js'
export * from './logger.js'
export * from './verify.js'
export * from './error.js'
export * from './util.js'

View File

@@ -340,5 +340,6 @@ export {
formatResponseError,
getAuthoritativeDnsResolver,
retrieveTlsAlpnCertificate,
resolveDomainBySoaRecord
};

View File

@@ -59,7 +59,7 @@ export interface ClientExternalAccountBindingOptions {
export interface ClientAutoOptions {
csr: CsrBuffer | CsrString;
challengeCreateFn: (authz: Authorization, keyAuthorization: (challenge:rfc8555.Challenge)=>Promise<string>) => Promise<{recordReq?:any,recordRes?:any,dnsProvider?:any,challenge: rfc8555.Challenge,keyAuthorization:string}>;
challengeRemoveFn: (authz: Authorization, challenge: rfc8555.Challenge, keyAuthorization: string,recordReq:any, recordRes:any,dnsProvider:any) => Promise<any>;
challengeRemoveFn: (authz: Authorization, challenge: rfc8555.Challenge, keyAuthorization: string,recordReq:any, recordRes:any,dnsProvider:any,httpUploader:any) => Promise<any>;
email?: string;
termsOfServiceAgreed?: boolean;
skipChallengeVerification?: boolean;
@@ -204,4 +204,6 @@ export function setLogger(fn: (message: any, ...args: any[]) => void): void;
export function walkTxtRecord(record: any): Promise<string[]>;
export const CancelError: typeof CancelError;
export const CancelError: typeof CancelError;
export function resolveDomainBySoaRecord(domain: string): Promise<string>;

View File

@@ -1,137 +0,0 @@
"use strict";
/**
* acme-client type definition tests
*/
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (g && (g = 0, op[0] && (_ = 0)), _) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
Object.defineProperty(exports, "__esModule", { value: true });
var acme = require("acme-client");
(function () { return __awaiter(void 0, void 0, void 0, function () {
var accountKey, client, order, authorizations, authorization, challenge, _a, certKey, certCsr;
return __generator(this, function (_b) {
switch (_b.label) {
case 0: return [4 /*yield*/, acme.crypto.createPrivateKey()];
case 1:
accountKey = _b.sent();
client = new acme.Client({
accountKey: accountKey,
directoryUrl: acme.directory.letsencrypt.staging
});
/* Account */
return [4 /*yield*/, client.createAccount({
termsOfServiceAgreed: true,
contact: ['mailto:test@example.com']
})];
case 2:
/* Account */
_b.sent();
return [4 /*yield*/, client.createOrder({
identifiers: [
{ type: 'dns', value: 'example.com' },
{ type: 'dns', value: '*.example.com' },
]
})];
case 3:
order = _b.sent();
return [4 /*yield*/, client.getOrder(order)];
case 4:
_b.sent();
return [4 /*yield*/, client.getAuthorizations(order)];
case 5:
authorizations = _b.sent();
authorization = authorizations[0];
challenge = authorization.challenges[0];
return [4 /*yield*/, client.getChallengeKeyAuthorization(challenge)];
case 6:
_b.sent();
return [4 /*yield*/, client.verifyChallenge(authorization, challenge)];
case 7:
_b.sent();
return [4 /*yield*/, client.completeChallenge(challenge)];
case 8:
_b.sent();
return [4 /*yield*/, client.waitForValidStatus(challenge)];
case 9:
_b.sent();
return [4 /*yield*/, acme.crypto.createCsr({
commonName: 'example.com',
altNames: ['example.com', '*.example.com']
})];
case 10:
_a = _b.sent(), certKey = _a[0], certCsr = _a[1];
return [4 /*yield*/, client.finalizeOrder(order, certCsr)];
case 11:
_b.sent();
return [4 /*yield*/, client.getCertificate(order)];
case 12:
_b.sent();
return [4 /*yield*/, client.getCertificate(order, 'DST Root CA X3')];
case 13:
_b.sent();
/* Auto */
return [4 /*yield*/, client.auto({
csr: certCsr,
challengeCreateFn: function (authz, challenge, keyAuthorization) { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
return [2 /*return*/];
}); }); },
challengeRemoveFn: function (authz, challenge, keyAuthorization) { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
return [2 /*return*/];
}); }); }
})];
case 14:
/* Auto */
_b.sent();
return [4 /*yield*/, client.auto({
csr: certCsr,
email: 'test@example.com',
termsOfServiceAgreed: false,
skipChallengeVerification: false,
challengePriority: ['http-01', 'dns-01'],
preferredChain: 'DST Root CA X3',
challengeCreateFn: function (authz, challenge, keyAuthorization) { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
return [2 /*return*/];
}); }); },
challengeRemoveFn: function (authz, challenge, keyAuthorization) { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
return [2 /*return*/];
}); }); }
})];
case 15:
_b.sent();
return [2 /*return*/];
}
});
}); })();

View File

@@ -3,6 +3,52 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [1.34.0](https://github.com/certd/certd/compare/v1.33.8...v1.34.0) (2025-04-28)
**Note:** Version bump only for package @certd/basic
## [1.33.8](https://github.com/certd/certd/compare/v1.33.7...v1.33.8) (2025-04-26)
**Note:** Version bump only for package @certd/basic
## [1.33.7](https://github.com/certd/certd/compare/v1.33.6...v1.33.7) (2025-04-22)
### Performance Improvements
* 支持51dns ([96a0900](https://github.com/certd/certd/commit/96a0900edc95dcfd9acccf9d13592f12f5a09b3d))
## [1.33.6](https://github.com/certd/certd/compare/v1.33.5...v1.33.6) (2025-04-20)
**Note:** Version bump only for package @certd/basic
## [1.33.5](https://github.com/certd/certd/compare/v1.33.4...v1.33.5) (2025-04-17)
### Performance Improvements
* 多重认证登录 ([0f82cf4](https://github.com/certd/certd/commit/0f82cf409bc60706ab07e4ca4f272b9a1ca7eecb))
## [1.33.4](https://github.com/certd/certd/compare/v1.33.3...v1.33.4) (2025-04-15)
**Note:** Version bump only for package @certd/basic
## [1.33.3](https://github.com/certd/certd/compare/v1.33.2...v1.33.3) (2025-04-14)
**Note:** Version bump only for package @certd/basic
## [1.33.2](https://github.com/certd/certd/compare/v1.33.1...v1.33.2) (2025-04-12)
### Bug Fixes
* 修复某些情况下无法输出日志的bug ([70101bf](https://github.com/certd/certd/commit/70101bfa7ade65678d9202c804bbae2cb808b594))
## [1.33.1](https://github.com/certd/certd/compare/v1.33.0...v1.33.1) (2025-04-12)
**Note:** Version bump only for package @certd/basic
# [1.33.0](https://github.com/certd/certd/compare/v1.32.0...v1.33.0) (2025-04-11)
**Note:** Version bump only for package @certd/basic
# [1.32.0](https://github.com/certd/certd/compare/v1.31.11...v1.32.0) (2025-04-04)
**Note:** Version bump only for package @certd/basic

View File

@@ -1 +1 @@
01:33
17:24

View File

@@ -1,7 +1,7 @@
{
"name": "@certd/basic",
"private": false,
"version": "1.32.0",
"version": "1.34.0",
"type": "module",
"main": "./dist/index.js",
"module": "./dist/index.js",
@@ -44,5 +44,5 @@
"tslib": "^2.8.1",
"typescript": "^5.4.2"
},
"gitHead": "8374c3941a9d1398989b8f38fd4bfa2a2f29937b"
"gitHead": "9b420ad33ff4c36fc99d643c18be9ec7e29f220d"
}

View File

@@ -1,18 +1,18 @@
import crypto, { BinaryToTextEncoding } from 'crypto';
import crypto, { BinaryToTextEncoding } from "crypto";
function md5(data: string, digest: BinaryToTextEncoding = 'hex') {
return crypto.createHash('md5').update(data).digest(digest);
function md5(data: string, digest: BinaryToTextEncoding = "hex") {
return crypto.createHash("md5").update(data).digest(digest);
}
function sha256(data: string, digest: BinaryToTextEncoding = 'hex') {
return crypto.createHash('sha256').update(data).digest(digest);
function sha256(data: string, digest: BinaryToTextEncoding = "hex") {
return crypto.createHash("sha256").update(data).digest(digest);
}
function hmacSha256(data: string, digest: BinaryToTextEncoding = 'base64') {
return crypto.createHmac('sha256', data).update(Buffer.alloc(0)).digest(digest);
function hmacSha256(data: string, digest: BinaryToTextEncoding = "base64") {
return crypto.createHmac("sha256", data).update(Buffer.alloc(0)).digest(digest);
}
function base64(data: string) {
return Buffer.from(data).toString('base64');
return Buffer.from(data).toString("base64");
}
export const hashUtils = {
md5,

View File

@@ -1,4 +1,4 @@
import { customAlphabet } from "nanoid";
export const randomNumber = customAlphabet("1234567890", 4);
export const simpleNanoId = customAlphabet("1234567890abcdefghijklmopqrstuvwxyz", 12);
export const simpleNanoId = customAlphabet("1234567890abcdefghijklmopqrstuvwxyzABCDEFGHIJKLMOPQRSTUVWXYZ", 12);

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

@@ -1,13 +1,13 @@
import axios, { AxiosHeaders, AxiosRequestConfig } from 'axios';
import { ILogger, logger } from './util.log.js';
import { Logger } from 'log4js';
import { HttpProxyAgent } from 'http-proxy-agent';
import { HttpsProxyAgent } from 'https-proxy-agent';
import nodeHttp from 'http';
import * as https from 'node:https';
import { merge } from 'lodash-es';
import { safePromise } from './util.promise.js';
import fs from 'fs';
import axios, { AxiosHeaders, AxiosRequestConfig } from "axios";
import { ILogger, logger } from "./util.log.js";
import { Logger } from "log4js";
import { HttpProxyAgent } from "http-proxy-agent";
import { HttpsProxyAgent } from "https-proxy-agent";
import nodeHttp from "http";
import * as https from "node:https";
import { merge } from "lodash-es";
import { safePromise } from "./util.promise.js";
import fs from "fs";
export class HttpError extends Error {
status?: number;
statusText?: string;
@@ -22,10 +22,10 @@ export class HttpError extends Error {
super(error.message || error.response?.statusText);
const message = error?.message;
if (message && typeof message === 'string') {
if (message.indexOf && message.indexOf('ssl3_get_record:wrong version number') >= 0) {
if (message && typeof message === "string") {
if (message.indexOf && message.indexOf("ssl3_get_record:wrong version number") >= 0) {
this.message = `${message}(http协议错误服务端要求http协议请检查是否使用了https请求)`;
} else if (message.indexOf('getaddrinfo EAI_AGAIN') >= 0) {
} else if (message.indexOf("getaddrinfo EAI_AGAIN") >= 0) {
this.message = `${message}(无法解析域名请检查网络连接或dns配置更换docker-compose.yaml中dns配置)`;
}
}
@@ -47,7 +47,7 @@ export class HttpError extends Error {
};
let url = error.config?.url;
if (error.config?.baseURL) {
url = (error.config?.baseURL || '') + url;
url = (error.config?.baseURL || "") + url;
}
if (url) {
this.message = `${this.message}${url}`;
@@ -73,7 +73,7 @@ export const HttpCommonError = HttpError;
let defaultAgents = createAgent();
export function setGlobalProxy(opts: { httpProxy?: string; httpsProxy?: string }) {
logger.info('setGlobalProxy:', opts);
logger.info("setGlobalProxy:", opts);
defaultAgents = createAgent(opts);
}
@@ -102,12 +102,12 @@ export function createAxiosService({ logger }: { logger: Logger }) {
if (config.skipSslVerify || config.httpProxy) {
let rejectUnauthorized = true;
if (config.skipSslVerify) {
logger.info('跳过SSL验证');
logger.info("跳过SSL验证");
rejectUnauthorized = false;
}
const proxy: any = {};
if (config.httpProxy) {
logger.info('使用自定义http代理:', config.httpProxy);
logger.info("使用自定义http代理:", config.httpProxy);
proxy.httpProxy = config.httpProxy;
proxy.httpsProxy = config.httpProxy;
}
@@ -128,7 +128,7 @@ export function createAxiosService({ logger }: { logger: Logger }) {
},
(error: Error) => {
// 发送失败
logger.error('接口请求失败:', error);
logger.error("接口请求失败:", error);
return Promise.reject(error);
}
);
@@ -143,7 +143,7 @@ export function createAxiosService({ logger }: { logger: Logger }) {
logger.info(`http response : status=${response?.status},data=${resData}`);
} else {
logger.info('http response status:', response?.status);
logger.info("http response status:", response?.status);
}
if (response?.config?.returnResponse) {
return response;
@@ -154,53 +154,51 @@ export function createAxiosService({ logger }: { logger: Logger }) {
const status = error.response?.status;
switch (status) {
case 400:
error.message = '请求错误';
error.message = "请求错误";
break;
case 401:
error.message = '认证/登录失败';
error.message = "认证/登录失败";
break;
case 403:
error.message = '拒绝访问';
error.message = "拒绝访问";
break;
case 404:
error.message = `请求地址出错`;
break;
case 408:
error.message = '请求超时';
error.message = "请求超时";
break;
case 500:
error.message = '服务器内部错误';
error.message = "服务器内部错误";
break;
case 501:
error.message = '服务未实现';
error.message = "服务未实现";
break;
case 502:
error.message = '网关错误';
error.message = "网关错误";
break;
case 503:
error.message = '服务不可用';
error.message = "服务不可用";
break;
case 504:
error.message = '网关超时';
error.message = "网关超时";
break;
case 505:
error.message = 'HTTP版本不受支持';
error.message = "HTTP版本不受支持";
break;
default:
break;
}
logger.error(
`请求出错status:${error.response?.status},statusText:${error.response?.statusText},url:${error.config?.url},method:${error.config?.method}`
);
logger.error('返回数据:', JSON.stringify(error.response?.data));
logger.error(`请求出错status:${error.response?.status},statusText:${error.response?.statusText},url:${error.config?.url},method:${error.config?.method}`);
logger.error("返回数据:", JSON.stringify(error.response?.data));
if (error.response?.data) {
const message = error.response.data.message || error.response.data.msg || error.response.data.error;
if (typeof message === 'string') {
if (typeof message === "string") {
error.message = message;
}
}
if (error instanceof AggregateError) {
logger.error('AggregateError', error);
logger.error("AggregateError", error);
}
const err = new HttpError(error);
return Promise.reject(err);
@@ -244,24 +242,24 @@ export function createAgent(opts: CreateAgentOptions = {}) {
if (httpProxy) {
process.env.HTTP_PROXY = httpProxy;
process.env.http_proxy = httpProxy;
logger.info('use httpProxy:', httpProxy);
logger.info("use httpProxy:", httpProxy);
httpAgent = new HttpProxyAgent(httpProxy, opts as any);
merge(httpAgent.options, opts);
} else {
process.env.HTTP_PROXY = '';
process.env.http_proxy = '';
process.env.HTTP_PROXY = "";
process.env.http_proxy = "";
httpAgent = new nodeHttp.Agent(opts);
}
const httpsProxy = opts.httpsProxy;
if (httpsProxy) {
process.env.HTTPS_PROXY = httpsProxy;
process.env.https_proxy = httpsProxy;
logger.info('use httpsProxy:', httpsProxy);
logger.info("use httpsProxy:", httpsProxy);
httpsAgent = new HttpsProxyAgent(httpsProxy, opts as any);
merge(httpsAgent.options, opts);
} else {
process.env.HTTPS_PROXY = '';
process.env.https_proxy = '';
process.env.HTTPS_PROXY = "";
process.env.https_proxy = "";
httpsAgent = new https.Agent(opts);
}
return {
@@ -276,27 +274,27 @@ export async function download(req: { http: HttpClient; config: HttpRequestConfi
http
.request({
logRes: false,
responseType: 'stream',
responseType: "stream",
...config,
})
.then(res => {
const writer = fs.createWriteStream(savePath);
res.pipe(writer);
writer.on('close', () => {
logger.info('文件下载成功');
writer.on("close", () => {
logger.info("文件下载成功");
resolve(true);
});
//error
writer.on('error', err => {
logger.error('下载失败', err);
writer.on("error", err => {
logger.error("下载失败", err);
reject(err);
});
//进度条打印
const totalLength = res.headers['content-length'];
const totalLength = res.headers["content-length"];
let currentLength = 0;
// 每5%打印一次
const step = (totalLength / 100) * 5;
res.on('data', (chunk: any) => {
res.on("data", (chunk: any) => {
currentLength += chunk.length;
if (currentLength % step < chunk.length) {
const percent = ((currentLength / totalLength) * 100).toFixed(2);
@@ -305,19 +303,19 @@ export async function download(req: { http: HttpClient; config: HttpRequestConfi
});
})
.catch(err => {
logger.info('下载失败', err);
logger.info("下载失败", err);
reject(err);
});
});
}
export function getCookie(response: any, name: string) {
const cookies = response.headers['set-cookie'];
const cookies = response.headers["set-cookie"];
//根据name 返回对应的cookie
const found = cookies.find((cookie: any) => cookie.includes(name));
if (!found) {
return null;
}
const cookie = found.split(';')[0];
return cookie.substring(cookie.indexOf('=') + 1);
const cookie = found.split(";")[0];
return cookie.substring(cookie.indexOf("=") + 1);
}

View File

@@ -3,6 +3,50 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [1.34.0](https://github.com/certd/certd/compare/v1.33.8...v1.34.0) (2025-04-28)
**Note:** Version bump only for package @certd/pipeline
## [1.33.8](https://github.com/certd/certd/compare/v1.33.7...v1.33.8) (2025-04-26)
**Note:** Version bump only for package @certd/pipeline
## [1.33.7](https://github.com/certd/certd/compare/v1.33.6...v1.33.7) (2025-04-22)
**Note:** Version bump only for package @certd/pipeline
## [1.33.6](https://github.com/certd/certd/compare/v1.33.5...v1.33.6) (2025-04-20)
**Note:** Version bump only for package @certd/pipeline
## [1.33.5](https://github.com/certd/certd/compare/v1.33.4...v1.33.5) (2025-04-17)
**Note:** Version bump only for package @certd/pipeline
## [1.33.4](https://github.com/certd/certd/compare/v1.33.3...v1.33.4) (2025-04-15)
**Note:** Version bump only for package @certd/pipeline
## [1.33.3](https://github.com/certd/certd/compare/v1.33.2...v1.33.3) (2025-04-14)
**Note:** Version bump only for package @certd/pipeline
## [1.33.2](https://github.com/certd/certd/compare/v1.33.1...v1.33.2) (2025-04-12)
**Note:** Version bump only for package @certd/pipeline
## [1.33.1](https://github.com/certd/certd/compare/v1.33.0...v1.33.1) (2025-04-12)
### Bug Fixes
* 修复ssh插件报length空指针的bug ([9c4cbe1](https://github.com/certd/certd/commit/9c4cbe17a22b548611cf1fbefecc83a421788e42))
# [1.33.0](https://github.com/certd/certd/compare/v1.32.0...v1.33.0) (2025-04-11)
### Performance Improvements
* 隐藏运行策略选项 ([2951df0](https://github.com/certd/certd/commit/2951df0cd94c23e2efee84ff1b843055aac56cae))
# [1.32.0](https://github.com/certd/certd/compare/v1.31.11...v1.32.0) (2025-04-04)
**Note:** Version bump only for package @certd/pipeline

View File

@@ -1,7 +1,7 @@
{
"name": "@certd/pipeline",
"private": false,
"version": "1.32.0",
"version": "1.34.0",
"type": "module",
"main": "./dist/index.js",
"module": "./dist/index.js",
@@ -16,8 +16,8 @@
"test": "mocha --loader=ts-node/esm"
},
"dependencies": {
"@certd/basic": "^1.32.0",
"@certd/plus-core": "^1.32.0",
"@certd/basic": "^1.34.0",
"@certd/plus-core": "^1.34.0",
"dayjs": "^1.11.7",
"lodash-es": "^4.17.21",
"reflect-metadata": "^0.1.13"
@@ -43,5 +43,5 @@
"tslib": "^2.8.1",
"typescript": "^5.4.2"
},
"gitHead": "8374c3941a9d1398989b8f38fd4bfa2a2f29937b"
"gitHead": "9b420ad33ff4c36fc99d643c18be9ec7e29f220d"
}

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,46 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [1.34.0](https://github.com/certd/certd/compare/v1.33.8...v1.34.0) (2025-04-28)
**Note:** Version bump only for package @certd/lib-huawei
## [1.33.8](https://github.com/certd/certd/compare/v1.33.7...v1.33.8) (2025-04-26)
**Note:** Version bump only for package @certd/lib-huawei
## [1.33.7](https://github.com/certd/certd/compare/v1.33.6...v1.33.7) (2025-04-22)
**Note:** Version bump only for package @certd/lib-huawei
## [1.33.6](https://github.com/certd/certd/compare/v1.33.5...v1.33.6) (2025-04-20)
**Note:** Version bump only for package @certd/lib-huawei
## [1.33.5](https://github.com/certd/certd/compare/v1.33.4...v1.33.5) (2025-04-17)
**Note:** Version bump only for package @certd/lib-huawei
## [1.33.4](https://github.com/certd/certd/compare/v1.33.3...v1.33.4) (2025-04-15)
**Note:** Version bump only for package @certd/lib-huawei
## [1.33.3](https://github.com/certd/certd/compare/v1.33.2...v1.33.3) (2025-04-14)
**Note:** Version bump only for package @certd/lib-huawei
## [1.33.2](https://github.com/certd/certd/compare/v1.33.1...v1.33.2) (2025-04-12)
**Note:** Version bump only for package @certd/lib-huawei
## [1.33.1](https://github.com/certd/certd/compare/v1.33.0...v1.33.1) (2025-04-12)
**Note:** Version bump only for package @certd/lib-huawei
# [1.33.0](https://github.com/certd/certd/compare/v1.32.0...v1.33.0) (2025-04-11)
**Note:** Version bump only for package @certd/lib-huawei
# [1.32.0](https://github.com/certd/certd/compare/v1.31.11...v1.32.0) (2025-04-04)
**Note:** Version bump only for package @certd/lib-huawei

View File

@@ -1,7 +1,7 @@
{
"name": "@certd/lib-huawei",
"private": false,
"version": "1.32.0",
"version": "1.34.0",
"main": "./dist/bundle.js",
"module": "./dist/bundle.js",
"types": "./dist/d/index.d.ts",
@@ -23,5 +23,5 @@
"prettier": "^2.8.8",
"tslib": "^2.8.1"
},
"gitHead": "8374c3941a9d1398989b8f38fd4bfa2a2f29937b"
"gitHead": "9b420ad33ff4c36fc99d643c18be9ec7e29f220d"
}

View File

@@ -3,6 +3,48 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [1.34.0](https://github.com/certd/certd/compare/v1.33.8...v1.34.0) (2025-04-28)
**Note:** Version bump only for package @certd/lib-iframe
## [1.33.8](https://github.com/certd/certd/compare/v1.33.7...v1.33.8) (2025-04-26)
**Note:** Version bump only for package @certd/lib-iframe
## [1.33.7](https://github.com/certd/certd/compare/v1.33.6...v1.33.7) (2025-04-22)
**Note:** Version bump only for package @certd/lib-iframe
## [1.33.6](https://github.com/certd/certd/compare/v1.33.5...v1.33.6) (2025-04-20)
### Performance Improvements
* 更新license时同时绑定url ([78367af](https://github.com/certd/certd/commit/78367af8307f801e778c76d49f0918c21ffe032f))
## [1.33.5](https://github.com/certd/certd/compare/v1.33.4...v1.33.5) (2025-04-17)
**Note:** Version bump only for package @certd/lib-iframe
## [1.33.4](https://github.com/certd/certd/compare/v1.33.3...v1.33.4) (2025-04-15)
**Note:** Version bump only for package @certd/lib-iframe
## [1.33.3](https://github.com/certd/certd/compare/v1.33.2...v1.33.3) (2025-04-14)
**Note:** Version bump only for package @certd/lib-iframe
## [1.33.2](https://github.com/certd/certd/compare/v1.33.1...v1.33.2) (2025-04-12)
**Note:** Version bump only for package @certd/lib-iframe
## [1.33.1](https://github.com/certd/certd/compare/v1.33.0...v1.33.1) (2025-04-12)
**Note:** Version bump only for package @certd/lib-iframe
# [1.33.0](https://github.com/certd/certd/compare/v1.32.0...v1.33.0) (2025-04-11)
**Note:** Version bump only for package @certd/lib-iframe
# [1.32.0](https://github.com/certd/certd/compare/v1.31.11...v1.32.0) (2025-04-04)
**Note:** Version bump only for package @certd/lib-iframe

View File

@@ -1,7 +1,7 @@
{
"name": "@certd/lib-iframe",
"private": false,
"version": "1.32.0",
"version": "1.34.0",
"type": "module",
"main": "./dist/index.js",
"module": "./dist/index.js",
@@ -30,5 +30,5 @@
"tslib": "^2.8.1",
"typescript": "^5.4.2"
},
"gitHead": "8374c3941a9d1398989b8f38fd4bfa2a2f29937b"
"gitHead": "9b420ad33ff4c36fc99d643c18be9ec7e29f220d"
}

View File

@@ -65,7 +65,7 @@ export class IframeClient {
return window.self !== window.top;
}
register<T = any>(action: string, handler: (data: IframeMessageData<T>) => Promise<void>) {
register<T = any>(action: string, handler: (data: IframeMessageData<T>) => Promise<any>) {
this.handlers[action] = handler;
}

View File

@@ -3,6 +3,46 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [1.34.0](https://github.com/certd/certd/compare/v1.33.8...v1.34.0) (2025-04-28)
**Note:** Version bump only for package @certd/jdcloud
## [1.33.8](https://github.com/certd/certd/compare/v1.33.7...v1.33.8) (2025-04-26)
**Note:** Version bump only for package @certd/jdcloud
## [1.33.7](https://github.com/certd/certd/compare/v1.33.6...v1.33.7) (2025-04-22)
**Note:** Version bump only for package @certd/jdcloud
## [1.33.6](https://github.com/certd/certd/compare/v1.33.5...v1.33.6) (2025-04-20)
**Note:** Version bump only for package @certd/jdcloud
## [1.33.5](https://github.com/certd/certd/compare/v1.33.4...v1.33.5) (2025-04-17)
**Note:** Version bump only for package @certd/jdcloud
## [1.33.4](https://github.com/certd/certd/compare/v1.33.3...v1.33.4) (2025-04-15)
**Note:** Version bump only for package @certd/jdcloud
## [1.33.3](https://github.com/certd/certd/compare/v1.33.2...v1.33.3) (2025-04-14)
**Note:** Version bump only for package @certd/jdcloud
## [1.33.2](https://github.com/certd/certd/compare/v1.33.1...v1.33.2) (2025-04-12)
**Note:** Version bump only for package @certd/jdcloud
## [1.33.1](https://github.com/certd/certd/compare/v1.33.0...v1.33.1) (2025-04-12)
**Note:** Version bump only for package @certd/jdcloud
# [1.33.0](https://github.com/certd/certd/compare/v1.32.0...v1.33.0) (2025-04-11)
**Note:** Version bump only for package @certd/jdcloud
# [1.32.0](https://github.com/certd/certd/compare/v1.31.11...v1.32.0) (2025-04-04)
**Note:** Version bump only for package @certd/jdcloud

View File

@@ -1,6 +1,6 @@
{
"name": "@certd/jdcloud",
"version": "1.32.0",
"version": "1.34.0",
"description": "jdcloud openApi sdk",
"main": "./dist/bundle.js",
"module": "./dist/bundle.js",
@@ -60,5 +60,5 @@
"fetch"
]
},
"gitHead": "8374c3941a9d1398989b8f38fd4bfa2a2f29937b"
"gitHead": "9b420ad33ff4c36fc99d643c18be9ec7e29f220d"
}

View File

@@ -3,6 +3,46 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [1.34.0](https://github.com/certd/certd/compare/v1.33.8...v1.34.0) (2025-04-28)
**Note:** Version bump only for package @certd/lib-k8s
## [1.33.8](https://github.com/certd/certd/compare/v1.33.7...v1.33.8) (2025-04-26)
**Note:** Version bump only for package @certd/lib-k8s
## [1.33.7](https://github.com/certd/certd/compare/v1.33.6...v1.33.7) (2025-04-22)
**Note:** Version bump only for package @certd/lib-k8s
## [1.33.6](https://github.com/certd/certd/compare/v1.33.5...v1.33.6) (2025-04-20)
**Note:** Version bump only for package @certd/lib-k8s
## [1.33.5](https://github.com/certd/certd/compare/v1.33.4...v1.33.5) (2025-04-17)
**Note:** Version bump only for package @certd/lib-k8s
## [1.33.4](https://github.com/certd/certd/compare/v1.33.3...v1.33.4) (2025-04-15)
**Note:** Version bump only for package @certd/lib-k8s
## [1.33.3](https://github.com/certd/certd/compare/v1.33.2...v1.33.3) (2025-04-14)
**Note:** Version bump only for package @certd/lib-k8s
## [1.33.2](https://github.com/certd/certd/compare/v1.33.1...v1.33.2) (2025-04-12)
**Note:** Version bump only for package @certd/lib-k8s
## [1.33.1](https://github.com/certd/certd/compare/v1.33.0...v1.33.1) (2025-04-12)
**Note:** Version bump only for package @certd/lib-k8s
# [1.33.0](https://github.com/certd/certd/compare/v1.32.0...v1.33.0) (2025-04-11)
**Note:** Version bump only for package @certd/lib-k8s
# [1.32.0](https://github.com/certd/certd/compare/v1.31.11...v1.32.0) (2025-04-04)
**Note:** Version bump only for package @certd/lib-k8s

View File

@@ -1,7 +1,7 @@
{
"name": "@certd/lib-k8s",
"private": false,
"version": "1.32.0",
"version": "1.34.0",
"type": "module",
"main": "./dist/index.js",
"module": "./dist/index.js",
@@ -16,7 +16,7 @@
"preview": "vite preview"
},
"dependencies": {
"@certd/basic": "^1.32.0",
"@certd/basic": "^1.34.0",
"@kubernetes/client-node": "0.21.0"
},
"devDependencies": {
@@ -31,5 +31,5 @@
"tslib": "^2.8.1",
"typescript": "^5.4.2"
},
"gitHead": "8374c3941a9d1398989b8f38fd4bfa2a2f29937b"
"gitHead": "9b420ad33ff4c36fc99d643c18be9ec7e29f220d"
}

View File

@@ -3,6 +3,48 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [1.34.0](https://github.com/certd/certd/compare/v1.33.8...v1.34.0) (2025-04-28)
**Note:** Version bump only for package @certd/lib-server
## [1.33.8](https://github.com/certd/certd/compare/v1.33.7...v1.33.8) (2025-04-26)
**Note:** Version bump only for package @certd/lib-server
## [1.33.7](https://github.com/certd/certd/compare/v1.33.6...v1.33.7) (2025-04-22)
**Note:** Version bump only for package @certd/lib-server
## [1.33.6](https://github.com/certd/certd/compare/v1.33.5...v1.33.6) (2025-04-20)
**Note:** Version bump only for package @certd/lib-server
## [1.33.5](https://github.com/certd/certd/compare/v1.33.4...v1.33.5) (2025-04-17)
### Performance Improvements
* 登录支持双重认证 ([48aef25](https://github.com/certd/certd/commit/48aef25b3f6499d674ca4e4ef16f4c62399fb735))
## [1.33.4](https://github.com/certd/certd/compare/v1.33.3...v1.33.4) (2025-04-15)
**Note:** Version bump only for package @certd/lib-server
## [1.33.3](https://github.com/certd/certd/compare/v1.33.2...v1.33.3) (2025-04-14)
**Note:** Version bump only for package @certd/lib-server
## [1.33.2](https://github.com/certd/certd/compare/v1.33.1...v1.33.2) (2025-04-12)
**Note:** Version bump only for package @certd/lib-server
## [1.33.1](https://github.com/certd/certd/compare/v1.33.0...v1.33.1) (2025-04-12)
**Note:** Version bump only for package @certd/lib-server
# [1.33.0](https://github.com/certd/certd/compare/v1.32.0...v1.33.0) (2025-04-11)
**Note:** Version bump only for package @certd/lib-server
# [1.32.0](https://github.com/certd/certd/compare/v1.31.11...v1.32.0) (2025-04-04)
**Note:** Version bump only for package @certd/lib-server

View File

@@ -1,6 +1,6 @@
{
"name": "@certd/lib-server",
"version": "1.32.0",
"version": "1.34.0",
"description": "midway with flyway, sql upgrade way ",
"private": false,
"type": "module",
@@ -27,10 +27,10 @@
],
"license": "AGPL",
"dependencies": {
"@certd/acme-client": "^1.32.0",
"@certd/basic": "^1.32.0",
"@certd/pipeline": "^1.32.0",
"@certd/plus-core": "^1.32.0",
"@certd/acme-client": "^1.34.0",
"@certd/basic": "^1.34.0",
"@certd/pipeline": "^1.34.0",
"@certd/plus-core": "^1.34.0",
"@midwayjs/cache": "~3.14.0",
"@midwayjs/core": "~3.20.3",
"@midwayjs/i18n": "~3.20.3",
@@ -61,5 +61,5 @@
"typeorm": "^0.3.11",
"typescript": "^5.4.2"
},
"gitHead": "8374c3941a9d1398989b8f38fd4bfa2a2f29937b"
"gitHead": "9b420ad33ff4c36fc99d643c18be9ec7e29f220d"
}

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

@@ -66,10 +66,19 @@ export const Constants = {
code: 404,
message: '页面/文件/资源不存在',
},
preview: {
code: 10001,
message: '对不起,预览环境不允许修改此数据',
},
siteOff:{
code: 10010,
message: '站点已关闭',
},
need2fa:{
code: 10020,
message: '需要2FA认证',
},
openKeyError: {
code: 20000,
message: 'ApiToken错误',

View File

@@ -1,10 +1,19 @@
import { Constants } from '../constants.js';
import { BaseException } from './base-exception.js';
import { TextException } from "./common-exception.js";
/**
* 授权异常
*/
export class AuthException extends BaseException {
constructor(message) {
constructor(message?:string) {
super('AuthException', Constants.res.auth.code, message ? message : Constants.res.auth.message);
}
}
export class Need2FAException extends TextException {
constructor(message:string,data:any) {
super('Need2FAException', Constants.res.need2fa.code, message ? message : Constants.res.need2fa.message,data);
}
}

View File

@@ -3,9 +3,11 @@
*/
export class BaseException extends Error {
code: number;
constructor(name, code, message) {
data?:any
constructor(name, code, message,data?:any) {
super(message);
this.name = name;
this.code = code;
this.data = data;
}
}

View File

@@ -1,16 +1,23 @@
import { Constants } from '../constants.js';
import { BaseException } from './base-exception.js';
import { Constants } from "../constants.js";
import { BaseException } from "./base-exception.js";
/**
* 通用异常
*/
export class CommonException extends BaseException {
constructor(message) {
super('CommonException', Constants.res.error.code, message ? message : Constants.res.error.message);
super("CommonException", Constants.res.error.code, message ? message : Constants.res.error.message);
}
}
export class CodeException extends BaseException {
constructor(res: { code: number; message: string }) {
super('CodeException', res.code, res.message);
super("CodeException", res.code, res.message);
}
}
export class TextException extends BaseException {
constructor(name, code,message, data?) {
super(name, code, message, data);
}
}

View File

@@ -7,3 +7,4 @@ export * from './vip-exception.js';
export * from './common-exception.js';
export * from './not-found-exception.js';
export * from './param-exception.js';
export * from './site-off-exception.js';

View File

@@ -0,0 +1,9 @@
import { Constants } from '../constants.js';
import { BaseException } from './base-exception.js';
/**
*/
export class SiteOffException extends BaseException {
constructor(message) {
super('SiteOffException', Constants.res.siteOff.code, message ? message : Constants.res.siteOff.message);
}
}

View File

@@ -2,14 +2,15 @@ export class Result<T> {
code: number;
msg: string;
data: T;
constructor(code, msg, data?) {
this.code = code;
this.msg = msg;
this.data = data;
}
static error(code = 1, msg) {
return new Result(code, msg);
static error(code = 1, msg, data?: any) {
return new Result(code, msg, data);
}
static success(msg, data?) {

View File

@@ -171,7 +171,7 @@ export class SysSuiteSetting extends BaseSettings {
static __key__ = 'sys.suite';
static __access__ = 'private';
enabled = false;
enabled:boolean = false;
registerGift?: {
productId: number;
@@ -180,3 +180,25 @@ export class SysSuiteSetting extends BaseSettings {
intro?: string;
}
export type SiteHidden = {
enabled: boolean;
openPath?: string;
//md5 hash 两次后保存
openPassword?: string;
autoHiddenTimes?: number;
hiddenOpenApi?: boolean
};
export class SysSafeSetting extends BaseSettings {
static __title__ = '站点安全设置';
static __key__ = 'sys.safe';
static __access__ = 'private';
// 站点隐藏
hidden:SiteHidden = {
enabled: false,
hiddenOpenApi:false,
autoHiddenTimes: 5,
};
}

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,46 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [1.34.0](https://github.com/certd/certd/compare/v1.33.8...v1.34.0) (2025-04-28)
**Note:** Version bump only for package @certd/midway-flyway-js
## [1.33.8](https://github.com/certd/certd/compare/v1.33.7...v1.33.8) (2025-04-26)
**Note:** Version bump only for package @certd/midway-flyway-js
## [1.33.7](https://github.com/certd/certd/compare/v1.33.6...v1.33.7) (2025-04-22)
**Note:** Version bump only for package @certd/midway-flyway-js
## [1.33.6](https://github.com/certd/certd/compare/v1.33.5...v1.33.6) (2025-04-20)
**Note:** Version bump only for package @certd/midway-flyway-js
## [1.33.5](https://github.com/certd/certd/compare/v1.33.4...v1.33.5) (2025-04-17)
**Note:** Version bump only for package @certd/midway-flyway-js
## [1.33.4](https://github.com/certd/certd/compare/v1.33.3...v1.33.4) (2025-04-15)
**Note:** Version bump only for package @certd/midway-flyway-js
## [1.33.3](https://github.com/certd/certd/compare/v1.33.2...v1.33.3) (2025-04-14)
**Note:** Version bump only for package @certd/midway-flyway-js
## [1.33.2](https://github.com/certd/certd/compare/v1.33.1...v1.33.2) (2025-04-12)
**Note:** Version bump only for package @certd/midway-flyway-js
## [1.33.1](https://github.com/certd/certd/compare/v1.33.0...v1.33.1) (2025-04-12)
**Note:** Version bump only for package @certd/midway-flyway-js
# [1.33.0](https://github.com/certd/certd/compare/v1.32.0...v1.33.0) (2025-04-11)
**Note:** Version bump only for package @certd/midway-flyway-js
# [1.32.0](https://github.com/certd/certd/compare/v1.31.11...v1.32.0) (2025-04-04)
**Note:** Version bump only for package @certd/midway-flyway-js

View File

@@ -1,6 +1,6 @@
{
"name": "@certd/midway-flyway-js",
"version": "1.32.0",
"version": "1.34.0",
"description": "midway with flyway, sql upgrade way ",
"private": false,
"type": "module",
@@ -46,5 +46,5 @@
"typeorm": "^0.3.11",
"typescript": "^5.4.2"
},
"gitHead": "8374c3941a9d1398989b8f38fd4bfa2a2f29937b"
"gitHead": "9b420ad33ff4c36fc99d643c18be9ec7e29f220d"
}

View File

@@ -3,6 +3,65 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [1.34.0](https://github.com/certd/certd/compare/v1.33.8...v1.34.0) (2025-04-28)
**Note:** Version bump only for package @certd/plugin-cert
## [1.33.8](https://github.com/certd/certd/compare/v1.33.7...v1.33.8) (2025-04-26)
### Bug Fixes
* 修复http上传方式无法清除记录文件的bug ([72a7b51](https://github.com/certd/certd/commit/72a7b51d479602b2c54c6c3ac8d8a0dcb9664e73))
### Performance Improvements
* 从域名的soa获取主域名子域名托管无需额外配置 ([a586a92](https://github.com/certd/certd/commit/a586a92d5e32ea846ac37be52a7ad8c328d89966))
* 数据库备份支持oss ([308d460](https://github.com/certd/certd/commit/308d4600efe2002f199c33b4594d3071784e58ea))
* 支持阿里云中文域名申请 ([b3468cf](https://github.com/certd/certd/commit/b3468cf7f28228d7c9cf68de6b5a9bbeb67f2c6d))
* 支持中文域名 ([162ebfd](https://github.com/certd/certd/commit/162ebfd4e0c25727efb33952d3bbf7420a02e2c3))
## [1.33.7](https://github.com/certd/certd/compare/v1.33.6...v1.33.7) (2025-04-22)
**Note:** Version bump only for package @certd/plugin-cert
## [1.33.6](https://github.com/certd/certd/compare/v1.33.5...v1.33.6) (2025-04-20)
**Note:** Version bump only for package @certd/plugin-cert
## [1.33.5](https://github.com/certd/certd/compare/v1.33.4...v1.33.5) (2025-04-17)
**Note:** Version bump only for package @certd/plugin-cert
## [1.33.4](https://github.com/certd/certd/compare/v1.33.3...v1.33.4) (2025-04-15)
**Note:** Version bump only for package @certd/plugin-cert
## [1.33.3](https://github.com/certd/certd/compare/v1.33.2...v1.33.3) (2025-04-14)
**Note:** Version bump only for package @certd/plugin-cert
## [1.33.2](https://github.com/certd/certd/compare/v1.33.1...v1.33.2) (2025-04-12)
**Note:** Version bump only for package @certd/plugin-cert
## [1.33.1](https://github.com/certd/certd/compare/v1.33.0...v1.33.1) (2025-04-12)
**Note:** Version bump only for package @certd/plugin-cert
# [1.33.0](https://github.com/certd/certd/compare/v1.32.0...v1.33.0) (2025-04-11)
### Bug Fixes
* 修复eab授权没有email绑定的bug ([2f1683b](https://github.com/certd/certd/commit/2f1683b26acebbfb7d6e2d751435be04a4e7cab4))
### Features
* **lego:** support set key type ([f3bf4fa](https://github.com/certd/certd/commit/f3bf4faee0be5bdbfdbcf70a502849ed4c8ed4c4))
### Performance Improvements
* 增加手动上传证书功能说明 ([5d083a1](https://github.com/certd/certd/commit/5d083a153637caddbc6f44e915d9fb2d1ae87b33))
# [1.32.0](https://github.com/certd/certd/compare/v1.31.11...v1.32.0) (2025-04-04)
**Note:** Version bump only for package @certd/plugin-cert

View File

@@ -1,7 +1,7 @@
{
"name": "@certd/plugin-cert",
"private": false,
"version": "1.32.0",
"version": "1.34.0",
"type": "module",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
@@ -15,15 +15,16 @@
"preview": "vite preview"
},
"dependencies": {
"@certd/acme-client": "^1.32.0",
"@certd/basic": "^1.32.0",
"@certd/pipeline": "^1.32.0",
"@certd/plugin-lib": "^1.32.0",
"@certd/acme-client": "^1.34.0",
"@certd/basic": "^1.34.0",
"@certd/pipeline": "^1.34.0",
"@certd/plugin-lib": "^1.34.0",
"@google-cloud/publicca": "^1.3.0",
"dayjs": "^1.11.7",
"jszip": "^3.10.1",
"lodash-es": "^4.17.21",
"psl": "^1.9.0",
"punycode": "^2.3.1",
"rimraf": "^5.0.5"
},
"devDependencies": {
@@ -41,5 +42,5 @@
"tslib": "^2.8.1",
"typescript": "^5.4.2"
},
"gitHead": "8374c3941a9d1398989b8f38fd4bfa2a2f29937b"
"gitHead": "9b420ad33ff4c36fc99d643c18be9ec7e29f220d"
}

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> {
@@ -34,4 +35,14 @@ export interface IDnsProvider<T = any> {
createRecord(options: CreateRecordOptions): Promise<T>;
removeRecord(options: RemoveRecordOptions<T>): Promise<void>;
setCtx(ctx: DnsProviderContext): void;
//中文域名是否需要punycode转码如果返回True则使用punycode来添加解析记录否则使用中文域名添加解析记录
usePunyCode(): boolean;
}
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";
@@ -10,12 +8,20 @@ export abstract class AbstractDnsProvider<T = any> implements IDnsProvider<T> {
http!: HttpClient;
logger!: ILogger;
usePunyCode(): boolean {
return false;
}
setCtx(ctx: DnsProviderContext) {
this.ctx = ctx;
this.logger = ctx.logger;
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,18 +29,10 @@ 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);
const DnsProviderClass = dnsProviderPlugin.target;
const DnsProviderClass = await dnsProviderPlugin.target();
const dnsProviderDefine = dnsProviderPlugin.define as DnsProviderDefine;
if (dnsProviderDefine.deprecated) {
context.logger.warn(dnsProviderDefine.deprecated);

View File

@@ -24,7 +24,9 @@ export function IsDnsProvider(define: DnsProviderDefine): ClassDecorator {
target.define = define;
dnsProviderRegistry.register(define.name, {
define,
target,
target: async () => {
return target;
},
});
};
}

View File

@@ -0,0 +1,56 @@
import { IDomainParser, ISubDomainsGetter } from "./api";
//@ts-ignore
import psl from "psl";
import { resolveDomainBySoaRecord } from "@certd/acme-client";
import { logger, utils } from "@certd/basic";
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) {
logger.info(`查找主域名:${fullDomain}`);
const cacheKey = `domain_parse:${fullDomain}`;
const value = utils.cache.get(cacheKey);
if (value) {
logger.info(`从缓存获取到主域名:${fullDomain}->${value}`);
return value;
}
try {
const mainDomain = await resolveDomainBySoaRecord(fullDomain);
if (mainDomain) {
utils.cache.set(cacheKey, mainDomain, {
ttl: 2 * 60 * 1000,
});
logger.info(`获取到主域名:${fullDomain}->${mainDomain}`);
return mainDomain;
}
} catch (e) {
logger.error("从SOA获取主域名失败", e.message);
}
// const subDomains = await this.subDomainsGetter.getSubDomains();
// if (subDomains && subDomains.length > 0) {
// for (const subDomain of subDomains) {
// if (fullDomain.endsWith(subDomain)) {
// //找到子域名托管
// return subDomain;
// }
// }
// }
const res = this.parseDomain(fullDomain);
logger.info(`从psl获取主域名:${fullDomain}->${res}`);
return res;
}
}

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 { HttpChallengeUploader } from "./uploads/api.js";
import { IDnsProvider, IDomainParser } from "../../dns-provider/index.js";
import punycode from "node:punycode";
import { IOssClient } from "@certd/plugin-lib";
export type CnameVerifyPlan = {
type?: string;
domain: string;
@@ -17,7 +18,7 @@ export type CnameVerifyPlan = {
export type HttpVerifyPlan = {
type: string;
domain: string;
httpUploader: HttpChallengeUploader;
httpUploader: IOssClient;
};
export type DomainVerifyPlan = {
@@ -34,7 +35,6 @@ export type DomainsVerifyPlan = {
export type Providers = {
dnsProvider?: IDnsProvider;
domainsVerifyPlan?: DomainsVerifyPlan;
httpUploader?: HttpChallengeUploader;
};
export type CertInfo = {
@@ -61,6 +61,8 @@ type AcmeServiceOptions = {
privateKeyType?: PrivateKeyType;
signal?: AbortSignal;
maxCheckRetryCount?: number;
userId: number;
domainParser: IDomainParser;
};
export class AcmeService {
@@ -174,14 +176,14 @@ 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) => {
return authz.challenges.find((c: any) => c.type === type);
};
const doHttpVerify = async (challenge: any, httpUploader: HttpChallengeUploader) => {
const doHttpVerify = async (challenge: any, httpUploader: IOssClient) => {
const keyAuthorization = await keyAuthorizationGetter(challenge);
this.logger.info("http校验");
const filePath = `.well-known/acme-challenge/${challenge.token}`;
@@ -200,14 +202,16 @@ export class AcmeService {
this.logger.info("dns校验");
const keyAuthorization = await keyAuthorizationGetter(challenge);
const mainDomain = dnsProvider.usePunyCode() ? domain : punycode.toUnicode(domain);
fullRecord = dnsProvider.usePunyCode() ? fullRecord : punycode.toUnicode(fullRecord);
const recordValue = keyAuthorization;
let hostRecord = fullRecord.replace(`${domain}`, "");
let hostRecord = fullRecord.replace(`${mainDomain}`, "");
if (hostRecord.endsWith(".")) {
hostRecord = hostRecord.substring(0, hostRecord.length - 1);
}
const recordReq = {
domain,
domain: mainDomain,
fullRecord,
hostRecord,
type: "TXT",
@@ -240,7 +244,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 {
@@ -283,7 +287,7 @@ export class AcmeService {
* @returns {Promise}
*/
async challengeRemoveFn(authz: any, challenge: any, keyAuthorization: string, recordReq: any, recordRes: any, dnsProvider?: IDnsProvider, httpUploader?: HttpChallengeUploader) {
async challengeRemoveFn(authz: any, challenge: any, keyAuthorization: string, recordReq: any, recordRes: any, dnsProvider?: IDnsProvider, httpUploader?: IOssClient) {
this.logger.info("执行清理");
/* http-01 */
@@ -318,9 +322,16 @@ export class AcmeService {
isTest?: boolean;
privateKeyType?: string;
}): Promise<CertInfo> {
const { email, isTest, domains, csrInfo, dnsProvider, domainsVerifyPlan, httpUploader } = options;
const { email, isTest, csrInfo, dnsProvider, domainsVerifyPlan } = options;
const client: acme.Client = await this.getAcmeClient(email, isTest);
let domains = options.domains;
const encodingDomains = [];
for (const domain of domains) {
encodingDomains.push(punycode.toASCII(domain));
}
domains = encodingDomains;
/* Create CSR */
const { commonName, altNames } = this.buildCommonNameByDomains(domains);
let privateKey = null;
@@ -358,14 +369,13 @@ export class AcmeService {
privateKey
);
if (dnsProvider == null && domainsVerifyPlan == null && httpUploader == null) {
throw new Error("dnsProvider 、 domainsVerifyPlan 、 httpUploader不能都为空");
if (dnsProvider == null && domainsVerifyPlan == null) {
throw new Error("dnsProvider 、 domainsVerifyPlan不能都为空");
}
const providers: Providers = {
dnsProvider,
domainsVerifyPlan,
httpUploader,
};
/* 自动申请证书 */
const crt = await client.auto({
@@ -380,7 +390,7 @@ export class AcmeService {
): Promise<{ recordReq?: any; recordRes?: any; dnsProvider?: any; challenge: Challenge; keyAuthorization: string }> => {
return await this.challengeCreateFn(authz, keyAuthorizationGetter, providers);
},
challengeRemoveFn: async (authz: acme.Authorization, challenge: Challenge, keyAuthorization: string, recordReq: any, recordRes: any, dnsProvider: IDnsProvider): Promise<any> => {
challengeRemoveFn: async (authz: acme.Authorization, challenge: Challenge, keyAuthorization: string, recordReq: any, recordRes: any, dnsProvider: IDnsProvider, httpUploader: IOssClient): Promise<any> => {
return await this.challengeRemoveFn(authz, challenge, keyAuthorization, recordReq, recordRes, dnsProvider, httpUploader);
},
signal: this.options.signal,

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";
import { ossClientFactory } from "@certd/plugin-lib";
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,9 @@ HTTP文件验证不支持泛域名需要配置网站文件上传`,
})
dnsProviderType!: string;
// dns解析授权类型,勿删
dnsProviderAccessType!: string;
@TaskInput({
title: "DNS解析授权",
component: {
@@ -116,7 +128,7 @@ HTTP文件验证不支持泛域名需要配置网站文件上传`,
mergeScript: `return {
component:{
type: ctx.compute(({form})=>{
return form.dnsProviderType
return form.dnsProviderAccessType || form.dnsProviderType
})
},
show: ctx.compute(({form})=>{
@@ -287,7 +299,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 +307,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 +340,7 @@ HTTP文件验证不支持泛域名需要配置网站文件上传`,
privateKeyType: this.privateKeyType,
signal: this.ctx.signal,
maxCheckRetryCount: this.maxCheckRetryCount,
// cnameProxyService: this.ctx.cnameProxyService,
// dnsProviderCreator: this.createDnsProvider.bind(this),
domainParser,
});
}
@@ -356,7 +370,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 +401,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 +417,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,13 +441,13 @@ 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 + "/";
}
this.logger.info("上传方式", httpRecord.httpUploaderType);
const httpUploader = await httpChallengeUploaderFactory.createUploaderByType(httpRecord.httpUploaderType, {
const httpUploader = await ossClientFactory.createOssClientByType(httpRecord.httpUploaderType, {
access,
rootDir: rootDir,
ctx: httpUploaderContext,

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

@@ -1,35 +0,0 @@
import { IAccessService } from "@certd/pipeline";
import { ILogger, utils } from "@certd/basic";
export type HttpChallengeUploader = {
upload: (fileName: string, fileContent: Buffer) => Promise<void>;
remove: (fileName: string) => Promise<void>;
};
export type HttpChallengeUploadContext = {
accessService: IAccessService;
logger: ILogger;
utils: typeof utils;
};
export abstract class BaseHttpChallengeUploader<A> implements HttpChallengeUploader {
rootDir: string;
access: A = null;
logger: ILogger;
utils: typeof utils;
ctx: HttpChallengeUploadContext;
protected constructor(opts: { rootDir: string; access: A }) {
this.rootDir = opts.rootDir;
this.access = opts.access;
}
async setCtx(ctx: any) {
// set context
this.ctx = ctx;
this.logger = ctx.logger;
this.utils = ctx.utils;
}
abstract remove(fileName: string): Promise<void>;
abstract upload(fileName: string, fileContent: Buffer): Promise<void>;
}

View File

@@ -1,39 +0,0 @@
import { BaseHttpChallengeUploader } from "../api.js";
import { AliossAccess, AliyunAccess } from "@certd/plugin-lib";
import { AliossClient } from "@certd/plugin-lib";
export class AliossHttpChallengeUploader extends BaseHttpChallengeUploader<AliossAccess> {
async upload(filePath: string, fileContent: Buffer) {
const aliyunAccess = await this.ctx.accessService.getById<AliyunAccess>(this.access.accessId);
const client = new AliossClient({
access: aliyunAccess,
bucket: this.access.bucket,
region: this.access.region,
});
const key = this.rootDir + filePath;
this.logger.info(`开始上传文件: ${key}`);
await client.uploadFile(key, fileContent);
this.logger.info(`校验文件上传成功: ${filePath}`);
}
async remove(filePath: string) {
const key = this.rootDir + filePath;
// remove file from alioss
const client = await this.getAliossClient();
await client.removeFile(key);
this.logger.info(`文件删除成功: ${key}`);
}
private async getAliossClient() {
const aliyunAccess = await this.ctx.accessService.getById<AliyunAccess>(this.access.accessId);
const client = new AliossClient({
access: aliyunAccess,
bucket: this.access.bucket,
region: this.access.region,
});
await client.init();
return client;
}
}

View File

@@ -1,41 +0,0 @@
import { BaseHttpChallengeUploader } from "../api.js";
import { FtpAccess, FtpClient } from "@certd/plugin-lib";
import path from "path";
import os from "os";
import fs from "fs";
export class FtpHttpChallengeUploader extends BaseHttpChallengeUploader<FtpAccess> {
async upload(filePath: string, fileContent: Buffer) {
const client = new FtpClient({
access: this.access,
logger: this.logger,
});
await client.connect(async (client) => {
const tmpFilePath = path.join(os.tmpdir(), "cert", "http", filePath);
const dir = path.dirname(tmpFilePath);
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
}
fs.writeFileSync(tmpFilePath, fileContent);
try {
// Write file to temp path
const path = this.rootDir + filePath;
await client.upload(path, tmpFilePath);
} finally {
// Remove temp file
fs.unlinkSync(tmpFilePath);
}
});
}
async remove(filePath: string) {
const client = new FtpClient({
access: this.access,
logger: this.logger,
});
await client.connect(async (client) => {
const path = this.rootDir + filePath;
await client.client.remove(path);
});
}
}

View File

@@ -1,31 +0,0 @@
import { BaseHttpChallengeUploader } from "../api.js";
import { QiniuOssAccess, QiniuClient, QiniuAccess } from "@certd/plugin-lib";
export class QiniuOssHttpChallengeUploader extends BaseHttpChallengeUploader<QiniuOssAccess> {
async upload(filePath: string, fileContent: Buffer) {
const qiniuAccess = await this.ctx.accessService.getById<QiniuAccess>(this.access.accessId);
const client = new QiniuClient({
access: qiniuAccess,
logger: this.logger,
http: this.ctx.utils.http,
});
if (this.rootDir.endsWith("/")) {
this.rootDir = this.rootDir.slice(0, -1);
}
await client.uploadFile(this.access.bucket, this.rootDir + filePath, fileContent);
}
async remove(filePath: string) {
const qiniuAccess = await this.ctx.accessService.getById<QiniuAccess>(this.access.accessId);
const client = new QiniuClient({
access: qiniuAccess,
logger: this.logger,
http: this.ctx.utils.http,
});
if (this.rootDir.endsWith("/")) {
this.rootDir = this.rootDir.slice(0, -1);
}
await client.removeFile(this.access.bucket, this.rootDir + filePath);
}
}

View File

@@ -1,51 +0,0 @@
import { BaseHttpChallengeUploader } from "../api.js";
import { SshAccess, SshClient } from "@certd/plugin-lib";
import path from "path";
import os from "os";
import fs from "fs";
import { SftpAccess } from "@certd/plugin-lib";
export class SftpHttpChallengeUploader extends BaseHttpChallengeUploader<SftpAccess> {
async upload(filePath: string, fileContent: Buffer) {
const tmpFilePath = path.join(os.tmpdir(), "cert", "http", filePath);
// Write file to temp path
const dir = path.dirname(tmpFilePath);
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
}
fs.writeFileSync(tmpFilePath, fileContent);
const access = await this.ctx.accessService.getById<SshAccess>(this.access.sshAccess);
const key = this.rootDir + filePath;
try {
const client = new SshClient(this.logger);
await client.uploadFiles({
connectConf: access,
mkdirs: true,
transports: [
{
localPath: tmpFilePath,
remotePath: key,
},
],
opts: {
mode: this.access?.fileMode ?? undefined,
},
});
} finally {
// Remove temp file
fs.unlinkSync(tmpFilePath);
}
}
async remove(filePath: string) {
const access = await this.ctx.accessService.getById<SshAccess>(this.access.sshAccess);
const client = new SshClient(this.logger);
const key = this.rootDir + filePath;
await client.removeFiles({
connectConf: access,
files: [key],
});
}
}

View File

@@ -1,28 +0,0 @@
import { BaseHttpChallengeUploader } from "../api.js";
import { TencentAccess, TencentCosAccess, TencentCosClient } from "@certd/plugin-lib";
export class TencentCosHttpChallengeUploader extends BaseHttpChallengeUploader<TencentCosAccess> {
async upload(filePath: string, fileContent: Buffer) {
const access = await this.ctx.accessService.getById<TencentAccess>(this.access.accessId);
const client = new TencentCosClient({
access: access,
logger: this.logger,
region: this.access.region,
bucket: this.access.bucket,
});
const key = this.rootDir + filePath;
await client.uploadFile(key, fileContent);
}
async remove(filePath: string) {
const access = await this.ctx.accessService.getById<TencentAccess>(this.access.accessId);
const client = new TencentCosClient({
access: access,
logger: this.logger,
region: this.access.region,
bucket: this.access.bucket,
});
const key = this.rootDir + filePath;
await client.removeFile(key);
}
}

View File

@@ -3,6 +3,60 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [1.34.0](https://github.com/certd/certd/compare/v1.33.8...v1.34.0) (2025-04-28)
### Performance Improvements
* 优化cdnfly插件支持自动匹配域名部署 ([afd59e9](https://github.com/certd/certd/commit/afd59e9933b2650f41c5d47684c171b93b962065))
## [1.33.8](https://github.com/certd/certd/compare/v1.33.7...v1.33.8) (2025-04-26)
### Bug Fixes
* 修复http上传方式无法清除记录文件的bug ([72a7b51](https://github.com/certd/certd/commit/72a7b51d479602b2c54c6c3ac8d8a0dcb9664e73))
### Performance Improvements
* 七牛oss支持删除过期备份 ([b7113bd](https://github.com/certd/certd/commit/b7113bda2378116d6c116dc583f563cce7cf9f00))
* 数据库备份支持oss ([308d460](https://github.com/certd/certd/commit/308d4600efe2002f199c33b4594d3071784e58ea))
## [1.33.7](https://github.com/certd/certd/compare/v1.33.6...v1.33.7) (2025-04-22)
### Performance Improvements
* ssh PTY模式登录设置 ([8385bcc](https://github.com/certd/certd/commit/8385bcc2d7f2411a07748bb5c53f9eaf4d38d7cc))
* ssh伪终端模式优化windows下不开启 ([42dfe93](https://github.com/certd/certd/commit/42dfe936b773b7bdd82ca3378363252ffffd7b71))
## [1.33.6](https://github.com/certd/certd/compare/v1.33.5...v1.33.6) (2025-04-20)
**Note:** Version bump only for package @certd/plugin-lib
## [1.33.5](https://github.com/certd/certd/compare/v1.33.4...v1.33.5) (2025-04-17)
**Note:** Version bump only for package @certd/plugin-lib
## [1.33.4](https://github.com/certd/certd/compare/v1.33.3...v1.33.4) (2025-04-15)
### Performance Improvements
* 插件支持导入导出 ([cf8abb4](https://github.com/certd/certd/commit/cf8abb45282070c8ba91469f93fd379fabf1f74a))
## [1.33.3](https://github.com/certd/certd/compare/v1.33.2...v1.33.3) (2025-04-14)
**Note:** Version bump only for package @certd/plugin-lib
## [1.33.2](https://github.com/certd/certd/compare/v1.33.1...v1.33.2) (2025-04-12)
**Note:** Version bump only for package @certd/plugin-lib
## [1.33.1](https://github.com/certd/certd/compare/v1.33.0...v1.33.1) (2025-04-12)
**Note:** Version bump only for package @certd/plugin-lib
# [1.33.0](https://github.com/certd/certd/compare/v1.32.0...v1.33.0) (2025-04-11)
**Note:** Version bump only for package @certd/plugin-lib
# [1.32.0](https://github.com/certd/certd/compare/v1.31.11...v1.32.0) (2025-04-04)
**Note:** Version bump only for package @certd/plugin-lib

View File

@@ -1,7 +1,7 @@
{
"name": "@certd/plugin-lib",
"private": false,
"version": "1.32.0",
"version": "1.34.0",
"type": "module",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
@@ -16,10 +16,11 @@
},
"dependencies": {
"@alicloud/pop-core": "^1.7.10",
"@certd/basic": "^1.32.0",
"@certd/pipeline": "^1.32.0",
"@aws-sdk/client-s3": "^3.787.0",
"@certd/basic": "^1.34.0",
"@certd/pipeline": "^1.34.0",
"@kubernetes/client-node": "0.21.0",
"ali-oss": "^6.21.0",
"ali-oss": "^6.22.0",
"basic-ftp": "^5.0.5",
"cos-nodejs-sdk-v5": "^2.14.6",
"dayjs": "^1.11.7",
@@ -48,5 +49,5 @@
"tslib": "^2.8.1",
"typescript": "^5.4.2"
},
"gitHead": "8374c3941a9d1398989b8f38fd4bfa2a2f29937b"
"gitHead": "9b420ad33ff4c36fc99d643c18be9ec7e29f220d"
}

View File

@@ -5,6 +5,7 @@ import { IsAccess, AccessInput, BaseAccess } from "@certd/pipeline";
title: "阿里云授权",
desc: "",
icon: "ant-design:aliyun-outlined",
order: 0,
})
export class AliyunAccess extends BaseAccess {
@AccessInput({

View File

@@ -1,4 +1,4 @@
import { AliyunAccess } from "../access";
import { AliyunAccess } from "../access/index.js";
export class AliossClient {
access: AliyunAccess;
@@ -52,7 +52,7 @@ export class AliossClient {
}
}
async uploadFile(filePath: string, content: Buffer) {
async uploadFile(filePath: string, content: Buffer | string) {
await this.init();
return await this.client.put(filePath, content);
}
@@ -61,4 +61,23 @@ export class AliossClient {
await this.init();
return await this.client.delete(filePath);
}
async downloadFile(key: string, savePath: string) {
await this.init();
return await this.client.get(key, savePath);
}
async listDir(dirKey: string) {
await this.init();
const res = await this.client.listV2({
prefix: dirKey,
// max-keys: 100,
// continuation-token: "token",
// delimiter: "/",
// marker: "marker",
// encoding-type: "url",
});
return res.objects;
}
}

View File

@@ -65,7 +65,7 @@ export function createRemoteSelectInputDefine(opts?: {
watches: [certDomainsInputKey, accessIdInputKey, ...watches],
},
rules: opts?.rules,
required: true,
required: opts.required ?? true,
mergeScript: `
return {
component:{

View File

@@ -11,7 +11,7 @@ export class FtpClient {
this.logger = opts.logger;
}
async connect(callback: (client: FtpClient) => Promise<void>) {
async connect(callback: (client: FtpClient) => Promise<any>) {
const ftp = await import("basic-ftp");
const Client = ftp.Client;
const client = new Client();
@@ -21,7 +21,7 @@ export class FtpClient {
this.logger.info("FTP连接成功");
this.client = client;
try {
await callback(this);
return await callback(this);
} finally {
if (client) {
client.close();
@@ -44,4 +44,20 @@ export class FtpClient {
this.logger.info(`开始删除文件${filePath}`);
await this.client.remove(filePath, true);
}
async listDir(dir: string): Promise<any[]> {
if (!dir) {
return [];
}
if (!dir.endsWith("/")) {
dir = dir + "/";
}
this.logger.info(`开始列出目录${dir}`);
return await this.client.list(dir);
}
async download(filePath: string, savePath: string): Promise<void> {
this.logger.info(`开始下载文件${filePath} -> ${savePath}`);
await this.client.downloadTo(savePath, filePath);
}
}

View File

@@ -5,3 +5,5 @@ export * from "./ftp/index.js";
export * from "./tencent/index.js";
export * from "./qiniu/index.js";
export * from "./ctyun/index.js";
export * from "./oss/index.js";
export * from "./s3/index.js";

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