sliftutils 1.5.3 → 1.5.4
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
CHANGED
|
@@ -70,7 +70,6 @@ declare module "sliftutils/misc/https/certs" {
|
|
|
70
70
|
/// <reference types="node" />
|
|
71
71
|
/// <reference types="node" />
|
|
72
72
|
import * as forge from "node-forge";
|
|
73
|
-
import { MaybePromise } from "socket-function/src/types";
|
|
74
73
|
export declare const CA_NOT_FOUND_ERROR = "18aa7318-f88f-4d2d-b41f-3daf4a433827";
|
|
75
74
|
export declare const identityStorageKey = "machineCA_12";
|
|
76
75
|
export type IdentityStorageType = {
|
|
@@ -121,7 +120,7 @@ declare module "sliftutils/misc/https/certs" {
|
|
|
121
120
|
export declare function setIdentityCARaw(domain: string, json: string): Promise<void>;
|
|
122
121
|
export declare function loadIdentityCA(domain: string): Promise<void>;
|
|
123
122
|
export declare function getIdentityCA(domain: string): X509KeyPair;
|
|
124
|
-
export declare function getIdentityCAPromise(domain: string):
|
|
123
|
+
export declare function getIdentityCAPromise(domain: string): X509KeyPair;
|
|
125
124
|
export declare function getOwnMachineId(domain: string): string;
|
|
126
125
|
export declare function getOwnThreadId(domain: string): string;
|
|
127
126
|
/** Part of the machineId comes from the publicKey, so we can use it to verify */
|
|
@@ -217,10 +216,9 @@ declare module "sliftutils/misc/https/node-forge-ed25519" {
|
|
|
217
216
|
}
|
|
218
217
|
|
|
219
218
|
declare module "sliftutils/misc/https/persistentLocalStorage" {
|
|
220
|
-
import { MaybePromise } from "socket-function/src/types";
|
|
221
219
|
export declare function getKeyStore<T>(appName: string, key: string): {
|
|
222
|
-
get():
|
|
223
|
-
set(value: T | null):
|
|
220
|
+
get(): T | undefined;
|
|
221
|
+
set(value: T | null): void;
|
|
224
222
|
};
|
|
225
223
|
|
|
226
224
|
}
|
package/misc/https/certs.d.ts
CHANGED
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
/// <reference types="node" />
|
|
4
4
|
/// <reference types="node" />
|
|
5
5
|
import * as forge from "node-forge";
|
|
6
|
-
import { MaybePromise } from "socket-function/src/types";
|
|
7
6
|
export declare const CA_NOT_FOUND_ERROR = "18aa7318-f88f-4d2d-b41f-3daf4a433827";
|
|
8
7
|
export declare const identityStorageKey = "machineCA_12";
|
|
9
8
|
export type IdentityStorageType = {
|
|
@@ -54,7 +53,7 @@ export declare function encodeNodeId(parts: NodeIdParts): string;
|
|
|
54
53
|
export declare function setIdentityCARaw(domain: string, json: string): Promise<void>;
|
|
55
54
|
export declare function loadIdentityCA(domain: string): Promise<void>;
|
|
56
55
|
export declare function getIdentityCA(domain: string): X509KeyPair;
|
|
57
|
-
export declare function getIdentityCAPromise(domain: string):
|
|
56
|
+
export declare function getIdentityCAPromise(domain: string): X509KeyPair;
|
|
58
57
|
export declare function getOwnMachineId(domain: string): string;
|
|
59
58
|
export declare function getOwnThreadId(domain: string): string;
|
|
60
59
|
/** Part of the machineId comes from the publicKey, so we can use it to verify */
|
package/misc/https/certs.ts
CHANGED
|
@@ -15,7 +15,6 @@ import crypto from "crypto";
|
|
|
15
15
|
import { trustCertificate } from "socket-function/src/certStore";
|
|
16
16
|
import { measureBlock, measureFnc, measureWrap } from "socket-function/src/profiling/measure";
|
|
17
17
|
import { getNodeIdDomain, getNodeIdDomainMaybeUndefined, getNodeIdLocation } from "socket-function/src/nodeCache";
|
|
18
|
-
import { MaybePromise } from "socket-function/src/types";
|
|
19
18
|
import { SocketFunction } from "socket-function/SocketFunction";
|
|
20
19
|
import { resetAllNodeCallFactories } from "socket-function/src/nodeCache";
|
|
21
20
|
import { getKeyStore } from "./persistentLocalStorage";
|
|
@@ -386,6 +385,14 @@ function validateAltNames(certParsed: forge.pki.Certificate, subject: string) {
|
|
|
386
385
|
}
|
|
387
386
|
|
|
388
387
|
|
|
388
|
+
// NOTE: We can't use crypto.subtle (non-extractable CryptoKeys) for our keys, because subtle
|
|
389
|
+
// is asynchronous, and everything here (key generation, cert creation, signing) must be
|
|
390
|
+
// available synchronously. The only real benefit of subtle is that a cross-site scripting
|
|
391
|
+
// attack can't exfiltrate the key. Which, while nice, is of minor benefit, as the cross-site
|
|
392
|
+
// script can already do quite a bit of damage anyway with access. And if that happens, the
|
|
393
|
+
// first thing the user is probably going to do is reset all their credentials, which solves
|
|
394
|
+
// the case of the key being exfiltrated anyway (by telling the server to stop trusting
|
|
395
|
+
// all identities).
|
|
389
396
|
export function generateKeyPair() {
|
|
390
397
|
return measureBlock(function generateKeyPair() {
|
|
391
398
|
// NOTE: We use ED25519 because it can generated keys about 10X faster, WHICH, is still slow
|
|
@@ -415,36 +422,32 @@ export function generateTestCA(domain: string) {
|
|
|
415
422
|
return createX509({ domain: fullDomain, issuer: "self", keyPair, lifeSpan: timeInDay * 365 * 20 });
|
|
416
423
|
}
|
|
417
424
|
|
|
418
|
-
let identityCA = cache((domain: string) => {
|
|
419
|
-
let
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
let fullDomain = `${caPublicKeyPart}.${domain}`;
|
|
425
|
+
let identityCA = cache((domain: string) => lazy((): X509KeyPair => {
|
|
426
|
+
let identityCACached = getIdentityStore(domain);
|
|
427
|
+
let caCached = identityCACached.get();
|
|
428
|
+
if (!caCached) {
|
|
429
|
+
console.log(`Generating new identity CA`);
|
|
430
|
+
const keyPair = generateKeyPair();
|
|
431
|
+
let caPublicKeyPart = getDomainPartFromPublicKey(keyPair.publicKey);
|
|
432
|
+
let fullDomain = `${caPublicKeyPart}.${domain}`;
|
|
427
433
|
|
|
428
|
-
|
|
434
|
+
let value = createX509({ domain: fullDomain, issuer: "self", keyPair, lifeSpan: timeInDay * 365 * 20 });
|
|
429
435
|
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
};
|
|
435
|
-
await identityCACached.set(caCached);
|
|
436
|
-
}
|
|
437
|
-
let result = {
|
|
438
|
-
domain: caCached.domain,
|
|
439
|
-
cert: Buffer.from(caCached.certB64, "base64"),
|
|
440
|
-
key: Buffer.from(caCached.keyB64, "base64"),
|
|
436
|
+
caCached = {
|
|
437
|
+
domain: value.domain,
|
|
438
|
+
certB64: value.cert.toString("base64"),
|
|
439
|
+
keyB64: value.key.toString("base64"),
|
|
441
440
|
};
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
441
|
+
identityCACached.set(caCached);
|
|
442
|
+
}
|
|
443
|
+
let result = {
|
|
444
|
+
domain: caCached.domain,
|
|
445
|
+
cert: Buffer.from(caCached.certB64, "base64"),
|
|
446
|
+
key: Buffer.from(caCached.keyB64, "base64"),
|
|
447
|
+
};
|
|
448
|
+
trustCertificate(result.cert.toString());
|
|
449
|
+
return result;
|
|
450
|
+
}));
|
|
448
451
|
|
|
449
452
|
// IMPORTANT! We do not embed any debug info in this domain. If we did, it would be useful,
|
|
450
453
|
// but... potentally a security vulnerability, as if the debug info (such as a prefix)
|
|
@@ -535,24 +538,23 @@ export async function setIdentityCARaw(domain: string, json: string) {
|
|
|
535
538
|
trustCertificate(ca.cert.toString());
|
|
536
539
|
identityCA(domain).set(ca);
|
|
537
540
|
getThreadKeyCertBase(domain).reset();
|
|
538
|
-
|
|
541
|
+
identityCACached.set(obj);
|
|
539
542
|
resetAllNodeCallFactories();
|
|
540
543
|
}
|
|
541
544
|
|
|
545
|
+
// NOTE: The identity CA is available synchronously (storage is fs/localStorage, both
|
|
546
|
+
// synchronous), so this only exists for backwards compatibility with startup code
|
|
547
|
+
// that awaits it.
|
|
542
548
|
export async function loadIdentityCA(domain: string) {
|
|
543
|
-
|
|
549
|
+
identityCA(domain)();
|
|
544
550
|
}
|
|
545
551
|
export function getIdentityCA(domain: string): X509KeyPair {
|
|
546
|
-
|
|
547
|
-
if (value instanceof Promise) {
|
|
548
|
-
throw new Error(`Identity CA is not yet loaded. Call and wait for loadIdentityCA(${JSON.stringify(domain)}) in your startup before accessing the identity (or call getIdentityCAPromise(${JSON.stringify(domain)}))`);
|
|
549
|
-
}
|
|
550
|
-
return value;
|
|
552
|
+
return identityCA(domain)();
|
|
551
553
|
}
|
|
552
554
|
|
|
553
555
|
// TODO: Replace this with a database, so it is easy for us to trust CAs
|
|
554
556
|
// cross machine, and even have multiple users, etc, etc.
|
|
555
|
-
export function getIdentityCAPromise(domain: string):
|
|
557
|
+
export function getIdentityCAPromise(domain: string): X509KeyPair {
|
|
556
558
|
return identityCA(domain)();
|
|
557
559
|
}
|
|
558
560
|
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { MaybePromise } from "socket-function/src/types";
|
|
2
1
|
export declare function getKeyStore<T>(appName: string, key: string): {
|
|
3
|
-
get():
|
|
4
|
-
set(value: T | null):
|
|
2
|
+
get(): T | undefined;
|
|
3
|
+
set(value: T | null): void;
|
|
5
4
|
};
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { isNode } from "socket-function/src/misc";
|
|
2
2
|
import fs from "fs";
|
|
3
3
|
import os from "os";
|
|
4
|
-
import { MaybePromise } from "socket-function/src/types";
|
|
5
4
|
import { cache } from "socket-function/src/caching";
|
|
6
5
|
|
|
7
6
|
export function getKeyStore<T>(appName: string, key: string): {
|
|
8
|
-
get():
|
|
9
|
-
set(value: T | null):
|
|
7
|
+
get(): T | undefined;
|
|
8
|
+
set(value: T | null): void;
|
|
10
9
|
} {
|
|
11
10
|
if (isNode()) {
|
|
12
11
|
let path = os.homedir() + `/keystore_${appName}_` + key + ".json";
|