@certd/plugin-cert 1.0.0 → 1.0.3
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 +16 -0
- package/dist/bundle.js +1 -0
- package/dist/plugin-cert.mjs +33826 -0
- package/dist/plugin-cert.umd.js +106 -0
- package/package.json +20 -11
- package/rollup.config.js +35 -0
- package/tsconfig.json +1 -2
- package/vite.config.ts +38 -6
- package/src/dns-provider/api.ts +0 -23
- package/src/dns-provider/decorator.ts +0 -30
- package/src/dns-provider/index.ts +0 -3
- package/src/dns-provider/registry.ts +0 -3
- package/src/index.ts +0 -2
- package/src/plugin/cert-plugin/acme.ts +0 -205
- package/src/plugin/cert-plugin/cert-reader.ts +0 -52
- package/src/plugin/cert-plugin/index.ts +0 -276
- package/src/plugin/index.ts +0 -2
package/package.json
CHANGED
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@certd/plugin-cert",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "1.0.
|
|
5
|
-
"main": "./dist/
|
|
4
|
+
"version": "1.0.3",
|
|
5
|
+
"main": "./dist/bundle.js",
|
|
6
6
|
"module": "./dist/plugin-cert.mjs",
|
|
7
7
|
"types": "./dist/es/plugin-cert.d.ts",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"dev": "vite",
|
|
10
|
+
"build": "rollup -c",
|
|
11
|
+
"build2": "vue-tsc --noEmit && vite build",
|
|
12
|
+
"preview": "vite preview"
|
|
13
|
+
},
|
|
8
14
|
"dependencies": {
|
|
9
|
-
"@certd/acme-client": "^1.0.
|
|
10
|
-
"@certd/pipeline": "^1.0.
|
|
15
|
+
"@certd/acme-client": "^1.0.3",
|
|
16
|
+
"@certd/pipeline": "^1.0.3",
|
|
11
17
|
"node-forge": "^0.10.0"
|
|
12
18
|
},
|
|
13
19
|
"devDependencies": {
|
|
@@ -16,6 +22,11 @@
|
|
|
16
22
|
"@alicloud/pop-core": "^1.7.10",
|
|
17
23
|
"@midwayjs/core": "^3.0.0",
|
|
18
24
|
"@midwayjs/decorator": "^3.0.0",
|
|
25
|
+
"@rollup/plugin-commonjs": "^23.0.4",
|
|
26
|
+
"@rollup/plugin-json": "^6.0.0",
|
|
27
|
+
"@rollup/plugin-node-resolve": "^15.0.1",
|
|
28
|
+
"@rollup/plugin-terser": "^0.4.3",
|
|
29
|
+
"@rollup/plugin-typescript": "^11.0.0",
|
|
19
30
|
"@types/chai": "^4.3.3",
|
|
20
31
|
"@types/lodash": "^4.14.186",
|
|
21
32
|
"@types/mocha": "^10.0.0",
|
|
@@ -32,15 +43,13 @@
|
|
|
32
43
|
"lodash": "^4.17.21",
|
|
33
44
|
"log4js": "^6.7.1",
|
|
34
45
|
"mocha": "^10.1.0",
|
|
46
|
+
"rollup": "^3.7.4",
|
|
47
|
+
"rollup-plugin-visualizer": "^5.8.2",
|
|
35
48
|
"ts-node": "^10.9.1",
|
|
49
|
+
"tslib": "^2.5.2",
|
|
36
50
|
"typescript": "^4.8.4",
|
|
37
51
|
"vite": "^3.1.0",
|
|
38
52
|
"vue-tsc": "^0.38.9"
|
|
39
53
|
},
|
|
40
|
-
"gitHead": "
|
|
41
|
-
|
|
42
|
-
"dev": "vite",
|
|
43
|
-
"build": "vue-tsc --noEmit && vite build",
|
|
44
|
-
"preview": "vite preview"
|
|
45
|
-
}
|
|
46
|
-
}
|
|
54
|
+
"gitHead": "a43c5b0824d2cb19a731c16f62c5e7464f6635d6"
|
|
55
|
+
}
|
package/rollup.config.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
const resolve = require("@rollup/plugin-node-resolve");
|
|
2
|
+
const commonjs = require("@rollup/plugin-commonjs");
|
|
3
|
+
const rollupTypescript = require("rollup-plugin-typescript2");
|
|
4
|
+
const json = require("@rollup/plugin-json");
|
|
5
|
+
const terser = require("@rollup/plugin-terser");
|
|
6
|
+
module.exports = {
|
|
7
|
+
input: "src/index.ts",
|
|
8
|
+
output: {
|
|
9
|
+
file: "dist/bundle.js",
|
|
10
|
+
format: "cjs",
|
|
11
|
+
},
|
|
12
|
+
plugins: [
|
|
13
|
+
// 解析第三方依赖
|
|
14
|
+
resolve(),
|
|
15
|
+
// 识别 commonjs 模式第三方依赖
|
|
16
|
+
commonjs(),
|
|
17
|
+
rollupTypescript(),
|
|
18
|
+
json(),
|
|
19
|
+
terser(),
|
|
20
|
+
],
|
|
21
|
+
external: [
|
|
22
|
+
"vue",
|
|
23
|
+
"lodash",
|
|
24
|
+
"dayjs",
|
|
25
|
+
"@certd/acme-client",
|
|
26
|
+
"@certd/pipeline",
|
|
27
|
+
"@certd/plugin-cert",
|
|
28
|
+
"@certd/plugin-aliyun",
|
|
29
|
+
"@certd/plugin-tencent",
|
|
30
|
+
"@certd/plugin-huawei",
|
|
31
|
+
"@certd/plugin-host",
|
|
32
|
+
"@certd/plugin-tencent",
|
|
33
|
+
"@certd/plugin-util",
|
|
34
|
+
],
|
|
35
|
+
};
|
package/tsconfig.json
CHANGED
package/vite.config.ts
CHANGED
|
@@ -1,22 +1,54 @@
|
|
|
1
1
|
import { defineConfig } from "vite";
|
|
2
|
+
import visualizer from "rollup-plugin-visualizer";
|
|
3
|
+
import typescript from "@rollup/plugin-typescript";
|
|
2
4
|
// https://vitejs.dev/config/
|
|
3
5
|
export default defineConfig({
|
|
4
6
|
plugins: [],
|
|
5
7
|
build: {
|
|
6
8
|
lib: {
|
|
7
9
|
entry: "src/index.ts",
|
|
8
|
-
name: "
|
|
10
|
+
name: "CertdPluginCert",
|
|
9
11
|
},
|
|
10
12
|
rollupOptions: {
|
|
11
|
-
|
|
13
|
+
plugins: [
|
|
14
|
+
// @ts-ignore
|
|
15
|
+
visualizer(),
|
|
16
|
+
// @ts-ignore
|
|
17
|
+
typescript({
|
|
18
|
+
target: "esnext",
|
|
19
|
+
rootDir: "src",
|
|
20
|
+
declaration: true,
|
|
21
|
+
declarationDir: "dist/d",
|
|
22
|
+
exclude: ["./node_modules/**", "./src/**/*.vue"],
|
|
23
|
+
allowSyntheticDefaultImports: true,
|
|
24
|
+
}),
|
|
25
|
+
],
|
|
26
|
+
external: [
|
|
27
|
+
"vue",
|
|
28
|
+
"lodash",
|
|
29
|
+
"dayjs",
|
|
30
|
+
"@certd/acme-client",
|
|
31
|
+
"@certd/pipeline",
|
|
32
|
+
"@certd/plugin-cert",
|
|
33
|
+
"@certd/plugin-aliyun",
|
|
34
|
+
"@certd/plugin-tencent",
|
|
35
|
+
"@certd/plugin-huawei",
|
|
36
|
+
"@certd/plugin-host",
|
|
37
|
+
"@certd/plugin-tencent",
|
|
38
|
+
"@certd/plugin-util",
|
|
39
|
+
],
|
|
12
40
|
output: {
|
|
13
|
-
// Provide global variables to use in the UMD build
|
|
14
|
-
// for externalized deps
|
|
15
41
|
globals: {
|
|
16
42
|
vue: "Vue",
|
|
17
|
-
|
|
43
|
+
lodash: "_",
|
|
18
44
|
dayjs: "dayjs",
|
|
19
|
-
"@
|
|
45
|
+
"@certd/plugin-cert": "CertdPluginCert",
|
|
46
|
+
"@certd/acme-client": "CertdAcmeClient",
|
|
47
|
+
"@certd/pipeline": "CertdPluginPipeline",
|
|
48
|
+
"@certd/plugin-aliyun": "CertdPluginAliyun",
|
|
49
|
+
"@certd/plugin-host": "CertdPluginHost",
|
|
50
|
+
"@certd/plugin-huawei": "CertdPluginHuawei",
|
|
51
|
+
"@certd/plugin-util": "CertdPluginUtil",
|
|
20
52
|
},
|
|
21
53
|
},
|
|
22
54
|
},
|
package/src/dns-provider/api.ts
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { Registrable } from "@certd/pipeline";
|
|
2
|
-
|
|
3
|
-
export type DnsProviderDefine = Registrable & {
|
|
4
|
-
accessType: string;
|
|
5
|
-
autowire?: {
|
|
6
|
-
[key: string]: any;
|
|
7
|
-
};
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
export type CreateRecordOptions = {
|
|
11
|
-
fullRecord: string;
|
|
12
|
-
type: string;
|
|
13
|
-
value: any;
|
|
14
|
-
};
|
|
15
|
-
export type RemoveRecordOptions = CreateRecordOptions & {
|
|
16
|
-
record: any;
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
export interface IDnsProvider {
|
|
20
|
-
onInstance(): Promise<void>;
|
|
21
|
-
createRecord(options: CreateRecordOptions): Promise<any>;
|
|
22
|
-
removeRecord(options: RemoveRecordOptions): Promise<any>;
|
|
23
|
-
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { dnsProviderRegistry } from "./registry";
|
|
2
|
-
import { DnsProviderDefine } from "./api";
|
|
3
|
-
import { Decorator, AUTOWIRE_KEY } from "@certd/pipeline";
|
|
4
|
-
import _ from "lodash";
|
|
5
|
-
|
|
6
|
-
// 提供一个唯一 key
|
|
7
|
-
export const DNS_PROVIDER_CLASS_KEY = "pipeline:dns-provider";
|
|
8
|
-
|
|
9
|
-
export function IsDnsProvider(define: DnsProviderDefine): ClassDecorator {
|
|
10
|
-
return (target: any) => {
|
|
11
|
-
target = Decorator.target(target);
|
|
12
|
-
const autowires: any = {};
|
|
13
|
-
const properties = Decorator.getClassProperties(target);
|
|
14
|
-
for (const property in properties) {
|
|
15
|
-
const autowire = Reflect.getMetadata(AUTOWIRE_KEY, target, property);
|
|
16
|
-
if (autowire) {
|
|
17
|
-
autowires[property] = autowire;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
_.merge(define, { autowire: autowires });
|
|
21
|
-
|
|
22
|
-
Reflect.defineMetadata(DNS_PROVIDER_CLASS_KEY, define, target);
|
|
23
|
-
|
|
24
|
-
target.define = define;
|
|
25
|
-
dnsProviderRegistry.register(define.name, {
|
|
26
|
-
define,
|
|
27
|
-
target,
|
|
28
|
-
});
|
|
29
|
-
};
|
|
30
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,205 +0,0 @@
|
|
|
1
|
-
// @ts-ignore
|
|
2
|
-
import * as acme from "@certd/acme-client";
|
|
3
|
-
import _ from "lodash";
|
|
4
|
-
import { Challenge } from "@certd/acme-client/types/rfc8555";
|
|
5
|
-
import { Logger } from "log4js";
|
|
6
|
-
import { IContext } from "@certd/pipeline/src/core/context";
|
|
7
|
-
import { IDnsProvider } from "../../dns-provider";
|
|
8
|
-
export type CertInfo = {
|
|
9
|
-
crt: string;
|
|
10
|
-
key: string;
|
|
11
|
-
csr: string;
|
|
12
|
-
};
|
|
13
|
-
export class AcmeService {
|
|
14
|
-
userContext: IContext;
|
|
15
|
-
logger: Logger;
|
|
16
|
-
constructor(options: { userContext: IContext; logger: Logger }) {
|
|
17
|
-
this.userContext = options.userContext;
|
|
18
|
-
this.logger = options.logger;
|
|
19
|
-
acme.setLogger((text: string) => {
|
|
20
|
-
this.logger.info(text);
|
|
21
|
-
});
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
async getAccountConfig(email: string): Promise<any> {
|
|
25
|
-
return (await this.userContext.getObj(this.buildAccountKey(email))) || {};
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
buildAccountKey(email: string) {
|
|
29
|
-
return "acme.config." + email;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
async saveAccountConfig(email: string, conf: any) {
|
|
33
|
-
await this.userContext.setObj(this.buildAccountKey(email), conf);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
async getAcmeClient(email: string, isTest = false): Promise<acme.Client> {
|
|
37
|
-
const conf = await this.getAccountConfig(email);
|
|
38
|
-
if (conf.key == null) {
|
|
39
|
-
conf.key = await this.createNewKey();
|
|
40
|
-
await this.saveAccountConfig(email, conf);
|
|
41
|
-
}
|
|
42
|
-
const client = new acme.Client({
|
|
43
|
-
directoryUrl: isTest ? acme.directory.letsencrypt.staging : acme.directory.letsencrypt.production,
|
|
44
|
-
accountKey: conf.key,
|
|
45
|
-
accountUrl: conf.accountUrl,
|
|
46
|
-
backoffAttempts: 20,
|
|
47
|
-
backoffMin: 5000,
|
|
48
|
-
backoffMax: 10000,
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
if (conf.accountUrl == null) {
|
|
52
|
-
const accountPayload = {
|
|
53
|
-
termsOfServiceAgreed: true,
|
|
54
|
-
contact: [`mailto:${email}`],
|
|
55
|
-
};
|
|
56
|
-
await client.createAccount(accountPayload);
|
|
57
|
-
conf.accountUrl = client.getAccountUrl();
|
|
58
|
-
await this.saveAccountConfig(email, conf);
|
|
59
|
-
}
|
|
60
|
-
return client;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
async createNewKey() {
|
|
64
|
-
const key = await acme.forge.createPrivateKey();
|
|
65
|
-
return key.toString();
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
async challengeCreateFn(authz: any, challenge: any, keyAuthorization: string, dnsProvider: IDnsProvider) {
|
|
69
|
-
this.logger.info("Triggered challengeCreateFn()");
|
|
70
|
-
|
|
71
|
-
/* http-01 */
|
|
72
|
-
if (challenge.type === "http-01") {
|
|
73
|
-
const filePath = `/var/www/html/.well-known/acme-challenge/${challenge.token}`;
|
|
74
|
-
const fileContents = keyAuthorization;
|
|
75
|
-
|
|
76
|
-
this.logger.info(`Creating challenge response for ${authz.identifier.value} at path: ${filePath}`);
|
|
77
|
-
|
|
78
|
-
/* Replace this */
|
|
79
|
-
this.logger.info(`Would write "${fileContents}" to path "${filePath}"`);
|
|
80
|
-
// await fs.writeFileAsync(filePath, fileContents);
|
|
81
|
-
} else if (challenge.type === "dns-01") {
|
|
82
|
-
/* dns-01 */
|
|
83
|
-
const dnsRecord = `_acme-challenge.${authz.identifier.value}`;
|
|
84
|
-
const recordValue = keyAuthorization;
|
|
85
|
-
|
|
86
|
-
this.logger.info(`Creating TXT record for ${authz.identifier.value}: ${dnsRecord}`);
|
|
87
|
-
|
|
88
|
-
/* Replace this */
|
|
89
|
-
this.logger.info(`Would create TXT record "${dnsRecord}" with value "${recordValue}"`);
|
|
90
|
-
|
|
91
|
-
return await dnsProvider.createRecord({
|
|
92
|
-
fullRecord: dnsRecord,
|
|
93
|
-
type: "TXT",
|
|
94
|
-
value: recordValue,
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* Function used to remove an ACME challenge response
|
|
101
|
-
*
|
|
102
|
-
* @param {object} authz Authorization object
|
|
103
|
-
* @param {object} challenge Selected challenge
|
|
104
|
-
* @param {string} keyAuthorization Authorization key
|
|
105
|
-
* @param recordItem challengeCreateFn create record item
|
|
106
|
-
* @param dnsProvider dnsProvider
|
|
107
|
-
* @returns {Promise}
|
|
108
|
-
*/
|
|
109
|
-
|
|
110
|
-
async challengeRemoveFn(authz: any, challenge: any, keyAuthorization: string, recordItem: any, dnsProvider: IDnsProvider) {
|
|
111
|
-
this.logger.info("Triggered challengeRemoveFn()");
|
|
112
|
-
|
|
113
|
-
/* http-01 */
|
|
114
|
-
if (challenge.type === "http-01") {
|
|
115
|
-
const filePath = `/var/www/html/.well-known/acme-challenge/${challenge.token}`;
|
|
116
|
-
|
|
117
|
-
this.logger.info(`Removing challenge response for ${authz.identifier.value} at path: ${filePath}`);
|
|
118
|
-
|
|
119
|
-
/* Replace this */
|
|
120
|
-
this.logger.info(`Would remove file on path "${filePath}"`);
|
|
121
|
-
// await fs.unlinkAsync(filePath);
|
|
122
|
-
} else if (challenge.type === "dns-01") {
|
|
123
|
-
const dnsRecord = `_acme-challenge.${authz.identifier.value}`;
|
|
124
|
-
const recordValue = keyAuthorization;
|
|
125
|
-
|
|
126
|
-
this.logger.info(`Removing TXT record for ${authz.identifier.value}: ${dnsRecord}`);
|
|
127
|
-
|
|
128
|
-
/* Replace this */
|
|
129
|
-
this.logger.info(`Would remove TXT record "${dnsRecord}" with value "${recordValue}"`);
|
|
130
|
-
try {
|
|
131
|
-
await dnsProvider.removeRecord({
|
|
132
|
-
fullRecord: dnsRecord,
|
|
133
|
-
type: "TXT",
|
|
134
|
-
value: keyAuthorization,
|
|
135
|
-
record: recordItem,
|
|
136
|
-
});
|
|
137
|
-
} catch (e) {
|
|
138
|
-
this.logger.error("删除解析记录出错:", e);
|
|
139
|
-
throw e;
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
async order(options: { email: string; domains: string | string[]; dnsProvider: any; csrInfo: any; isTest?: boolean }) {
|
|
145
|
-
const { email, isTest, domains, csrInfo, dnsProvider } = options;
|
|
146
|
-
const client: acme.Client = await this.getAcmeClient(email, isTest);
|
|
147
|
-
|
|
148
|
-
/* Create CSR */
|
|
149
|
-
const { commonName, altNames } = this.buildCommonNameByDomains(domains);
|
|
150
|
-
|
|
151
|
-
const [key, csr] = await acme.forge.createCsr({
|
|
152
|
-
commonName,
|
|
153
|
-
...csrInfo,
|
|
154
|
-
altNames,
|
|
155
|
-
});
|
|
156
|
-
if (dnsProvider == null) {
|
|
157
|
-
throw new Error("dnsProvider 不能为空");
|
|
158
|
-
}
|
|
159
|
-
/* 自动申请证书 */
|
|
160
|
-
const crt = await client.auto({
|
|
161
|
-
csr,
|
|
162
|
-
email: email,
|
|
163
|
-
termsOfServiceAgreed: true,
|
|
164
|
-
challengePriority: ["dns-01"],
|
|
165
|
-
challengeCreateFn: async (authz: acme.Authorization, challenge: Challenge, keyAuthorization: string): Promise<any> => {
|
|
166
|
-
return await this.challengeCreateFn(authz, challenge, keyAuthorization, dnsProvider);
|
|
167
|
-
},
|
|
168
|
-
challengeRemoveFn: async (authz: acme.Authorization, challenge: Challenge, keyAuthorization: string, recordItem: any): Promise<any> => {
|
|
169
|
-
return await this.challengeRemoveFn(authz, challenge, keyAuthorization, recordItem, dnsProvider);
|
|
170
|
-
},
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
const cert: CertInfo = {
|
|
174
|
-
crt: crt.toString(),
|
|
175
|
-
key: key.toString(),
|
|
176
|
-
csr: csr.toString(),
|
|
177
|
-
};
|
|
178
|
-
/* Done */
|
|
179
|
-
this.logger.debug(`CSR:\n${cert.csr}`);
|
|
180
|
-
this.logger.debug(`Certificate:\n${cert.crt}`);
|
|
181
|
-
this.logger.info("证书申请成功");
|
|
182
|
-
return cert;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
buildCommonNameByDomains(domains: string | string[]): {
|
|
186
|
-
commonName: string;
|
|
187
|
-
altNames: string[] | undefined;
|
|
188
|
-
} {
|
|
189
|
-
if (typeof domains === "string") {
|
|
190
|
-
domains = domains.split(",");
|
|
191
|
-
}
|
|
192
|
-
if (domains.length === 0) {
|
|
193
|
-
throw new Error("domain can not be empty");
|
|
194
|
-
}
|
|
195
|
-
const commonName = domains[0];
|
|
196
|
-
let altNames: undefined | string[] = undefined;
|
|
197
|
-
if (domains.length > 1) {
|
|
198
|
-
altNames = _.slice(domains, 1);
|
|
199
|
-
}
|
|
200
|
-
return {
|
|
201
|
-
commonName,
|
|
202
|
-
altNames,
|
|
203
|
-
};
|
|
204
|
-
}
|
|
205
|
-
}
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import { CertInfo } from "./acme";
|
|
2
|
-
import fs from "fs";
|
|
3
|
-
import os from "os";
|
|
4
|
-
import forge from "node-forge";
|
|
5
|
-
import path from "path";
|
|
6
|
-
export class CertReader implements CertInfo {
|
|
7
|
-
crt: string;
|
|
8
|
-
key: string;
|
|
9
|
-
csr: string;
|
|
10
|
-
|
|
11
|
-
detail: any;
|
|
12
|
-
expires: number;
|
|
13
|
-
constructor(certInfo: CertInfo) {
|
|
14
|
-
this.crt = certInfo.crt;
|
|
15
|
-
this.key = certInfo.key;
|
|
16
|
-
this.csr = certInfo.csr;
|
|
17
|
-
|
|
18
|
-
const { detail, expires } = this.getCrtDetail(this.crt);
|
|
19
|
-
this.detail = detail;
|
|
20
|
-
this.expires = expires.getTime();
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
toCertInfo(): CertInfo {
|
|
24
|
-
return {
|
|
25
|
-
crt: this.crt,
|
|
26
|
-
key: this.key,
|
|
27
|
-
csr: this.csr,
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
getCrtDetail(crt: string) {
|
|
32
|
-
const pki = forge.pki;
|
|
33
|
-
const detail = pki.certificateFromPem(crt.toString());
|
|
34
|
-
const expires = detail.validity.notAfter;
|
|
35
|
-
return { detail, expires };
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
saveToFile(type: "crt" | "key", filepath?: string) {
|
|
39
|
-
if (filepath == null) {
|
|
40
|
-
//写入临时目录
|
|
41
|
-
filepath = path.join(os.tmpdir(), "/certd/tmp/", Math.floor(Math.random() * 1000000) + "", `cert.${type}`);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const dir = path.dirname(filepath);
|
|
45
|
-
if (!fs.existsSync(dir)) {
|
|
46
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
fs.writeFileSync(filepath, this[type]);
|
|
50
|
-
return filepath;
|
|
51
|
-
}
|
|
52
|
-
}
|