@entity-access/server-pages 1.0.30 → 1.0.31

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.
@@ -0,0 +1,247 @@
1
+ import * as forge from "node-forge";
2
+ import * as crypto from "crypto";
3
+ import * as acme from "acme-client";
4
+ import DateTime from "@entity-access/entity-access/dist/types/DateTime.js";
5
+ import cluster from "cluster";
6
+ import { existsSync, writeFileSync, readFileSync, unlinkSync, mkdirSync } from "fs";
7
+ import { join } from "path"
8
+ import ensureDir, { deleteIfExists } from "../core/FileApi.js";
9
+ import Inject, { RegisterSingleton } from "@entity-access/entity-access/dist/di/di.js";
10
+ import ChallengeStore from "./ChallengeStore.js";
11
+ import * as tls from "node:tls";
12
+
13
+ export interface IAcmeOptions {
14
+ sslMode?: string,
15
+ accountPrivateKeyPath?: string,
16
+ emailAddress?: string,
17
+ mode?: "production" | "self-signed" | "staging",
18
+ endPoint?: string,
19
+ eabKid?: string,
20
+ eabHmac?: string
21
+ }
22
+
23
+ export interface ICertOptions extends IAcmeOptions {
24
+ host: string,
25
+ };
26
+
27
+ @RegisterSingleton
28
+ export default class ACME {
29
+
30
+ @Inject
31
+ private challengeStore: ChallengeStore;
32
+
33
+ private map = new Map<string, tls.SecureContext>();
34
+
35
+ public async getSecureContext(options: ICertOptions) {
36
+ const { host } = options;
37
+ let sc = this.map.get(host);
38
+ if (sc) {
39
+ return sc;
40
+ }
41
+
42
+ const { key , cert } = await this.setup(options)
43
+ sc = tls.createSecureContext({ cert, key });
44
+ this.map.set(host, sc);
45
+ return sc;
46
+ }
47
+
48
+ public async setup({
49
+ host,
50
+ sslMode = "./",
51
+ accountPrivateKeyPath = "./",
52
+ emailAddress = "",
53
+ mode = "production" as "production" | "self-signed" | "staging",
54
+ endPoint = "",
55
+ eabKid = "",
56
+ eabHmac = ""
57
+ }) {
58
+
59
+ if (mode === "self-signed") {
60
+ return this.setupSelfSigned(sslMode);
61
+ }
62
+
63
+ const hostRoot = join(sslMode, host);
64
+
65
+ ensureDir(hostRoot);
66
+
67
+ const keyPath = join(hostRoot, "cert.key");
68
+ const certPath = join(hostRoot, "cert.crt");
69
+
70
+ const logs = [];
71
+
72
+ try {
73
+
74
+ const maintainerEmail = emailAddress;
75
+
76
+ let externalAccountBinding;
77
+
78
+ if (eabKid) {
79
+ externalAccountBinding = {
80
+ kid: eabKid,
81
+ hmacKey: eabHmac
82
+ };
83
+ }
84
+
85
+ let cert:string;
86
+ let key:string;
87
+
88
+ if (!existsSync(keyPath)) {
89
+ deleteIfExists(certPath);
90
+ key = (await acme.crypto.createPrivateRsaKey()).toString();
91
+ writeFileSync(keyPath, key);
92
+ console.log(`Creating key at ${keyPath}`);
93
+ } else {
94
+ key = readFileSync(keyPath, "utf8");
95
+ }
96
+
97
+ // load cert...
98
+ if (existsSync(certPath)) {
99
+ cert = readFileSync(certPath, "utf8");
100
+ const certificate = new crypto.X509Certificate(cert);
101
+ const validTo = DateTime.parse(certificate.validTo).diff(DateTime.now);
102
+ if (validTo.totalDays > 30) {
103
+ console.log(`Reusing certificate, valid for ${validTo.totalDays}`);
104
+ return { cert , key };
105
+ }
106
+ console.log(`Deleting old certificates`);
107
+ unlinkSync(certPath);
108
+ }
109
+
110
+ if (!cluster.isPrimary) {
111
+ console.log(`Generating Self Signed SSL Certificate for ${host} in cluster worker. Contact administrator.`);
112
+ return this.setupSelfSigned();
113
+ }
114
+
115
+ let accountKey;
116
+ if( existsSync(accountPrivateKeyPath) ) {
117
+ console.log("Reusing the account private key.");
118
+ accountKey = readFileSync(accountPrivateKeyPath);
119
+ } else {
120
+ console.log("Creating new private key.");
121
+ accountKey = await acme.crypto.createPrivateKey();
122
+ writeFileSync(accountPrivateKeyPath, accountKey);
123
+ }
124
+
125
+ acme.setLogger((message) => {
126
+ // console.log(message);
127
+ logs.push(message);
128
+ });
129
+
130
+ let altNames;
131
+
132
+ // auto renew...
133
+ const client = new acme.Client({
134
+ directoryUrl: endPoint || acme.directory.letsencrypt[mode],
135
+ accountKey,
136
+ externalAccountBinding,
137
+ });
138
+
139
+ /* Create CSR */
140
+ const [csrKey, csr] = await acme.crypto.createCsr({
141
+ commonName: host,
142
+ altNames
143
+ }, key);
144
+
145
+
146
+
147
+ /* Certificate */
148
+ cert = await client.auto({
149
+ csr,
150
+ email: maintainerEmail,
151
+ termsOfServiceAgreed: true,
152
+ skipChallengeVerification: true,
153
+ challengePriority: ["http-01"],
154
+ challengeCreateFn: (authz, challenge, keyAuthorization) => {
155
+ if (challenge.type !== "http-01") {
156
+ return;
157
+ }
158
+ return this.challengeStore.save(challenge.token, keyAuthorization);
159
+ },
160
+ challengeRemoveFn: (authz, challenge, keyAuthorization) => {
161
+ return this.challengeStore.remove(challenge.token);
162
+ },
163
+ });
164
+
165
+ writeFileSync(certPath, cert);
166
+
167
+ return { cert, key };
168
+ } catch (error) {
169
+ console.log(logs.join("\n"));
170
+ console.error(error);
171
+ throw error;
172
+ }
173
+ }
174
+
175
+ public setupSelfSigned(sslMode = "./") {
176
+
177
+ const selfSigned = `${sslMode}/self-signed/`;
178
+
179
+ ensureDir(selfSigned);
180
+
181
+ const certPath = `${selfSigned}/cert.crt`;
182
+ const keyPath = `${selfSigned}/key.pem`;
183
+
184
+ let key;
185
+ let cert;
186
+
187
+ if (existsSync(certPath) && existsSync(keyPath)) {
188
+ key = readFileSync(keyPath);
189
+ cert = readFileSync(certPath);
190
+ return { key, cert };
191
+ }
192
+
193
+ const pki = forge.default.pki;
194
+
195
+ // generate a key pair or use one you have already
196
+ const keys = pki.rsa.generateKeyPair(2048);
197
+
198
+ // create a new certificate
199
+ const crt = pki.createCertificate();
200
+
201
+ // fill the required fields
202
+ crt.publicKey = keys.publicKey;
203
+ crt.serialNumber = '01';
204
+ crt.validity.notBefore = new Date();
205
+ crt.validity.notAfter = new Date();
206
+ crt.validity.notAfter.setFullYear(crt.validity.notBefore.getFullYear() + 40);
207
+
208
+ // use your own attributes here, or supply a csr (check the docs)
209
+ const attrs = [
210
+ {
211
+ name: 'commonName',
212
+ value: 'dev.socialmail.in'
213
+ }, {
214
+ name: 'countryName',
215
+ value: 'IN'
216
+ }, {
217
+ shortName: 'ST',
218
+ value: 'Maharashtra'
219
+ }, {
220
+ name: 'localityName',
221
+ value: 'Navi Mumbai'
222
+ }, {
223
+ name: 'organizationName',
224
+ value: 'NeuroSpeech Technologies Pvt Ltd'
225
+ }, {
226
+ shortName: 'OU',
227
+ value: 'Test'
228
+ }
229
+ ];
230
+
231
+ // here we set subject and issuer as the same one
232
+ crt.setSubject(attrs);
233
+ crt.setIssuer(attrs);
234
+
235
+ // the actual certificate signing
236
+ crt.sign(keys.privateKey);
237
+
238
+ // now convert the Forge certificate to PEM format
239
+ cert = pki.certificateToPem(crt);
240
+ key = pki.privateKeyToPem(keys.privateKey);
241
+
242
+ writeFileSync(certPath, cert);
243
+ writeFileSync(keyPath, key);
244
+
245
+ return { key, cert };
246
+ }
247
+ }
@@ -0,0 +1,26 @@
1
+ import { RegisterSingleton } from "@entity-access/entity-access/dist/di/di.js";
2
+ import ensureDir from "../core/FileApi.js";
3
+ import { readFileSync, unlinkSync, writeFileSync } from "fs";
4
+ import { join } from "node:path";
5
+
6
+ const path = "./challenges";
7
+
8
+ @RegisterSingleton
9
+ export default class ChallengeStore {
10
+
11
+ constructor() {
12
+ ensureDir(path);
13
+ }
14
+
15
+ async get(name: string) {
16
+ return readFileSync(join(path, name));
17
+ }
18
+
19
+ async save(name: string, value: string) {
20
+ writeFileSync(join(path, name), value, "utf8");
21
+ }
22
+
23
+ async remove(name: string) {
24
+ unlinkSync(join(path, name));
25
+ }
26
+ }
@@ -1,7 +0,0 @@
1
- export declare class SelfSigned {
2
- static setupSelfSigned(sslMode?: string): {
3
- key: any;
4
- cert: any;
5
- };
6
- }
7
- //# sourceMappingURL=SelfSigned.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"SelfSigned.d.ts","sourceRoot":"","sources":["../../src/ssl/SelfSigned.ts"],"names":[],"mappings":"AAIA,qBAAa,UAAU;WACL,eAAe,CAAC,OAAO,SAAO;;;;CAwE/C"}
@@ -1,62 +0,0 @@
1
- import * as forge from "node-forge";
2
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
3
- export class SelfSigned {
4
- static setupSelfSigned(sslMode = "./") {
5
- const selfSigned = `${sslMode}/self-signed/`;
6
- mkdirSync(selfSigned, { recursive: true });
7
- const certPath = `${selfSigned}/cert.crt`;
8
- const keyPath = `${selfSigned}/key.pem`;
9
- let key;
10
- let cert;
11
- if (existsSync(certPath) && existsSync(keyPath)) {
12
- key = readFileSync(keyPath);
13
- cert = readFileSync(certPath);
14
- return { key, cert };
15
- }
16
- const pki = forge.default.pki;
17
- // generate a key pair or use one you have already
18
- const keys = pki.rsa.generateKeyPair(2048);
19
- // create a new certificate
20
- const crt = pki.createCertificate();
21
- // fill the required fields
22
- crt.publicKey = keys.publicKey;
23
- crt.serialNumber = '01';
24
- crt.validity.notBefore = new Date();
25
- crt.validity.notAfter = new Date();
26
- crt.validity.notAfter.setFullYear(crt.validity.notBefore.getFullYear() + 40);
27
- // use your own attributes here, or supply a csr (check the docs)
28
- const attrs = [
29
- {
30
- name: 'commonName',
31
- value: 'dev.socialmail.in'
32
- }, {
33
- name: 'countryName',
34
- value: 'IN'
35
- }, {
36
- shortName: 'ST',
37
- value: 'Maharashtra'
38
- }, {
39
- name: 'localityName',
40
- value: 'Navi Mumbai'
41
- }, {
42
- name: 'organizationName',
43
- value: 'NeuroSpeech Technologies Pvt Ltd'
44
- }, {
45
- shortName: 'OU',
46
- value: 'Test'
47
- }
48
- ];
49
- // here we set subject and issuer as the same one
50
- crt.setSubject(attrs);
51
- crt.setIssuer(attrs);
52
- // the actual certificate signing
53
- crt.sign(keys.privateKey);
54
- // now convert the Forge certificate to PEM format
55
- cert = pki.certificateToPem(crt);
56
- key = pki.privateKeyToPem(keys.privateKey);
57
- writeFileSync(certPath, cert);
58
- writeFileSync(keyPath, key);
59
- return { key, cert };
60
- }
61
- }
62
- //# sourceMappingURL=SelfSigned.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"SelfSigned.js","sourceRoot":"","sources":["../../src/ssl/SelfSigned.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,YAAY,CAAC;AAEpC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,IAAI,CAAC;AAExE,MAAM,OAAO,UAAU;IACZ,MAAM,CAAC,eAAe,CAAC,OAAO,GAAG,IAAI;QAExC,MAAM,UAAU,GAAG,GAAG,OAAO,eAAe,CAAC;QAE7C,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAE3C,MAAM,QAAQ,GAAI,GAAG,UAAU,WAAW,CAAC;QAC3C,MAAM,OAAO,GAAI,GAAG,UAAU,UAAU,CAAC;QAEzC,IAAI,GAAG,CAAC;QACR,IAAI,IAAI,CAAC;QAET,IAAI,UAAU,CAAC,QAAQ,CAAC,IAAI,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YAC9C,GAAG,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;YAC5B,IAAI,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;YAC9B,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;QACzB,CAAC;QAED,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;QAE9B,kDAAkD;QAClD,MAAM,IAAI,GAAG,GAAG,CAAC,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;QAE3C,2BAA2B;QAC3B,MAAM,GAAG,GAAG,GAAG,CAAC,iBAAiB,EAAE,CAAC;QAEpC,2BAA2B;QAC3B,GAAG,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC;QAC/B,GAAG,CAAC,YAAY,GAAG,IAAI,CAAC;QACxB,GAAG,CAAC,QAAQ,CAAC,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC;QACpC,GAAG,CAAC,QAAQ,CAAC,QAAQ,GAAG,IAAI,IAAI,EAAE,CAAC;QACnC,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,WAAW,EAAE,GAAG,EAAE,CAAC,CAAC;QAE7E,iEAAiE;QACjE,MAAM,KAAK,GAAG;YACV;gBACI,IAAI,EAAE,YAAY;gBAClB,KAAK,EAAE,mBAAmB;aAC7B,EAAE;gBACC,IAAI,EAAE,aAAa;gBACnB,KAAK,EAAE,IAAI;aACd,EAAE;gBACC,SAAS,EAAE,IAAI;gBACf,KAAK,EAAE,aAAa;aACvB,EAAE;gBACC,IAAI,EAAE,cAAc;gBACpB,KAAK,EAAE,aAAa;aACvB,EAAE;gBACC,IAAI,EAAE,kBAAkB;gBACxB,KAAK,EAAE,kCAAkC;aAC5C,EAAE;gBACC,SAAS,EAAE,IAAI;gBACf,KAAK,EAAE,MAAM;aAChB;SACJ,CAAC;QAEF,iDAAiD;QACjD,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;QACtB,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QAErB,iCAAiC;QACjC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAE1B,kDAAkD;QAClD,IAAI,GAAG,GAAG,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC;QACjC,GAAG,GAAG,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAE3C,aAAa,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QAC9B,aAAa,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QAE5B,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;IACzB,CAAC;CACJ"}
@@ -1,78 +0,0 @@
1
- import * as forge from "node-forge";
2
- import * as crypto from "crypto";
3
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
4
-
5
- export class SelfSigned {
6
- public static setupSelfSigned(sslMode = "./") {
7
-
8
- const selfSigned = `${sslMode}/self-signed/`;
9
-
10
- mkdirSync(selfSigned, { recursive: true });
11
-
12
- const certPath = `${selfSigned}/cert.crt`;
13
- const keyPath = `${selfSigned}/key.pem`;
14
-
15
- let key;
16
- let cert;
17
-
18
- if (existsSync(certPath) && existsSync(keyPath)) {
19
- key = readFileSync(keyPath);
20
- cert = readFileSync(certPath);
21
- return { key, cert };
22
- }
23
-
24
- const pki = forge.default.pki;
25
-
26
- // generate a key pair or use one you have already
27
- const keys = pki.rsa.generateKeyPair(2048);
28
-
29
- // create a new certificate
30
- const crt = pki.createCertificate();
31
-
32
- // fill the required fields
33
- crt.publicKey = keys.publicKey;
34
- crt.serialNumber = '01';
35
- crt.validity.notBefore = new Date();
36
- crt.validity.notAfter = new Date();
37
- crt.validity.notAfter.setFullYear(crt.validity.notBefore.getFullYear() + 40);
38
-
39
- // use your own attributes here, or supply a csr (check the docs)
40
- const attrs = [
41
- {
42
- name: 'commonName',
43
- value: 'dev.socialmail.in'
44
- }, {
45
- name: 'countryName',
46
- value: 'IN'
47
- }, {
48
- shortName: 'ST',
49
- value: 'Maharashtra'
50
- }, {
51
- name: 'localityName',
52
- value: 'Navi Mumbai'
53
- }, {
54
- name: 'organizationName',
55
- value: 'NeuroSpeech Technologies Pvt Ltd'
56
- }, {
57
- shortName: 'OU',
58
- value: 'Test'
59
- }
60
- ];
61
-
62
- // here we set subject and issuer as the same one
63
- crt.setSubject(attrs);
64
- crt.setIssuer(attrs);
65
-
66
- // the actual certificate signing
67
- crt.sign(keys.privateKey);
68
-
69
- // now convert the Forge certificate to PEM format
70
- cert = pki.certificateToPem(crt);
71
- key = pki.privateKeyToPem(keys.privateKey);
72
-
73
- writeFileSync(certPath, cert);
74
- writeFileSync(keyPath, key);
75
-
76
- return { key, cert };
77
- }
78
- }