Compare commits

...

10 Commits

Author SHA1 Message Date
xiaojunnuo fe1e2c3b62 Merge branch 'v2-dev' of https://github.com/certd/certd into v2-dev 2025-12-10 14:17:20 +08:00
xiaojunnuo bbe7e5f96d chore: 1 2025-12-10 14:15:39 +08:00
xiaojunnuo 2bfad9fc65 fix: 优化西部数据 500 already exists 的问题 2025-12-09 23:33:11 +08:00
xiaojunnuo 9f24c18f7f chore: 优化数据库脚本 2025-12-09 23:28:29 +08:00
xiaojunnuo a2d1e5ea03 chore: 修复sqlite语句双引号改单引号 2025-12-09 23:11:19 +08:00
xiaojunnuo b082e4e988 chore: 1 2025-12-09 00:47:08 +08:00
xiaojunnuo 45fbce0c2a perf: 新增数据库迁移doc说明文档,优化datetime字段平滑迁移 2025-12-09 00:45:10 +08:00
xiaojunnuo ff7006e232 build: release 2025-12-07 01:17:22 +08:00
xiaojunnuo c68fdef0e4 build: publish 2025-12-07 00:59:50 +08:00
xiaojunnuo 4c60e4edc1 build: trigger build image 2025-12-07 00:59:39 +08:00
43 changed files with 151 additions and 40 deletions
+2 -1
View File
@@ -9,5 +9,6 @@
"[typescript]": {
"editor.defaultFormatter": "vscode.typescript-language-features"
},
"editor.tabSize": 2
"editor.tabSize": 2,
"explorer.autoReveal": false
}
+13
View File
@@ -3,6 +3,19 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.37.15](https://github.com/certd/certd/compare/v1.37.14...v1.37.15) (2025-12-06)
### Bug Fixes
* oidc 支持nonce ([a5ca411](https://github.com/certd/certd/commit/a5ca41131b308b36b17ca359d9709ea8e9b7cee1))
### Performance Improvements
* 第三方登录支持gitee ([5cee7d4](https://github.com/certd/certd/commit/5cee7d44f17bd36972f477bc1f270999da558d05))
* 邮件模版安全优化 ([adca151](https://github.com/certd/certd/commit/adca151e4f07a4c6a2a753bfa48ee0d4d6469fd2))
* 支持部署到中国移动CDN ([4351304](https://github.com/certd/certd/commit/43513049beff407558d2a234415521464165cebc))
* 支持k8s apply ([d55954a](https://github.com/certd/certd/commit/d55954a36391ebe6a9397ff7dcfb710193ac5e34))
## [1.37.14](https://github.com/certd/certd/compare/v1.37.13...v1.37.14) (2025-12-02)
### Bug Fixes
+50 -5
View File
@@ -65,9 +65,54 @@ docker-compose up -d
## 二、从旧版的sqlite切换数据库
1. 先将`旧certd`升级到最新版 `建议:备份sqlite数据库`
2. 按照上面全新安装方式部署一套`新的certd` `注意:新旧版本的certd要一致`
3. 使用数据库工具将数据从sqlite导入到mysql或postgresql `注意:flyway_history数据表不要导入`
4. 重启新certd
5. 确认没有问题之后,删除旧版certd
从旧版`sqlite`迁移到`mysql``postgresql`数据库
下面以 `SQLite``MySQL` 为例进行演示
![db-0.png](images/db-0.png)
#### 0.前提条件:
1. SQLite版Certd站点已经`升级到最新版` `建议:备份sqlite数据库`
2. `全新安装`MySQL版本Certd`确保是全新的,因为里面的数据会被清空覆盖`
3. 两套Certd站点版本一致
#### 1. 安装DBeaver工具
[https://dbeaver.io/download/](https://dbeaver.io/download/)
![db-1.png](images/db-1.png)
#### 2. 连接到sqlite数据库
![db-2.png](images/db-sqlite-1.png)
![db-3.png](images/db-sqlite-2.png)
#### 3. 连接到mysql或postgresql数据库
![db-4.png](images/db-mysql-1.png)
![db-5.png](images/db-mysql-2.png)
#### 4. 开始同步数据
选择mysql数据库,选择所有的表(`flyway_history除外`),右键导入数据
> 切记flyway_history数据表不要导入
![db-6.png](images/db-sync-1.jpg)
![db-7.png](images/db-sync-2.png)
![db-8.png](images/db-sync-3.png)
下一步、下一步,直到数据加载设置,勾选`在加载前截断目标表`(此选项很重要,并且会清空mysql certd数据库中的数据)
![db-7.png](images/db-sync-4.png)
#### 5. 导入完成
![db-9.png](images/db-success.png)
#### 6. 重启MySQL版本Certd
访问MySQL版本测试,数据已成功迁移
确认没有问题之后,删除旧版certd
Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 145 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 194 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 145 KiB

+2 -1
View File
@@ -64,7 +64,8 @@
| 60.| **新网授权** | |
| 61.| **新网授权(代理方式)** | |
| 62.| **新网互联授权** | 仅支持代理账号,ip需要加入白名单 |
| 63.| **雨云授权** | https://app.rainyun.com/ |
| 63.| **中国移动CND授权** | |
| 64.| **雨云授权** | https://app.rainyun.com/ |
<style module>
table th:first-of-type {
+12 -10
View File
@@ -1,5 +1,5 @@
# 任务插件
`103` 款任务插件
`105` 款任务插件
## 1. 证书申请
| 序号 | 名称 | 说明 |
@@ -42,6 +42,7 @@
| 19.| **网宿-更新证书** | 网宿证书自动更新 |
| 20.| **金山云-更新CDN证书** | 金山云自动更新CDN证书 |
| 21.| **APISIX-更新证书** | 自动更新APISIX证书 |
| 22.| **中国移动-部署证书到CDN** | 中国移动自动部署证书到CDN |
## 4. 面板
| 序号 | 名称 | 说明 |
@@ -54,15 +55,16 @@
| 6.| **群晖-部署证书到群晖面板** | Synology,支持6.x以上版本 |
| 7.| **K8S-部署证书到Secret** | 部署证书到k8s的secret |
| 8.| **K8S-Ingress 证书部署** | 部署证书到k8s的Ingress |
| 9.| **1Panel-部署证书到1Panel** | 更新1Panel的证书 |
| 10.| **Plesk-部署Plesk网站证书** | |
| 11.| **雷池-更新证书** | 更新长亭雷池WAF的证书 |
| 12.| **lucky-更新Lucky证书** | |
| 13.| **uniCloud-部署到服务空间** | 部署到服务空间 |
| 14.| **威联通-部署证书到威联通** | 部署证书到qnap |
| 15.| **飞牛NAS-部署证书** | |
| 16.| **Proxmox-上传证书到Proxmox** | |
| 17.| **Dokploy-部署server证书** | 自动更新Dokploy server证书 |
| 9.| **K8S-Apply自定义yaml** | apply自定义yaml到k8s |
| 10.| **1Panel-部署证书到1Panel** | 更新1Panel的证书 |
| 11.| **Plesk-部署Plesk网站证书** | |
| 12.| **雷池-更新证书** | 更新长亭雷池WAF的证书 |
| 13.| **lucky-更新Lucky证书** | |
| 14.| **uniCloud-部署到服务空间** | 部署到服务空间 |
| 15.| **威联通-部署证书到威联通** | 部署证书到qnap |
| 16.| **飞牛NAS-部署证书** | |
| 17.| **Proxmox-上传证书到Proxmox** | |
| 18.| **Dokploy-部署server证书** | 自动更新Dokploy server证书 |
## 5. 阿里云
| 序号 | 名称 | 说明 |
+1
View File
@@ -16,6 +16,7 @@
"start": "lerna bootstrap --hoist",
"start:server": "cd ./packages/ui/certd-server && npm start",
"devb": "lerna run dev-build",
"build": "lerna run build",
"i-all": "lerna link && lerna exec npm install ",
"publish": "npm run prepublishOnly2 && lerna publish --force-publish=pro/plus-core --conventional-commits --create-release github && npm run afterpublishOnly ",
"afterpublishOnly": "npm run plugin-doc-gen && npm run copylogs && time /t >trigger/build.trigger && git add ./trigger/build.trigger && git commit -m \"build: trigger build image\" && TIMEOUT /T 10 && npm run commitAll",
+1 -1
View File
@@ -70,5 +70,5 @@
"bugs": {
"url": "https://github.com/publishlab/node-acme-client/issues"
},
"gitHead": "ddb18e6c219d0f7a7acb4a3355be5db3fd9e096e"
"gitHead": "f2e4e59f8d1b54b835d5da43aef8b527d6a4ba0b"
}
+1 -1
View File
@@ -47,5 +47,5 @@
"tslib": "^2.8.1",
"typescript": "^5.4.2"
},
"gitHead": "ddb18e6c219d0f7a7acb4a3355be5db3fd9e096e"
"gitHead": "f2e4e59f8d1b54b835d5da43aef8b527d6a4ba0b"
}
+1 -1
View File
@@ -45,5 +45,5 @@
"tslib": "^2.8.1",
"typescript": "^5.4.2"
},
"gitHead": "ddb18e6c219d0f7a7acb4a3355be5db3fd9e096e"
"gitHead": "f2e4e59f8d1b54b835d5da43aef8b527d6a4ba0b"
}
+1 -1
View File
@@ -24,5 +24,5 @@
"prettier": "^2.8.8",
"tslib": "^2.8.1"
},
"gitHead": "ddb18e6c219d0f7a7acb4a3355be5db3fd9e096e"
"gitHead": "f2e4e59f8d1b54b835d5da43aef8b527d6a4ba0b"
}
+1 -1
View File
@@ -31,5 +31,5 @@
"tslib": "^2.8.1",
"typescript": "^5.4.2"
},
"gitHead": "ddb18e6c219d0f7a7acb4a3355be5db3fd9e096e"
"gitHead": "f2e4e59f8d1b54b835d5da43aef8b527d6a4ba0b"
}
+1 -1
View File
@@ -56,5 +56,5 @@
"fetch"
]
},
"gitHead": "ddb18e6c219d0f7a7acb4a3355be5db3fd9e096e"
"gitHead": "f2e4e59f8d1b54b835d5da43aef8b527d6a4ba0b"
}
+1 -1
View File
@@ -32,5 +32,5 @@
"tslib": "^2.8.1",
"typescript": "^5.4.2"
},
"gitHead": "ddb18e6c219d0f7a7acb4a3355be5db3fd9e096e"
"gitHead": "f2e4e59f8d1b54b835d5da43aef8b527d6a4ba0b"
}
+1 -1
View File
@@ -64,5 +64,5 @@
"typeorm": "^0.3.11",
"typescript": "^5.4.2"
},
"gitHead": "ddb18e6c219d0f7a7acb4a3355be5db3fd9e096e"
"gitHead": "f2e4e59f8d1b54b835d5da43aef8b527d6a4ba0b"
}
+1 -1
View File
@@ -46,5 +46,5 @@
"typeorm": "^0.3.11",
"typescript": "^5.4.2"
},
"gitHead": "ddb18e6c219d0f7a7acb4a3355be5db3fd9e096e"
"gitHead": "f2e4e59f8d1b54b835d5da43aef8b527d6a4ba0b"
}
+1 -1
View File
@@ -43,5 +43,5 @@
"tslib": "^2.8.1",
"typescript": "^5.4.2"
},
"gitHead": "ddb18e6c219d0f7a7acb4a3355be5db3fd9e096e"
"gitHead": "f2e4e59f8d1b54b835d5da43aef8b527d6a4ba0b"
}
+1 -1
View File
@@ -53,5 +53,5 @@
"tslib": "^2.8.1",
"typescript": "^5.4.2"
},
"gitHead": "ddb18e6c219d0f7a7acb4a3355be5db3fd9e096e"
"gitHead": "f2e4e59f8d1b54b835d5da43aef8b527d6a4ba0b"
}
@@ -631,7 +631,7 @@ export default {
autoHideTime: "Auto Hide Time",
autoHideTimeHelper: "Minutes without requests before auto hiding",
hideOpenApi: "Hide Open API",
hideOpenApiHelper: "Whether to hide open APIs; whether to expose /api/v1 prefixed endpoints",
hideOpenApiHelper: "Whether to hide open APIs; whether to hide /api/v1 prefixed endpoints",
hideSiteImmediately: "Hide Site Immediately",
hideImmediately: "Hide Immediately",
confirmHideSiteTitle: "Are you sure to hide the site immediately?",
@@ -635,7 +635,7 @@ export default {
autoHideTime: "自动隐藏时间",
autoHideTimeHelper: "多少分钟内无请求自动隐藏",
hideOpenApi: "隐藏开放接口",
hideOpenApiHelper: "是否隐藏开放接口,是否放开/api/v1开头的接口",
hideOpenApiHelper: "是否隐藏开放接口,是否同时隐藏/api/v1开头的接口",
hideSiteImmediately: "立即隐藏站点",
hideImmediately: "立即隐藏",
confirmHideSiteTitle: "确定要立即隐藏站点吗?",
@@ -21,6 +21,7 @@
},
},
}"
:disabled="disabled"
:show-current="false"
:show-select="false"
:dialog="{ width: 960 }"
@@ -7,7 +7,7 @@
<vip-button class="ml-5" mode="button"></vip-button>
</div>
</a-form-item>
<a-form-item v-if="formState.public.oauthEnabled" :label="t('certd.sys.setting.oauthProviders')" :name="['public', 'oauthProviders']">
<a-form-item :label="t('certd.sys.setting.oauthProviders')" :name="['public', 'oauthProviders']">
<div class="flex flex-wrap">
<table class="w-full table-auto border-collapse border border-gray-400">
<thead>
@@ -31,7 +31,14 @@
</fs-copyable>
</td>
<td class="border border-gray-300 px-4 py-2">
<AddonSelector v-model:model-value="item.addonId" addon-type="oauth" from="sys" :type="item.name" :placeholder="t('certd.sys.setting.oauthProviderSelectorPlaceholder')" />
<AddonSelector
v-model:model-value="item.addonId"
:disabled="!formState.public.oauthEnabled"
addon-type="oauth"
from="sys"
:type="item.name"
:placeholder="t('certd.sys.setting.oauthProviderSelectorPlaceholder')"
/>
</td>
</tr>
</tbody>
+1
View File
@@ -22,3 +22,4 @@ run/
tools/lego/*
!tools/lego/readme.md
test.mjs
isolate-*.log
@@ -0,0 +1,2 @@
ALTER TABLE `sys_settings` MODIFY COLUMN `setting` longtext NULL;
ALTER TABLE `user_settings` MODIFY COLUMN `setting` longtext NULL;
@@ -0,0 +1,20 @@
update cd_access set create_time = '2024-08-08 00:00:00.000' where create_time < '999999999999999999999';
update cd_access set update_time = '2024-08-08 00:00:00.000' where update_time < '999999999999999999999';
update pi_history set create_time = '2024-08-08 00:00:00.000' where create_time < '999999999999999999999';
update pi_history set update_time = '2024-08-08 00:00:00.000' where update_time < '999999999999999999999';
update pi_history_log set create_time = '2024-08-08 00:00:00.000' where create_time < '999999999999999999999';
update pi_history_log set update_time = '2024-08-08 00:00:00.000' where update_time < '999999999999999999999';
update pi_pipeline set create_time = '2024-08-08 00:00:00.000' where create_time < '999999999999999999999';
update pi_pipeline set update_time = '2024-08-08 00:00:00.000' where update_time < '999999999999999999999';
update sys_permission set create_time = '2024-08-08 00:00:00.000' where create_time < '999999999999999999999';
update sys_permission set update_time = '2024-08-08 00:00:00.000' where update_time < '999999999999999999999';
update sys_role set create_time = '2024-08-08 00:00:00.000' where create_time < '999999999999999999999';
update sys_role set update_time = '2024-08-08 00:00:00.000' where update_time < '999999999999999999999';
update sys_user set create_time = '2024-08-08 00:00:00.000' where create_time < '999999999999999999999';
update sys_user set update_time = '2024-08-08 00:00:00.000' where update_time < '999999999999999999999';
+3 -3
View File
@@ -5,7 +5,7 @@
"private": true,
"type": "module",
"scripts": {
"start": "cross-env NODE_ENV=production node ./bootstrap.js",
"start": "cross-env NODE_ENV=production node --optimize-for-size ./bootstrap.js",
"dev-start": "mwtsc --watch --run @midwayjs/mock/app",
"dc": "cd ../../../ && pnpm run dev",
"dev": "cross-env NODE_ENV=local & pnpm run dev-start",
@@ -23,13 +23,13 @@
"lint": "mwts check",
"lint:fix": "mwts fix",
"ci": "npm run cov",
"build": "mwtsc --cleanOutDir --skipLibCheck",
"build": "cross-env NODE_ENV=production mwtsc --cleanOutDir --skipLibCheck",
"export-metadata": "node export-plugin-yaml.js",
"export-md": "node export-plugin-md.js",
"dev-build": "echo 1",
"build-on-docker": "node ./before-build.js && npm run build",
"up-mw-deps": "npx midway-version -u -w",
"heap": "cross-env NODE_ENV=local clinic heapprofiler -- node ./bootstrap.js",
"heap": "cross-env NODE_ENV=production clinic heapprofiler -- node --optimize-for-size --inspect ./bootstrap.js",
"flame": "clinic flame -- node ./bootstrap.js",
"tsc": "tsc --skipLibCheck",
"slimming": "node ./slimming.js",
@@ -21,6 +21,8 @@ import * as upload from '@midwayjs/upload';
import { setLogger } from '@certd/acme-client';
import {HiddenMiddleware} from "./middleware/hidden.js";
//@ts-ignore
// process.env.UV_THREADPOOL_SIZE = 2
process.on('uncaughtException', error => {
console.error('未捕获的异常:', error);
// 在这里可以添加日志记录、发送错误通知等操作
@@ -158,6 +158,9 @@ export class WestAccess extends BaseAccess {
},
});
if (res.msg !== 'success') {
if(res.msg.includes('500 already exists')){
return res;
}
throw new Error(`${JSON.stringify(res.msg)}`);
}
return res;
@@ -253,6 +256,9 @@ token=md5(zhangsan + 5dh232kfg!* + 1554691950854)=cfcd208495d565ef66e7dff9f98764
});
this.ctx.logger.info(`request ${url} ${method} res:${JSON.stringify(res)}`);
if (res.msg !== 'success' && res.result!= 200) {
if(res.msg.includes('500 already exists')){
return res;
}
throw new Error(`${JSON.stringify(res.msg)}`);
}
return res;
@@ -73,11 +73,16 @@ export class WestDnsProviderDomain extends AbstractDnsProvider<westRecord> {
}
//这里调用删除txt dns解析记录接口
const record_id = record?.body?.record_id;
if (!record_id) {
this.logger.info('record_id不存在');
return;
}
// 准备要发送到API的请求体
const requestBody = {
act: 'dnsrec.remove', // API动作类型
domain: domain, // 域名
record_id: record.body.record_id,
record_id: record_id,
hostname: fullRecord, // 完整的记录名
record_type: 'TXT', // DNS记录类型
record_line: '', // 记录线路
@@ -107,12 +107,16 @@ export class WestDnsProvider extends AbstractDnsProvider<westRecord> {
return;
}
//这里调用删除txt dns解析记录接口
const record_id = record.data?.id;
if (!record_id) {
this.logger.info('record_id不存在');
return;
}
// 准备要发送到API的请求体
const requestBody = {
act: 'deldnsrecord', // API动作类型
domain: domain, // 域名
id: record.data?.id,
id: record_id,
};
const url = '/v2/domain/';
+1 -1
View File
@@ -1 +1 @@
01:01
00:59
+1 -1
View File
@@ -1 +1 @@
10:09
01:17