@certd/plugin-lib 1.37.17 → 1.38.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/dist/cert/cert-reader.d.ts +62 -0
- package/dist/cert/cert-reader.js +205 -0
- package/dist/cert/consts.d.ts +2 -0
- package/dist/cert/consts.js +2 -0
- package/dist/cert/convert.d.ts +24 -0
- package/dist/cert/convert.js +122 -0
- package/dist/cert/dns-provider/api.d.ts +76 -0
- package/dist/cert/dns-provider/api.js +1 -0
- package/dist/cert/dns-provider/base.d.ts +27 -0
- package/dist/cert/dns-provider/base.js +48 -0
- package/dist/cert/dns-provider/decorator.d.ts +3 -0
- package/dist/cert/dns-provider/decorator.js +20 -0
- package/dist/cert/dns-provider/domain-parser.d.ts +9 -0
- package/dist/cert/dns-provider/domain-parser.js +63 -0
- package/dist/cert/dns-provider/index.d.ts +5 -0
- package/dist/cert/dns-provider/index.js +5 -0
- package/dist/cert/dns-provider/registry.d.ts +1 -0
- package/dist/cert/dns-provider/registry.js +2 -0
- package/dist/cert/index.d.ts +4 -0
- package/dist/cert/index.js +4 -0
- package/dist/common/index.js +0 -1
- package/dist/common/util.js +0 -1
- package/dist/index.d.ts +1 -8
- package/dist/index.js +1 -9
- package/dist/lib/check.d.ts +6 -0
- package/dist/lib/check.js +13 -0
- package/dist/lib/index.d.ts +1 -0
- package/dist/lib/index.js +1 -1
- package/dist/lib/ocr-api.js +0 -1
- package/dist/service/index.js +0 -1
- package/dist/service/site-info.js +0 -1
- package/package.json +13 -9
- package/tsconfig.json +2 -1
- package/dist/aliyun/access/aliesa-access.d.ts +0 -5
- package/dist/aliyun/access/aliesa-access.js +0 -61
- package/dist/aliyun/access/alioss-access.d.ts +0 -6
- package/dist/aliyun/access/alioss-access.js +0 -89
- package/dist/aliyun/access/aliyun-access.d.ts +0 -30
- package/dist/aliyun/access/aliyun-access.js +0 -126
- package/dist/aliyun/access/index.d.ts +0 -3
- package/dist/aliyun/access/index.js +0 -4
- package/dist/aliyun/index.d.ts +0 -2
- package/dist/aliyun/index.js +0 -3
- package/dist/aliyun/lib/base-client.d.ts +0 -16
- package/dist/aliyun/lib/base-client.js +0 -67
- package/dist/aliyun/lib/index.d.ts +0 -3
- package/dist/aliyun/lib/index.js +0 -4
- package/dist/aliyun/lib/oss-client.d.ts +0 -19
- package/dist/aliyun/lib/oss-client.js +0 -76
- package/dist/aliyun/lib/ssl-client.d.ts +0 -49
- package/dist/aliyun/lib/ssl-client.js +0 -133
- package/dist/ctyun/access/ctyun-access.d.ts +0 -5
- package/dist/ctyun/access/ctyun-access.js +0 -49
- package/dist/ctyun/index.d.ts +0 -1
- package/dist/ctyun/index.js +0 -2
- package/dist/ftp/access.d.ts +0 -12
- package/dist/ftp/access.js +0 -99
- package/dist/ftp/client.d.ts +0 -16
- package/dist/ftp/client.js +0 -57
- package/dist/ftp/index.d.ts +0 -2
- package/dist/ftp/index.js +0 -3
- package/dist/oss/api.d.ts +0 -46
- package/dist/oss/api.js +0 -48
- package/dist/oss/factory.d.ts +0 -10
- package/dist/oss/factory.js +0 -46
- package/dist/oss/impls/alioss.d.ts +0 -13
- package/dist/oss/impls/alioss.js +0 -55
- package/dist/oss/impls/ftp.d.ts +0 -12
- package/dist/oss/impls/ftp.js +0 -75
- package/dist/oss/impls/qiniuoss.d.ts +0 -13
- package/dist/oss/impls/qiniuoss.js +0 -47
- package/dist/oss/impls/s3.d.ts +0 -13
- package/dist/oss/impls/s3.js +0 -92
- package/dist/oss/impls/sftp.d.ts +0 -10
- package/dist/oss/impls/sftp.js +0 -79
- package/dist/oss/impls/ssh.d.ts +0 -11
- package/dist/oss/impls/ssh.js +0 -59
- package/dist/oss/impls/tencentcos.d.ts +0 -13
- package/dist/oss/impls/tencentcos.js +0 -51
- package/dist/oss/index.d.ts +0 -2
- package/dist/oss/index.js +0 -3
- package/dist/qiniu/access-oss.d.ts +0 -5
- package/dist/qiniu/access-oss.js +0 -47
- package/dist/qiniu/access.d.ts +0 -5
- package/dist/qiniu/access.js +0 -43
- package/dist/qiniu/index.d.ts +0 -3
- package/dist/qiniu/index.js +0 -4
- package/dist/qiniu/lib/sdk.d.ts +0 -34
- package/dist/qiniu/lib/sdk.js +0 -162
- package/dist/s3/access.d.ts +0 -25
- package/dist/s3/access.js +0 -134
- package/dist/s3/index.d.ts +0 -1
- package/dist/s3/index.js +0 -2
- package/dist/ssh/index.d.ts +0 -3
- package/dist/ssh/index.js +0 -4
- package/dist/ssh/sftp-access.d.ts +0 -5
- package/dist/ssh/sftp-access.js +0 -51
- package/dist/ssh/ssh-access.d.ts +0 -17
- package/dist/ssh/ssh-access.js +0 -214
- package/dist/ssh/ssh.d.ts +0 -138
- package/dist/ssh/ssh.js +0 -589
- package/dist/tencent/access-cos.d.ts +0 -6
- package/dist/tencent/access-cos.js +0 -83
- package/dist/tencent/access.d.ts +0 -10
- package/dist/tencent/access.js +0 -90
- package/dist/tencent/index.d.ts +0 -3
- package/dist/tencent/index.js +0 -4
- package/dist/tencent/lib/cos-client.d.ts +0 -19
- package/dist/tencent/lib/cos-client.js +0 -98
- package/dist/tencent/lib/index.d.ts +0 -2
- package/dist/tencent/lib/index.js +0 -3
- package/dist/tencent/lib/ssl-client.d.ts +0 -32
- package/dist/tencent/lib/ssl-client.js +0 -86
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,12 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# [1.38.0](https://github.com/certd/certd/compare/v1.37.17...v1.38.0) (2026-01-13)
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* 【破坏性更新】插件改为metadata加载模式,plugin-cert、plugin-lib包部分代码转移到certd-server中,影响自定义插件,需要修改相关import引用 ([a3fb249](https://github.com/certd/certd/commit/a3fb24993d7ac8fbb0bb354fa02ef067f609021e))
|
|
11
|
+
|
|
6
12
|
## [1.37.17](https://github.com/certd/certd/compare/v1.37.16...v1.37.17) (2025-12-29)
|
|
7
13
|
|
|
8
14
|
**Note:** Version bump only for package @certd/plugin-lib
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { CertificateInfo } from "@certd/acme-client";
|
|
2
|
+
import { ILogger } from "@certd/basic";
|
|
3
|
+
export type CertInfo = {
|
|
4
|
+
crt: string;
|
|
5
|
+
key: string;
|
|
6
|
+
csr: string;
|
|
7
|
+
oc?: string;
|
|
8
|
+
ic?: string;
|
|
9
|
+
pfx?: string;
|
|
10
|
+
der?: string;
|
|
11
|
+
jks?: string;
|
|
12
|
+
one?: string;
|
|
13
|
+
p7b?: string;
|
|
14
|
+
};
|
|
15
|
+
export type CertReaderHandleContext = {
|
|
16
|
+
reader: CertReader;
|
|
17
|
+
tmpCrtPath: string;
|
|
18
|
+
tmpKeyPath: string;
|
|
19
|
+
tmpOcPath?: string;
|
|
20
|
+
tmpPfxPath?: string;
|
|
21
|
+
tmpDerPath?: string;
|
|
22
|
+
tmpIcPath?: string;
|
|
23
|
+
tmpJksPath?: string;
|
|
24
|
+
tmpOnePath?: string;
|
|
25
|
+
tmpP7bPath?: string;
|
|
26
|
+
};
|
|
27
|
+
export type CertReaderHandle = (ctx: CertReaderHandleContext) => Promise<void>;
|
|
28
|
+
export type HandleOpts = {
|
|
29
|
+
logger: ILogger;
|
|
30
|
+
handle: CertReaderHandle;
|
|
31
|
+
};
|
|
32
|
+
export declare class CertReader {
|
|
33
|
+
cert: CertInfo;
|
|
34
|
+
detail: CertificateInfo;
|
|
35
|
+
effective: number;
|
|
36
|
+
expires: number;
|
|
37
|
+
constructor(certInfo: CertInfo);
|
|
38
|
+
getIc(): string;
|
|
39
|
+
getOc(): string;
|
|
40
|
+
toCertInfo(format?: string): CertInfo;
|
|
41
|
+
getCrtDetail(crt?: string): {
|
|
42
|
+
detail: CertificateInfo;
|
|
43
|
+
effective: Date;
|
|
44
|
+
expires: Date;
|
|
45
|
+
};
|
|
46
|
+
static readCertDetail(crt: string): {
|
|
47
|
+
detail: CertificateInfo;
|
|
48
|
+
effective: Date;
|
|
49
|
+
expires: Date;
|
|
50
|
+
};
|
|
51
|
+
getAllDomains(): any;
|
|
52
|
+
getAltNames(): string[];
|
|
53
|
+
static getMainDomain(crt: string): string;
|
|
54
|
+
getMainDomain(): string;
|
|
55
|
+
static getMainDomainFromDetail(detail: CertificateInfo): string;
|
|
56
|
+
saveToFile(type: "crt" | "key" | "pfx" | "der" | "oc" | "one" | "ic" | "jks" | "p7b", filepath?: string): string;
|
|
57
|
+
readCertFile(opts: HandleOpts): Promise<void>;
|
|
58
|
+
buildCertFileName(suffix: string, applyTime: any, prefix?: string): string;
|
|
59
|
+
buildCertName(prefix?: string): string;
|
|
60
|
+
static appendTimeSuffix(name?: string): string;
|
|
61
|
+
static buildCertName(cert: any): string;
|
|
62
|
+
}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import os from "os";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import { crypto } from "@certd/acme-client";
|
|
5
|
+
import dayjs from "dayjs";
|
|
6
|
+
import { uniq } from "lodash-es";
|
|
7
|
+
const formats = {
|
|
8
|
+
pem: ["crt", "key", "ic"],
|
|
9
|
+
one: ["one"],
|
|
10
|
+
pfx: ["pfx"],
|
|
11
|
+
der: ["der"],
|
|
12
|
+
jks: ["jks"],
|
|
13
|
+
p7b: ["p7b", "key"],
|
|
14
|
+
};
|
|
15
|
+
export class CertReader {
|
|
16
|
+
cert;
|
|
17
|
+
detail;
|
|
18
|
+
//毫秒时间戳
|
|
19
|
+
effective;
|
|
20
|
+
//毫秒时间戳
|
|
21
|
+
expires;
|
|
22
|
+
constructor(certInfo) {
|
|
23
|
+
this.cert = certInfo;
|
|
24
|
+
if (!certInfo.ic) {
|
|
25
|
+
this.cert.ic = this.getIc();
|
|
26
|
+
}
|
|
27
|
+
if (!certInfo.oc) {
|
|
28
|
+
this.cert.oc = this.getOc();
|
|
29
|
+
}
|
|
30
|
+
if (!certInfo.one) {
|
|
31
|
+
this.cert.one = this.cert.crt + "\n" + this.cert.key;
|
|
32
|
+
}
|
|
33
|
+
try {
|
|
34
|
+
const { detail, effective, expires } = this.getCrtDetail(this.cert.crt);
|
|
35
|
+
this.detail = detail;
|
|
36
|
+
this.effective = effective.getTime();
|
|
37
|
+
this.expires = expires.getTime();
|
|
38
|
+
}
|
|
39
|
+
catch (e) {
|
|
40
|
+
throw new Error("证书解析失败:" + e.message);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
getIc() {
|
|
44
|
+
//中间证书ic, 就是crt的第一个 -----END CERTIFICATE----- 之后的内容
|
|
45
|
+
const endStr = "-----END CERTIFICATE-----";
|
|
46
|
+
const firstBlockEndIndex = this.cert.crt.indexOf(endStr);
|
|
47
|
+
const start = firstBlockEndIndex + endStr.length + 1;
|
|
48
|
+
if (this.cert.crt.length <= start) {
|
|
49
|
+
return "";
|
|
50
|
+
}
|
|
51
|
+
const ic = this.cert.crt.substring(start);
|
|
52
|
+
if (ic == null) {
|
|
53
|
+
return "";
|
|
54
|
+
}
|
|
55
|
+
return ic?.trim();
|
|
56
|
+
}
|
|
57
|
+
getOc() {
|
|
58
|
+
//原始证书 就是crt的第一个 -----END CERTIFICATE----- 之前的内容
|
|
59
|
+
const endStr = "-----END CERTIFICATE-----";
|
|
60
|
+
const arr = this.cert.crt.split(endStr);
|
|
61
|
+
return arr[0] + endStr;
|
|
62
|
+
}
|
|
63
|
+
toCertInfo(format) {
|
|
64
|
+
if (!format) {
|
|
65
|
+
return this.cert;
|
|
66
|
+
}
|
|
67
|
+
const formatArr = formats[format];
|
|
68
|
+
const res = {};
|
|
69
|
+
formatArr.forEach((key) => {
|
|
70
|
+
res[key] = this.cert[key];
|
|
71
|
+
});
|
|
72
|
+
return res;
|
|
73
|
+
}
|
|
74
|
+
getCrtDetail(crt = this.cert.crt) {
|
|
75
|
+
return CertReader.readCertDetail(crt);
|
|
76
|
+
}
|
|
77
|
+
static readCertDetail(crt) {
|
|
78
|
+
const detail = crypto.readCertificateInfo(crt.toString());
|
|
79
|
+
const effective = detail.notBefore;
|
|
80
|
+
const expires = detail.notAfter;
|
|
81
|
+
return { detail, effective, expires };
|
|
82
|
+
}
|
|
83
|
+
getAllDomains() {
|
|
84
|
+
const { detail } = this.getCrtDetail();
|
|
85
|
+
const domains = [];
|
|
86
|
+
if (detail.domains?.commonName) {
|
|
87
|
+
domains.push(detail.domains.commonName);
|
|
88
|
+
}
|
|
89
|
+
domains.push(...detail.domains.altNames);
|
|
90
|
+
//去重
|
|
91
|
+
return uniq(domains);
|
|
92
|
+
}
|
|
93
|
+
getAltNames() {
|
|
94
|
+
const { detail } = this.getCrtDetail();
|
|
95
|
+
return detail.domains.altNames;
|
|
96
|
+
}
|
|
97
|
+
static getMainDomain(crt) {
|
|
98
|
+
const { detail } = CertReader.readCertDetail(crt);
|
|
99
|
+
return CertReader.getMainDomainFromDetail(detail);
|
|
100
|
+
}
|
|
101
|
+
getMainDomain() {
|
|
102
|
+
const { detail } = this.getCrtDetail();
|
|
103
|
+
return CertReader.getMainDomainFromDetail(detail);
|
|
104
|
+
}
|
|
105
|
+
static getMainDomainFromDetail(detail) {
|
|
106
|
+
let domain = detail?.domains?.commonName;
|
|
107
|
+
if (domain == null) {
|
|
108
|
+
domain = detail?.domains?.altNames?.[0];
|
|
109
|
+
}
|
|
110
|
+
if (domain == null) {
|
|
111
|
+
domain = "unknown";
|
|
112
|
+
}
|
|
113
|
+
return domain;
|
|
114
|
+
}
|
|
115
|
+
saveToFile(type, filepath) {
|
|
116
|
+
if (!this.cert[type]) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
if (filepath == null) {
|
|
120
|
+
//写入临时目录
|
|
121
|
+
filepath = path.join(os.tmpdir(), "/certd/tmp/", Math.floor(Math.random() * 1000000) + `_cert.${type}`);
|
|
122
|
+
}
|
|
123
|
+
const dir = path.dirname(filepath);
|
|
124
|
+
if (!fs.existsSync(dir)) {
|
|
125
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
126
|
+
}
|
|
127
|
+
if (type === "crt" || type === "key" || type === "ic" || type === "oc" || type === "one" || type === "p7b") {
|
|
128
|
+
fs.writeFileSync(filepath, this.cert[type]);
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
fs.writeFileSync(filepath, Buffer.from(this.cert[type], "base64"));
|
|
132
|
+
}
|
|
133
|
+
return filepath;
|
|
134
|
+
}
|
|
135
|
+
async readCertFile(opts) {
|
|
136
|
+
const logger = opts.logger;
|
|
137
|
+
logger.info("将证书写入本地缓存文件");
|
|
138
|
+
const tmpCrtPath = this.saveToFile("crt");
|
|
139
|
+
const tmpKeyPath = this.saveToFile("key");
|
|
140
|
+
const tmpPfxPath = this.saveToFile("pfx");
|
|
141
|
+
const tmpIcPath = this.saveToFile("ic");
|
|
142
|
+
const tmpOcPath = this.saveToFile("oc");
|
|
143
|
+
const tmpDerPath = this.saveToFile("der");
|
|
144
|
+
const tmpJksPath = this.saveToFile("jks");
|
|
145
|
+
const tmpOnePath = this.saveToFile("one");
|
|
146
|
+
const tmpP7bPath = this.saveToFile("p7b");
|
|
147
|
+
logger.info("本地文件写入成功");
|
|
148
|
+
try {
|
|
149
|
+
return await opts.handle({
|
|
150
|
+
reader: this,
|
|
151
|
+
tmpCrtPath,
|
|
152
|
+
tmpKeyPath,
|
|
153
|
+
tmpPfxPath,
|
|
154
|
+
tmpDerPath,
|
|
155
|
+
tmpIcPath,
|
|
156
|
+
tmpJksPath,
|
|
157
|
+
tmpOcPath,
|
|
158
|
+
tmpP7bPath,
|
|
159
|
+
tmpOnePath,
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
catch (err) {
|
|
163
|
+
logger.error("处理失败", err);
|
|
164
|
+
throw err;
|
|
165
|
+
}
|
|
166
|
+
finally {
|
|
167
|
+
//删除临时文件
|
|
168
|
+
logger.info("清理临时文件");
|
|
169
|
+
function removeFile(filepath) {
|
|
170
|
+
if (filepath) {
|
|
171
|
+
fs.unlinkSync(filepath);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
removeFile(tmpCrtPath);
|
|
175
|
+
removeFile(tmpKeyPath);
|
|
176
|
+
removeFile(tmpPfxPath);
|
|
177
|
+
removeFile(tmpOcPath);
|
|
178
|
+
removeFile(tmpDerPath);
|
|
179
|
+
removeFile(tmpIcPath);
|
|
180
|
+
removeFile(tmpJksPath);
|
|
181
|
+
removeFile(tmpOnePath);
|
|
182
|
+
removeFile(tmpP7bPath);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
buildCertFileName(suffix, applyTime, prefix = "cert") {
|
|
186
|
+
let domain = this.getMainDomain();
|
|
187
|
+
domain = domain.replaceAll(".", "_").replaceAll("*", "_");
|
|
188
|
+
const timeStr = dayjs(applyTime).format("YYYYMMDDHHmmss");
|
|
189
|
+
return `${prefix}_${domain}_${timeStr}.${suffix}`;
|
|
190
|
+
}
|
|
191
|
+
buildCertName(prefix = "") {
|
|
192
|
+
let domain = this.getMainDomain();
|
|
193
|
+
domain = domain.replaceAll(".", "_").replaceAll("*", "_");
|
|
194
|
+
return `${prefix}_${domain}_${dayjs().format("YYYYMMDDHHmmssSSS")}`;
|
|
195
|
+
}
|
|
196
|
+
static appendTimeSuffix(name) {
|
|
197
|
+
if (name == null) {
|
|
198
|
+
name = "certd";
|
|
199
|
+
}
|
|
200
|
+
return name + "_" + dayjs().format("YYYYMMDDHHmmssSSS");
|
|
201
|
+
}
|
|
202
|
+
static buildCertName(cert) {
|
|
203
|
+
return new CertReader(cert).buildCertName();
|
|
204
|
+
}
|
|
205
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ILogger } from "@certd/basic";
|
|
2
|
+
import type { CertInfo } from "./cert-reader.js";
|
|
3
|
+
import { CertReaderHandleContext } from "./cert-reader.js";
|
|
4
|
+
export declare class CertConverter {
|
|
5
|
+
logger: ILogger;
|
|
6
|
+
constructor(opts: {
|
|
7
|
+
logger: ILogger;
|
|
8
|
+
});
|
|
9
|
+
convert(opts: {
|
|
10
|
+
cert: CertInfo;
|
|
11
|
+
pfxPassword: string;
|
|
12
|
+
pfxArgs: string;
|
|
13
|
+
}): Promise<{
|
|
14
|
+
pfx: string;
|
|
15
|
+
der: string;
|
|
16
|
+
jks: string;
|
|
17
|
+
p7b: string;
|
|
18
|
+
}>;
|
|
19
|
+
exec(cmd: string): Promise<void>;
|
|
20
|
+
private convertPfx;
|
|
21
|
+
private convertDer;
|
|
22
|
+
convertP7b(opts: CertReaderHandleContext): Promise<string>;
|
|
23
|
+
convertJks(opts: CertReaderHandleContext, pfxPassword?: string): Promise<string>;
|
|
24
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { sp } from "@certd/basic";
|
|
2
|
+
import { CertReader } from "./cert-reader.js";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import os from "os";
|
|
5
|
+
import fs from "fs";
|
|
6
|
+
export class CertConverter {
|
|
7
|
+
logger;
|
|
8
|
+
constructor(opts) {
|
|
9
|
+
this.logger = opts.logger;
|
|
10
|
+
}
|
|
11
|
+
async convert(opts) {
|
|
12
|
+
const certReader = new CertReader(opts.cert);
|
|
13
|
+
let pfx;
|
|
14
|
+
let der;
|
|
15
|
+
let jks;
|
|
16
|
+
let p7b;
|
|
17
|
+
const handle = async (ctx) => {
|
|
18
|
+
// 调用openssl 转pfx
|
|
19
|
+
pfx = await this.convertPfx(ctx, opts.pfxPassword, opts.pfxArgs);
|
|
20
|
+
// 转der
|
|
21
|
+
der = await this.convertDer(ctx);
|
|
22
|
+
jks = await this.convertJks(ctx, opts.pfxPassword);
|
|
23
|
+
p7b = await this.convertP7b(ctx);
|
|
24
|
+
};
|
|
25
|
+
await certReader.readCertFile({ logger: this.logger, handle });
|
|
26
|
+
return {
|
|
27
|
+
pfx,
|
|
28
|
+
der,
|
|
29
|
+
jks,
|
|
30
|
+
p7b,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
async exec(cmd) {
|
|
34
|
+
process.env.LANG = "zh_CN.GBK";
|
|
35
|
+
await sp.spawn({
|
|
36
|
+
cmd: cmd,
|
|
37
|
+
logger: this.logger,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
async convertPfx(opts, pfxPassword, pfxArgs) {
|
|
41
|
+
const { tmpCrtPath, tmpKeyPath } = opts;
|
|
42
|
+
const pfxPath = path.join(os.tmpdir(), "/certd/tmp/", Math.floor(Math.random() * 1000000) + "_cert.pfx");
|
|
43
|
+
const dir = path.dirname(pfxPath);
|
|
44
|
+
if (!fs.existsSync(dir)) {
|
|
45
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
46
|
+
}
|
|
47
|
+
let passwordArg = "-passout pass:";
|
|
48
|
+
if (pfxPassword) {
|
|
49
|
+
passwordArg = `-password pass:${pfxPassword}`;
|
|
50
|
+
}
|
|
51
|
+
// 兼容server 2016,旧版本不能用sha256
|
|
52
|
+
const oldPfxCmd = `openssl pkcs12 ${pfxArgs} -export -out ${pfxPath} -inkey ${tmpKeyPath} -in ${tmpCrtPath} ${passwordArg}`;
|
|
53
|
+
// const newPfx = `openssl pkcs12 -export -out ${pfxPath} -inkey ${tmpKeyPath} -in ${tmpCrtPath} ${passwordArg}`;
|
|
54
|
+
await this.exec(oldPfxCmd);
|
|
55
|
+
const fileBuffer = fs.readFileSync(pfxPath);
|
|
56
|
+
const pfxCert = fileBuffer.toString("base64");
|
|
57
|
+
fs.unlinkSync(pfxPath);
|
|
58
|
+
return pfxCert;
|
|
59
|
+
//
|
|
60
|
+
// const applyTime = new Date().getTime();
|
|
61
|
+
// const filename = reader.buildCertFileName("pfx", applyTime);
|
|
62
|
+
// this.saveFile(filename, fileBuffer);
|
|
63
|
+
}
|
|
64
|
+
async convertDer(opts) {
|
|
65
|
+
const { tmpCrtPath } = opts;
|
|
66
|
+
const derPath = path.join(os.tmpdir(), "/certd/tmp/", Math.floor(Math.random() * 1000000) + `_cert.der`);
|
|
67
|
+
const dir = path.dirname(derPath);
|
|
68
|
+
if (!fs.existsSync(dir)) {
|
|
69
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
70
|
+
}
|
|
71
|
+
await this.exec(`openssl x509 -outform der -in ${tmpCrtPath} -out ${derPath}`);
|
|
72
|
+
const fileBuffer = fs.readFileSync(derPath);
|
|
73
|
+
const derCert = fileBuffer.toString("base64");
|
|
74
|
+
fs.unlinkSync(derPath);
|
|
75
|
+
return derCert;
|
|
76
|
+
}
|
|
77
|
+
async convertP7b(opts) {
|
|
78
|
+
const { tmpCrtPath } = opts;
|
|
79
|
+
const p7bPath = path.join(os.tmpdir(), "/certd/tmp/", Math.floor(Math.random() * 1000000) + `_cert.p7b`);
|
|
80
|
+
const dir = path.dirname(p7bPath);
|
|
81
|
+
if (!fs.existsSync(dir)) {
|
|
82
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
83
|
+
}
|
|
84
|
+
//openssl crl2pkcs7 -nocrl \
|
|
85
|
+
// -certfile your_domain.crt \
|
|
86
|
+
// -certfile intermediate.crt \
|
|
87
|
+
// -out chain.p7b
|
|
88
|
+
await this.exec(`openssl crl2pkcs7 -nocrl -certfile ${tmpCrtPath} -out ${p7bPath}`);
|
|
89
|
+
const fileBuffer = fs.readFileSync(p7bPath);
|
|
90
|
+
const p7bCert = fileBuffer.toString();
|
|
91
|
+
fs.unlinkSync(p7bPath);
|
|
92
|
+
return p7bCert;
|
|
93
|
+
}
|
|
94
|
+
async convertJks(opts, pfxPassword = "") {
|
|
95
|
+
const jksPassword = pfxPassword || "123456";
|
|
96
|
+
try {
|
|
97
|
+
const randomStr = Math.floor(Math.random() * 1000000) + "";
|
|
98
|
+
const p12Path = path.join(os.tmpdir(), "/certd/tmp/", randomStr + `_cert.p12`);
|
|
99
|
+
const { tmpCrtPath, tmpKeyPath } = opts;
|
|
100
|
+
let passwordArg = "-passout pass:";
|
|
101
|
+
if (jksPassword) {
|
|
102
|
+
passwordArg = `-password pass:${jksPassword}`;
|
|
103
|
+
}
|
|
104
|
+
await this.exec(`openssl pkcs12 -export -in ${tmpCrtPath} -inkey ${tmpKeyPath} -out ${p12Path} -name certd ${passwordArg}`);
|
|
105
|
+
const jksPath = path.join(os.tmpdir(), "/certd/tmp/", randomStr + `_cert.jks`);
|
|
106
|
+
const dir = path.dirname(jksPath);
|
|
107
|
+
if (!fs.existsSync(dir)) {
|
|
108
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
109
|
+
}
|
|
110
|
+
await this.exec(`keytool -importkeystore -srckeystore ${p12Path} -srcstoretype PKCS12 -srcstorepass "${jksPassword}" -destkeystore ${jksPath} -deststoretype PKCS12 -deststorepass "${jksPassword}" `);
|
|
111
|
+
fs.unlinkSync(p12Path);
|
|
112
|
+
const fileBuffer = fs.readFileSync(jksPath);
|
|
113
|
+
const certBase64 = fileBuffer.toString("base64");
|
|
114
|
+
fs.unlinkSync(jksPath);
|
|
115
|
+
return certBase64;
|
|
116
|
+
}
|
|
117
|
+
catch (e) {
|
|
118
|
+
this.logger.error("转换jks失败", e);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { HttpClient, ILogger, utils } from "@certd/basic";
|
|
2
|
+
import { IAccess, IServiceGetter, Registrable } from "@certd/pipeline";
|
|
3
|
+
export type DnsProviderDefine = Registrable & {
|
|
4
|
+
accessType: string;
|
|
5
|
+
icon?: string;
|
|
6
|
+
};
|
|
7
|
+
export type CreateRecordOptions = {
|
|
8
|
+
domain: string;
|
|
9
|
+
fullRecord: string;
|
|
10
|
+
hostRecord: string;
|
|
11
|
+
type: string;
|
|
12
|
+
value: any;
|
|
13
|
+
};
|
|
14
|
+
export type RemoveRecordOptions<T> = {
|
|
15
|
+
recordReq: CreateRecordOptions;
|
|
16
|
+
recordRes: T;
|
|
17
|
+
};
|
|
18
|
+
export type DnsProviderContext = {
|
|
19
|
+
access: IAccess;
|
|
20
|
+
logger: ILogger;
|
|
21
|
+
http: HttpClient;
|
|
22
|
+
utils: typeof utils;
|
|
23
|
+
domainParser: IDomainParser;
|
|
24
|
+
serviceGetter: IServiceGetter;
|
|
25
|
+
};
|
|
26
|
+
export interface IDnsProvider<T = any> {
|
|
27
|
+
onInstance(): Promise<void>;
|
|
28
|
+
/**
|
|
29
|
+
* 中文转英文
|
|
30
|
+
* @param domain
|
|
31
|
+
*/
|
|
32
|
+
punyCodeEncode(domain: string): string;
|
|
33
|
+
/**
|
|
34
|
+
* 转中文域名
|
|
35
|
+
* @param domain
|
|
36
|
+
*/
|
|
37
|
+
punyCodeDecode(domain: string): string;
|
|
38
|
+
createRecord(options: CreateRecordOptions): Promise<T>;
|
|
39
|
+
removeRecord(options: RemoveRecordOptions<T>): Promise<void>;
|
|
40
|
+
setCtx(ctx: DnsProviderContext): void;
|
|
41
|
+
usePunyCode(): boolean;
|
|
42
|
+
}
|
|
43
|
+
export interface ISubDomainsGetter {
|
|
44
|
+
getSubDomains(): Promise<string[]>;
|
|
45
|
+
}
|
|
46
|
+
export interface IDomainParser {
|
|
47
|
+
parse(fullDomain: string): Promise<string>;
|
|
48
|
+
}
|
|
49
|
+
export type DnsVerifier = {
|
|
50
|
+
dnsProviderType?: string;
|
|
51
|
+
dnsProviderAccessId?: number;
|
|
52
|
+
};
|
|
53
|
+
export type CnameVerifier = {
|
|
54
|
+
hostRecord: string;
|
|
55
|
+
domain: string;
|
|
56
|
+
recordValue: string;
|
|
57
|
+
};
|
|
58
|
+
export type HttpVerifier = {
|
|
59
|
+
httpUploaderType: string;
|
|
60
|
+
httpUploaderAccess: number;
|
|
61
|
+
httpUploadRootDir: string;
|
|
62
|
+
};
|
|
63
|
+
export type DomainVerifier = {
|
|
64
|
+
domain: string;
|
|
65
|
+
mainDomain: string;
|
|
66
|
+
type: string;
|
|
67
|
+
dns?: DnsVerifier;
|
|
68
|
+
cname?: CnameVerifier;
|
|
69
|
+
http?: HttpVerifier;
|
|
70
|
+
};
|
|
71
|
+
export type DomainVerifiers = {
|
|
72
|
+
[key: string]: DomainVerifier;
|
|
73
|
+
};
|
|
74
|
+
export interface IDomainVerifierGetter {
|
|
75
|
+
getVerifiers(domains: string[]): Promise<DomainVerifiers>;
|
|
76
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { CreateRecordOptions, DnsProviderContext, IDnsProvider, RemoveRecordOptions } from "./api.js";
|
|
2
|
+
import { HttpClient, ILogger } from "@certd/basic";
|
|
3
|
+
export declare abstract class AbstractDnsProvider<T = any> implements IDnsProvider<T> {
|
|
4
|
+
ctx: DnsProviderContext;
|
|
5
|
+
http: HttpClient;
|
|
6
|
+
logger: ILogger;
|
|
7
|
+
usePunyCode(): boolean;
|
|
8
|
+
/**
|
|
9
|
+
* 中文转英文
|
|
10
|
+
* @param domain
|
|
11
|
+
*/
|
|
12
|
+
punyCodeEncode(domain: string): any;
|
|
13
|
+
/**
|
|
14
|
+
* 转中文域名
|
|
15
|
+
* @param domain
|
|
16
|
+
*/
|
|
17
|
+
punyCodeDecode(domain: string): any;
|
|
18
|
+
setCtx(ctx: DnsProviderContext): void;
|
|
19
|
+
parseDomain(fullDomain: string): Promise<string>;
|
|
20
|
+
abstract createRecord(options: CreateRecordOptions): Promise<T>;
|
|
21
|
+
abstract onInstance(): Promise<void>;
|
|
22
|
+
abstract removeRecord(options: RemoveRecordOptions<T>): Promise<void>;
|
|
23
|
+
}
|
|
24
|
+
export declare function createDnsProvider(opts: {
|
|
25
|
+
dnsProviderType: string;
|
|
26
|
+
context: DnsProviderContext;
|
|
27
|
+
}): Promise<IDnsProvider>;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { dnsProviderRegistry } from "./registry.js";
|
|
2
|
+
import punycode from "punycode.js";
|
|
3
|
+
export class AbstractDnsProvider {
|
|
4
|
+
ctx;
|
|
5
|
+
http;
|
|
6
|
+
logger;
|
|
7
|
+
usePunyCode() {
|
|
8
|
+
//是否使用punycode来添加解析记录
|
|
9
|
+
//默认都使用原始中文域名来添加
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* 中文转英文
|
|
14
|
+
* @param domain
|
|
15
|
+
*/
|
|
16
|
+
punyCodeEncode(domain) {
|
|
17
|
+
return punycode.toASCII(domain);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* 转中文域名
|
|
21
|
+
* @param domain
|
|
22
|
+
*/
|
|
23
|
+
punyCodeDecode(domain) {
|
|
24
|
+
return punycode.toUnicode(domain);
|
|
25
|
+
}
|
|
26
|
+
setCtx(ctx) {
|
|
27
|
+
this.ctx = ctx;
|
|
28
|
+
this.logger = ctx.logger;
|
|
29
|
+
this.http = ctx.http;
|
|
30
|
+
}
|
|
31
|
+
async parseDomain(fullDomain) {
|
|
32
|
+
return await this.ctx.domainParser.parse(fullDomain);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
export async function createDnsProvider(opts) {
|
|
36
|
+
const { dnsProviderType, context } = opts;
|
|
37
|
+
const dnsProviderPlugin = dnsProviderRegistry.get(dnsProviderType);
|
|
38
|
+
const DnsProviderClass = await dnsProviderPlugin.target();
|
|
39
|
+
const dnsProviderDefine = dnsProviderPlugin.define;
|
|
40
|
+
if (dnsProviderDefine.deprecated) {
|
|
41
|
+
context.logger.warn(dnsProviderDefine.deprecated);
|
|
42
|
+
}
|
|
43
|
+
// @ts-ignore
|
|
44
|
+
const dnsProvider = new DnsProviderClass();
|
|
45
|
+
dnsProvider.setCtx(context);
|
|
46
|
+
await dnsProvider.onInstance();
|
|
47
|
+
return dnsProvider;
|
|
48
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { dnsProviderRegistry } from "./registry.js";
|
|
2
|
+
import { Decorator } from "@certd/pipeline";
|
|
3
|
+
// 提供一个唯一 key
|
|
4
|
+
export const DNS_PROVIDER_CLASS_KEY = "pipeline:dns-provider";
|
|
5
|
+
export function IsDnsProvider(define) {
|
|
6
|
+
return (target) => {
|
|
7
|
+
if (process.env.certd_plugin_loadmode === "metadata") {
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
target = Decorator.target(target);
|
|
11
|
+
Reflect.defineMetadata(DNS_PROVIDER_CLASS_KEY, define, target);
|
|
12
|
+
target.define = define;
|
|
13
|
+
dnsProviderRegistry.register(define.name, {
|
|
14
|
+
define,
|
|
15
|
+
target: async () => {
|
|
16
|
+
return target;
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
};
|
|
20
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { IDomainParser, ISubDomainsGetter } from "./api";
|
|
2
|
+
import { ILogger } from "@certd/basic";
|
|
3
|
+
export declare class DomainParser implements IDomainParser {
|
|
4
|
+
subDomainsGetter: ISubDomainsGetter;
|
|
5
|
+
logger: ILogger;
|
|
6
|
+
constructor(subDomainsGetter: ISubDomainsGetter, logger?: ILogger);
|
|
7
|
+
parseDomainByPsl(fullDomain: string): string;
|
|
8
|
+
parse(fullDomain: string): Promise<any>;
|
|
9
|
+
}
|