mirror of
https://github.com/certd/certd.git
synced 2026-04-23 19:57:27 +08:00
chore: 1
This commit is contained in:
@@ -175,11 +175,11 @@ https://certd.handfree.work/
|
||||
| 功能 | 免费版 | 专业版 |
|
||||
|---------|---------------------------------------|--------------------------------|
|
||||
| 免费证书申请 | 免费无限制 | 免费无限制 |
|
||||
| 域名数量 | 无限制 | 无限制 |
|
||||
| 证书域名数量 | 无限制 | 无限制 |
|
||||
| 证书流水线条数 | 无限制 | 无限制 |
|
||||
| 站点证书监控 | 限制1条 | 无限制 |
|
||||
| 自动部署插件 | 阿里云CDN、腾讯云、七牛CDN、主机部署、宝塔、1Panel等大部分插件 | 群晖、威联通、proxmox等 |
|
||||
| 通知 | 邮件通知、自定义webhook | 邮件免配置、企微、钉钉、飞书、anpush、server酱等 |
|
||||
| 站点监控 | 限制1条 | 无限制 |
|
||||
| 批量操作 | 无 | 流水线模版,流水线复制,批量运行,批量设置通知、定时等 |
|
||||
| VIP群 | 无 | 可加,一对一技术支持,必要时可申请远程协助 |
|
||||
|
||||
|
||||
@@ -1,190 +0,0 @@
|
||||
import { SynologyAccess } from "./access.js";
|
||||
import { HttpClient, ILogger } from "@certd/basic";
|
||||
import qs from "querystring";
|
||||
|
||||
export type SynologyAccessToken = {
|
||||
sid: string;
|
||||
did?: string;
|
||||
synotoken: string;
|
||||
};
|
||||
|
||||
export type SynologyRequest = {
|
||||
method?: string;
|
||||
apiParams: {
|
||||
api: string;
|
||||
version: number;
|
||||
method: string;
|
||||
};
|
||||
params?: any;
|
||||
data?: any;
|
||||
form?: any;
|
||||
headers?: any;
|
||||
useSynoToken?: boolean;
|
||||
};
|
||||
|
||||
const device_name = "certd";
|
||||
|
||||
export class SynologyClient {
|
||||
access: SynologyAccess;
|
||||
http: HttpClient;
|
||||
logger: ILogger;
|
||||
skipSslVerify: boolean;
|
||||
|
||||
token: SynologyAccessToken;
|
||||
constructor(access: SynologyAccess, http: HttpClient, logger: ILogger, skipSslVerify: boolean) {
|
||||
this.access = access;
|
||||
this.http = http;
|
||||
this.logger = logger;
|
||||
this.skipSslVerify = skipSslVerify;
|
||||
}
|
||||
|
||||
// 登录 DSM 的函数
|
||||
async doLogin() {
|
||||
const access = this.access;
|
||||
if (access.otp && access.deviceId != null) {
|
||||
this.logger.info("OTP登录");
|
||||
return await this.doLoginWithDeviceId(access.deviceId);
|
||||
}
|
||||
this.logger.info("使用普通登录");
|
||||
|
||||
const loginUrl = this.getLoginUrl();
|
||||
const res = await this.http.request({
|
||||
url: loginUrl,
|
||||
method: "GET",
|
||||
params: {
|
||||
api: "SYNO.API.Auth",
|
||||
version: 6,
|
||||
method: "login",
|
||||
account: access.username,
|
||||
passwd: access.password,
|
||||
session: "Certd",
|
||||
format: "sid",
|
||||
enable_syno_token: "yes",
|
||||
},
|
||||
skipSslVerify: this.skipSslVerify ?? true,
|
||||
timeout: this.access.timeout * 1000 || 120000,
|
||||
});
|
||||
|
||||
if (!res.success) {
|
||||
throw new Error(`登录失败: `, res.error);
|
||||
}
|
||||
this.logger.info("登录成功");
|
||||
|
||||
this.token = res.data as SynologyAccessToken;
|
||||
return this.token;
|
||||
}
|
||||
|
||||
async doLoginWithOTPCode(otpCode: string) {
|
||||
const loginUrl = this.getLoginUrl();
|
||||
const access = this.access;
|
||||
const res = await this.http.request({
|
||||
url: loginUrl,
|
||||
method: "GET",
|
||||
params: {
|
||||
api: "SYNO.API.Auth",
|
||||
version: 6,
|
||||
method: "login",
|
||||
account: access.username,
|
||||
passwd: access.password,
|
||||
otp_code: otpCode,
|
||||
enable_device_token: "yes",
|
||||
device_name,
|
||||
},
|
||||
timeout: this.access.timeout * 1000 || 30000,
|
||||
skipSslVerify: this.skipSslVerify ?? true,
|
||||
});
|
||||
|
||||
if (!res.success) {
|
||||
throw new Error(`登录失败: `, res.error);
|
||||
}
|
||||
this.logger.info("登录成功");
|
||||
|
||||
this.token = res.data as SynologyAccessToken;
|
||||
return this.token;
|
||||
}
|
||||
|
||||
private getLoginUrl() {
|
||||
const access = this.access;
|
||||
const loginPath = access.version === "6" ? "auth.cgi" : "entry.cgi";
|
||||
return `${access.baseUrl}/webapi/${loginPath}`;
|
||||
}
|
||||
|
||||
async doLoginWithDeviceId(device_id: string) {
|
||||
const access = this.access;
|
||||
const loginUrl = this.getLoginUrl();
|
||||
const res = await this.http.request({
|
||||
url: loginUrl,
|
||||
method: "GET",
|
||||
params: {
|
||||
api: "SYNO.API.Auth",
|
||||
version: 6,
|
||||
method: "login",
|
||||
account: access.username,
|
||||
passwd: access.password,
|
||||
device_name,
|
||||
device_id,
|
||||
session: "Certd",
|
||||
format: "sid",
|
||||
enable_syno_token: "yes",
|
||||
},
|
||||
timeout: this.access.timeout * 1000 || 30000,
|
||||
skipSslVerify: this.skipSslVerify ?? true,
|
||||
});
|
||||
|
||||
if (!res.success) {
|
||||
throw new Error(`登录失败: `, res.error);
|
||||
}
|
||||
this.logger.info("登录成功");
|
||||
|
||||
this.token = res.data as SynologyAccessToken;
|
||||
return this.token;
|
||||
}
|
||||
|
||||
async doRequest(req: SynologyRequest) {
|
||||
const sid = this.token.sid;
|
||||
const method = req.method || "POST";
|
||||
const params = {
|
||||
...req.apiParams,
|
||||
_sid: sid, // 使用登录后获得的 session ID
|
||||
...req.params,
|
||||
SynoToken: this.token.synotoken,
|
||||
};
|
||||
|
||||
const res = await this.http.request({
|
||||
url: `${this.access.baseUrl}/webapi/entry.cgi?${qs.stringify(params)}`,
|
||||
method,
|
||||
data: req.data,
|
||||
headers: req.headers,
|
||||
skipSslVerify: this.skipSslVerify ?? true,
|
||||
timeout: this.access.timeout * 1000 || 30000,
|
||||
});
|
||||
if (!res.success) {
|
||||
throw new Error(`API 调用失败: ${JSON.stringify(res.error)}`);
|
||||
}
|
||||
return res.data;
|
||||
}
|
||||
|
||||
async getCertList() {
|
||||
this.logger.info("获取证书列表");
|
||||
return await this.doRequest({
|
||||
method: "GET",
|
||||
apiParams: {
|
||||
api: "SYNO.Core.Certificate.CRT",
|
||||
version: 1,
|
||||
method: "list",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async getInfo() {
|
||||
this.logger.info("获取信息");
|
||||
return await this.doRequest({
|
||||
method: "GET",
|
||||
apiParams: {
|
||||
api: "SYNO.API.Info",
|
||||
version: 1,
|
||||
method: "query",
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
+6
-58
@@ -1,11 +1,9 @@
|
||||
import { IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from "@certd/pipeline";
|
||||
import { CertInfo, CertReader } from "@certd/plugin-cert";
|
||||
import { CertInfo } from "@certd/plugin-lib";
|
||||
import { AbstractPlusTaskPlugin } from "@certd/plugin-lib";
|
||||
import { SynologyClient } from "../client.js";
|
||||
import fs from "fs";
|
||||
import FormData from "form-data";
|
||||
import { SynologyClient } from "@certd/plugin-plus";
|
||||
import { SynologyAccess } from "../access.js";
|
||||
import { CertApplyPluginNames } from "@certd/plugin-cert";
|
||||
import { CertApplyPluginNames } from "@certd/plugin-lib";
|
||||
@IsTaskPlugin({
|
||||
name: "SynologyDeployToPanel",
|
||||
title: "群晖-部署证书到群晖面板",
|
||||
@@ -74,66 +72,16 @@ export class SynologyDeployToPanel extends AbstractPlusTaskPlugin {
|
||||
throw new Error(`未找到证书: ${this.certName}`);
|
||||
}
|
||||
this.logger.info(`找到证书: ${certItem.id}`);
|
||||
await this.updateCertToPanel(client, certItem);
|
||||
await client.updateCertToPanel(certItem,this.cert);
|
||||
} else {
|
||||
this.logger.info("开始更新全部证书");
|
||||
for (const item of certListRes.certificates) {
|
||||
this.logger.info(`更新证书: ${item.id}`);
|
||||
await this.updateCertToPanel(client, item);
|
||||
await client.updateCertToPanel(item,this.cert);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async updateCertToPanel(client: SynologyClient, certItem: any) {
|
||||
/**
|
||||
* query
|
||||
* api: SYNO.Core.Certificate
|
||||
* method: import
|
||||
* version: 1
|
||||
* SynoToken: Bvum9p7BNeSc6
|
||||
*
|
||||
* key: (二进制)
|
||||
* cert: (二进制)
|
||||
* inter_cert: (二进制)
|
||||
* id: yxTtcC
|
||||
* desc: certd
|
||||
* as_default:
|
||||
*/
|
||||
this.logger.info(`更新证书:${certItem.id}`);
|
||||
const certReader = new CertReader(this.cert);
|
||||
|
||||
return certReader.readCertFile({
|
||||
logger: this.logger,
|
||||
handle: async (ctx) => {
|
||||
const form = new FormData();
|
||||
const { tmpCrtPath, tmpKeyPath, tmpIcPath } = ctx;
|
||||
this.logger.info(`上传证书:${tmpCrtPath},${tmpKeyPath}`);
|
||||
form.append("key", fs.createReadStream(tmpKeyPath));
|
||||
form.append("cert", fs.createReadStream(tmpCrtPath));
|
||||
if (certReader.cert.ic) {
|
||||
this.logger.info(`包含中间证书:${tmpIcPath}`);
|
||||
form.append("inter_cert", fs.createReadStream(tmpIcPath));
|
||||
}
|
||||
form.append("id", certItem.id);
|
||||
form.append("desc", certItem.desc);
|
||||
// form传输必须是string,bool要改成string
|
||||
// form.append("as_default", certItem.is_default + "");
|
||||
|
||||
console.log(JSON.stringify(form.getHeaders()));
|
||||
return await client.doRequest({
|
||||
method: "POST",
|
||||
apiParams: {
|
||||
api: "SYNO.Core.Certificate",
|
||||
version: 1,
|
||||
method: "import",
|
||||
},
|
||||
data: form,
|
||||
headers: {
|
||||
...form.getHeaders(),
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
new SynologyDeployToPanel();
|
||||
|
||||
Reference in New Issue
Block a user