sliftutils 1.4.88 → 1.5.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/index.d.ts +11 -5
- package/misc/https/certs.d.ts +6 -5
- package/misc/https/certs.ts +36 -27
- package/misc/strings.d.ts +1 -0
- package/misc/strings.ts +8 -0
- package/package.json +1 -1
package/index.d.ts
CHANGED
|
@@ -72,7 +72,7 @@ declare module "sliftutils/misc/https/certs" {
|
|
|
72
72
|
import * as forge from "node-forge";
|
|
73
73
|
import { MaybePromise } from "socket-function/src/types";
|
|
74
74
|
export declare const CA_NOT_FOUND_ERROR = "18aa7318-f88f-4d2d-b41f-3daf4a433827";
|
|
75
|
-
export declare const identityStorageKey = "
|
|
75
|
+
export declare const identityStorageKey = "machineCA_11";
|
|
76
76
|
export type IdentityStorageType = {
|
|
77
77
|
domain: string;
|
|
78
78
|
certB64: string;
|
|
@@ -99,7 +99,7 @@ declare module "sliftutils/misc/https/certs" {
|
|
|
99
99
|
export declare const sign: (keyPair: {
|
|
100
100
|
key: string | Buffer;
|
|
101
101
|
}, data: unknown) => string;
|
|
102
|
-
export declare function verify(cert: string, signature: string, data: unknown):
|
|
102
|
+
export declare function verify(cert: string, signature: string, data: unknown): void;
|
|
103
103
|
export declare function validateCACert(domain: string, cert: string | Buffer): void;
|
|
104
104
|
export declare function validateCertificate(domain: string, cert: Buffer | string, issuerCert: Buffer | string): void;
|
|
105
105
|
export declare function generateKeyPair(): forge.pki.rsa.KeyPair;
|
|
@@ -108,21 +108,22 @@ declare module "sliftutils/misc/https/certs" {
|
|
|
108
108
|
export declare function createCertFromCA(config: {
|
|
109
109
|
CAKeyPair: X509KeyPair;
|
|
110
110
|
}): X509KeyPair;
|
|
111
|
-
export declare function getMachineId(
|
|
111
|
+
export declare function getMachineId(domainNameOrNodeId: string, domain: string): string;
|
|
112
112
|
export type NodeIdParts = {
|
|
113
113
|
threadId: string;
|
|
114
114
|
machineId: string;
|
|
115
115
|
domain: string;
|
|
116
116
|
port: number;
|
|
117
117
|
};
|
|
118
|
-
export declare function decodeNodeId(nodeId: string): NodeIdParts | undefined;
|
|
119
|
-
export declare function decodeNodeIdAssert(nodeId: string): NodeIdParts;
|
|
118
|
+
export declare function decodeNodeId(nodeId: string, domain: string, allowMissingThreadId?: "allowMissingThreadId"): NodeIdParts | undefined;
|
|
119
|
+
export declare function decodeNodeIdAssert(nodeId: string, domain: string, allowMissingThreadId?: "allowMissingThreadId"): NodeIdParts;
|
|
120
120
|
export declare function encodeNodeId(parts: NodeIdParts): string;
|
|
121
121
|
export declare function setIdentityCARaw(domain: string, json: string): Promise<void>;
|
|
122
122
|
export declare function loadIdentityCA(domain: string): Promise<void>;
|
|
123
123
|
export declare function getIdentityCA(domain: string): X509KeyPair;
|
|
124
124
|
export declare function getIdentityCAPromise(domain: string): MaybePromise<X509KeyPair>;
|
|
125
125
|
export declare function getOwnMachineId(domain: string): string;
|
|
126
|
+
export declare function getOwnThreadId(domain: string): string;
|
|
126
127
|
/** Part of the machineId comes from the publicKey, so we can use it to verify */
|
|
127
128
|
export declare function verifyMachineIdForPublicKey(config: {
|
|
128
129
|
machineId: string;
|
|
@@ -291,6 +292,11 @@ declare module "sliftutils/misc/random" {
|
|
|
291
292
|
|
|
292
293
|
}
|
|
293
294
|
|
|
295
|
+
declare module "sliftutils/misc/strings" {
|
|
296
|
+
export declare function ellipsize(text: string, maxLength: number): string;
|
|
297
|
+
|
|
298
|
+
}
|
|
299
|
+
|
|
294
300
|
declare module "sliftutils/misc/types" {
|
|
295
301
|
export declare function isDefined<T>(value: T | undefined | null): value is T;
|
|
296
302
|
export declare function freezeObject(value: unknown): unknown;
|
package/misc/https/certs.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import * as forge from "node-forge";
|
|
6
6
|
import { MaybePromise } from "socket-function/src/types";
|
|
7
7
|
export declare const CA_NOT_FOUND_ERROR = "18aa7318-f88f-4d2d-b41f-3daf4a433827";
|
|
8
|
-
export declare const identityStorageKey = "
|
|
8
|
+
export declare const identityStorageKey = "machineCA_11";
|
|
9
9
|
export type IdentityStorageType = {
|
|
10
10
|
domain: string;
|
|
11
11
|
certB64: string;
|
|
@@ -32,7 +32,7 @@ export declare function getPublicIdentifier(PEMorDER: string | Buffer): Buffer;
|
|
|
32
32
|
export declare const sign: (keyPair: {
|
|
33
33
|
key: string | Buffer;
|
|
34
34
|
}, data: unknown) => string;
|
|
35
|
-
export declare function verify(cert: string, signature: string, data: unknown):
|
|
35
|
+
export declare function verify(cert: string, signature: string, data: unknown): void;
|
|
36
36
|
export declare function validateCACert(domain: string, cert: string | Buffer): void;
|
|
37
37
|
export declare function validateCertificate(domain: string, cert: Buffer | string, issuerCert: Buffer | string): void;
|
|
38
38
|
export declare function generateKeyPair(): forge.pki.rsa.KeyPair;
|
|
@@ -41,21 +41,22 @@ export declare function generateTestCA(domain: string): X509KeyPair;
|
|
|
41
41
|
export declare function createCertFromCA(config: {
|
|
42
42
|
CAKeyPair: X509KeyPair;
|
|
43
43
|
}): X509KeyPair;
|
|
44
|
-
export declare function getMachineId(
|
|
44
|
+
export declare function getMachineId(domainNameOrNodeId: string, domain: string): string;
|
|
45
45
|
export type NodeIdParts = {
|
|
46
46
|
threadId: string;
|
|
47
47
|
machineId: string;
|
|
48
48
|
domain: string;
|
|
49
49
|
port: number;
|
|
50
50
|
};
|
|
51
|
-
export declare function decodeNodeId(nodeId: string): NodeIdParts | undefined;
|
|
52
|
-
export declare function decodeNodeIdAssert(nodeId: string): NodeIdParts;
|
|
51
|
+
export declare function decodeNodeId(nodeId: string, domain: string, allowMissingThreadId?: "allowMissingThreadId"): NodeIdParts | undefined;
|
|
52
|
+
export declare function decodeNodeIdAssert(nodeId: string, domain: string, allowMissingThreadId?: "allowMissingThreadId"): NodeIdParts;
|
|
53
53
|
export declare function encodeNodeId(parts: NodeIdParts): string;
|
|
54
54
|
export declare function setIdentityCARaw(domain: string, json: string): Promise<void>;
|
|
55
55
|
export declare function loadIdentityCA(domain: string): Promise<void>;
|
|
56
56
|
export declare function getIdentityCA(domain: string): X509KeyPair;
|
|
57
57
|
export declare function getIdentityCAPromise(domain: string): MaybePromise<X509KeyPair>;
|
|
58
58
|
export declare function getOwnMachineId(domain: string): string;
|
|
59
|
+
export declare function getOwnThreadId(domain: string): string;
|
|
59
60
|
/** Part of the machineId comes from the publicKey, so we can use it to verify */
|
|
60
61
|
export declare function verifyMachineIdForPublicKey(config: {
|
|
61
62
|
machineId: string;
|
package/misc/https/certs.ts
CHANGED
|
@@ -19,6 +19,7 @@ import { MaybePromise } from "socket-function/src/types";
|
|
|
19
19
|
import { SocketFunction } from "socket-function/SocketFunction";
|
|
20
20
|
import { resetAllNodeCallFactories } from "socket-function/src/nodeCache";
|
|
21
21
|
import { getKeyStore } from "./persistentLocalStorage";
|
|
22
|
+
import { ellipsize } from "../strings";
|
|
22
23
|
|
|
23
24
|
setFlag(require, "node-forge", "allowclient", true);
|
|
24
25
|
setFlag(require, "js-sha256", "allowclient", true);
|
|
@@ -27,7 +28,7 @@ const timeInDay = 1000 * 60 * 60 * 24;
|
|
|
27
28
|
|
|
28
29
|
export const CA_NOT_FOUND_ERROR = "18aa7318-f88f-4d2d-b41f-3daf4a433827";
|
|
29
30
|
|
|
30
|
-
export const identityStorageKey = "
|
|
31
|
+
export const identityStorageKey = "machineCA_11";
|
|
31
32
|
export type IdentityStorageType = { domain: string; certB64: string; keyB64: string };
|
|
32
33
|
|
|
33
34
|
function getIdentityStore(domain: string) {
|
|
@@ -99,21 +100,17 @@ export function createX509(
|
|
|
99
100
|
//{ type: 7, ip: "127.0.0.1" }
|
|
100
101
|
]
|
|
101
102
|
},
|
|
102
|
-
// NOTE: nameConstraints
|
|
103
|
+
// NOTE: nameConstraints require our forked node-forge:
|
|
103
104
|
// "node-forge": "https://github.com/sliftist/forge#e618181b469b07bdc70b968b0391beb8ef5fecd6",
|
|
104
|
-
//
|
|
105
|
-
//
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
// { type: 2, value: forge.util.encodeUtf8(domain) },
|
|
114
|
-
// { type: 2, value: forge.util.encodeUtf8(localHostDomain) },
|
|
115
|
-
// ]
|
|
116
|
-
// },
|
|
105
|
+
// Chrome ignores them (https://bugs.chromium.org/p/chromium/issues/detail?id=1072083),
|
|
106
|
+
// but our own validation (validateCACert/validateCertificate) enforces them.
|
|
107
|
+
{
|
|
108
|
+
name: "nameConstraints",
|
|
109
|
+
permittedSubtrees: [
|
|
110
|
+
{ type: 2, value: forge.util.encodeUtf8(domain) },
|
|
111
|
+
{ type: 2, value: forge.util.encodeUtf8(localHostDomain) },
|
|
112
|
+
]
|
|
113
|
+
},
|
|
117
114
|
]);
|
|
118
115
|
certObj.setExtensions(extensions);
|
|
119
116
|
|
|
@@ -191,7 +188,9 @@ export const sign = measureWrap(function sign(keyPair: { key: string | Buffer },
|
|
|
191
188
|
|
|
192
189
|
export function verify(cert: string, signature: string, data: unknown) {
|
|
193
190
|
let certObj = parseCert(cert);
|
|
194
|
-
|
|
191
|
+
if (!(certObj.publicKey as forge.pki.rsa.PublicKey).verify(JSON.stringify(data), signature)) {
|
|
192
|
+
throw new Error(`Signature verification failed. Signature: ${JSON.stringify(signature)} | Data: ${ellipsize(JSON.stringify(data), 1024)}`);
|
|
193
|
+
}
|
|
195
194
|
}
|
|
196
195
|
|
|
197
196
|
function normalizeCertToPEM(PEMorDER: string | Buffer): string {
|
|
@@ -211,7 +210,7 @@ function getDomainPartFromPublicKey(publicKey: { publicKeyBytes: Buffer } | forg
|
|
|
211
210
|
} else {
|
|
212
211
|
bytes = Buffer.from(new Uint32Array((publicKey as any).n.data).buffer);
|
|
213
212
|
}
|
|
214
|
-
return "b" + sha265.sha256(Buffer.from(bytes)).slice(0, 16).replaceAll("+", "-").replaceAll("/", "_");
|
|
213
|
+
return "b" + Buffer.from(sha265.sha256.array(Buffer.from(bytes))).toString("base64").slice(0, 16).replaceAll("+", "-").replaceAll("/", "_");
|
|
215
214
|
}
|
|
216
215
|
|
|
217
216
|
export function validateCACert(domain: string, cert: string | Buffer) {
|
|
@@ -440,8 +439,8 @@ export function createCertFromCA(config: {
|
|
|
440
439
|
});
|
|
441
440
|
}
|
|
442
441
|
|
|
443
|
-
export function getMachineId(
|
|
444
|
-
return
|
|
442
|
+
export function getMachineId(domainNameOrNodeId: string, domain: string) {
|
|
443
|
+
return decodeNodeIdAssert(domainNameOrNodeId, domain, "allowMissingThreadId").machineId;
|
|
445
444
|
}
|
|
446
445
|
|
|
447
446
|
export type NodeIdParts = {
|
|
@@ -450,13 +449,18 @@ export type NodeIdParts = {
|
|
|
450
449
|
domain: string;
|
|
451
450
|
port: number;
|
|
452
451
|
};
|
|
453
|
-
export function decodeNodeId(nodeId: string): NodeIdParts | undefined {
|
|
452
|
+
export function decodeNodeId(nodeId: string, domain: string, allowMissingThreadId?: "allowMissingThreadId"): NodeIdParts | undefined {
|
|
454
453
|
let locationObj = getNodeIdLocation(nodeId);
|
|
455
454
|
if (!locationObj) {
|
|
456
455
|
return undefined;
|
|
457
456
|
}
|
|
458
457
|
let parts = locationObj.address.split(".");
|
|
459
|
-
|
|
458
|
+
// NOTE: We have to only allow localhost domains on our own domain, as the underlying domain
|
|
459
|
+
// gets stripped when we're looking at the machineId. So if we allowed localhost domains on
|
|
460
|
+
// other domains, a server could trick us into connecting to it, and then once the connection
|
|
461
|
+
// is established, it could talk back and we would think it has a localhost machineId, which
|
|
462
|
+
// is implicitly trusted, which would then give it access to everything.
|
|
463
|
+
if (locationObj.address === `127-0-0-1.${domain}` && nodeId.includes(":")) {
|
|
460
464
|
return {
|
|
461
465
|
threadId: "",
|
|
462
466
|
machineId: parts.at(-3) || "",
|
|
@@ -464,7 +468,8 @@ export function decodeNodeId(nodeId: string): NodeIdParts | undefined {
|
|
|
464
468
|
port: locationObj.port,
|
|
465
469
|
};
|
|
466
470
|
}
|
|
467
|
-
|
|
471
|
+
let isValid = parts.length >= 4 || allowMissingThreadId && parts.length === 3;
|
|
472
|
+
if (!isValid) {
|
|
468
473
|
return undefined;
|
|
469
474
|
}
|
|
470
475
|
return {
|
|
@@ -474,10 +479,10 @@ export function decodeNodeId(nodeId: string): NodeIdParts | undefined {
|
|
|
474
479
|
port: locationObj.port,
|
|
475
480
|
};
|
|
476
481
|
}
|
|
477
|
-
export function decodeNodeIdAssert(nodeId: string): NodeIdParts {
|
|
478
|
-
let result = decodeNodeId(nodeId);
|
|
482
|
+
export function decodeNodeIdAssert(nodeId: string, domain: string, allowMissingThreadId?: "allowMissingThreadId"): NodeIdParts {
|
|
483
|
+
let result = decodeNodeId(nodeId, domain, allowMissingThreadId);
|
|
479
484
|
if (!result) {
|
|
480
|
-
throw new Error(`Invalid nodeId: ${nodeId}`);
|
|
485
|
+
throw new Error(`Invalid nodeId: ${JSON.stringify(nodeId)}`);
|
|
481
486
|
}
|
|
482
487
|
return result;
|
|
483
488
|
}
|
|
@@ -523,7 +528,10 @@ export function getIdentityCAPromise(domain: string): MaybePromise<X509KeyPair>
|
|
|
523
528
|
|
|
524
529
|
|
|
525
530
|
export function getOwnMachineId(domain: string) {
|
|
526
|
-
return getMachineId(getIdentityCA(domain).domain);
|
|
531
|
+
return getMachineId(getIdentityCA(domain).domain, domain);
|
|
532
|
+
}
|
|
533
|
+
export function getOwnThreadId(domain: string) {
|
|
534
|
+
return decodeNodeIdAssert(getThreadKeyCert(domain).domain, domain).threadId;
|
|
527
535
|
}
|
|
528
536
|
|
|
529
537
|
/** Part of the machineId comes from the publicKey, so we can use it to verify */
|
|
@@ -533,7 +541,8 @@ export function verifyMachineIdForPublicKey(config: {
|
|
|
533
541
|
}): boolean {
|
|
534
542
|
let { machineId, publicKey } = config;
|
|
535
543
|
let domainPart = getDomainPartFromPublicKey(publicKey);
|
|
536
|
-
|
|
544
|
+
// machineId is the bare key-hash label, but also accept legacy "hash.domain.tld" forms
|
|
545
|
+
return machineId.split(".")[0] === domainPart;
|
|
537
546
|
}
|
|
538
547
|
|
|
539
548
|
// NOTE: We don't have a cache per CA, as... the CA should be set first
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function ellipsize(text: string, maxLength: number): string;
|
package/misc/strings.ts
ADDED