@dxos/keyring 0.1.56-main.e47dfd1 → 0.1.56-main.e79d64a
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/dist/lib/browser/index.mjs +82 -6
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node/index.cjs +85 -17
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/types/src/index.d.ts +1 -0
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/keyring.d.ts +1 -0
- package/dist/types/src/keyring.d.ts.map +1 -1
- package/dist/types/src/testing.d.ts +15 -0
- package/dist/types/src/testing.d.ts.map +1 -0
- package/package.json +12 -12
- package/src/index.ts +1 -0
- package/src/keyring.test.ts +9 -0
- package/src/keyring.ts +6 -2
- package/src/testing.ts +51 -0
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import "@dxos/node-std/globals";
|
|
2
2
|
|
|
3
3
|
// packages/core/halo/keyring/src/keyring.ts
|
|
4
|
-
import invariant from "tiny-invariant";
|
|
5
4
|
import { Event, synchronized } from "@dxos/async";
|
|
6
5
|
import { subtleCrypto } from "@dxos/crypto";
|
|
7
6
|
import { todo } from "@dxos/debug";
|
|
7
|
+
import { invariant } from "@dxos/invariant";
|
|
8
8
|
import { PublicKey } from "@dxos/keys";
|
|
9
9
|
import { schema } from "@dxos/protocols";
|
|
10
10
|
import { createStorage, StorageType } from "@dxos/random-access-storage";
|
|
@@ -19,6 +19,7 @@ function _ts_decorate(decorators, target, key, desc) {
|
|
|
19
19
|
r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
20
20
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
21
21
|
}
|
|
22
|
+
var __dxlog_file = "/home/runner/work/dxos/dxos/packages/core/halo/keyring/src/keyring.ts";
|
|
22
23
|
var KeyRecord = schema.getCodecForType("dxos.halo.keyring.KeyRecord");
|
|
23
24
|
var Keyring = class {
|
|
24
25
|
constructor(_storage = createStorage({
|
|
@@ -27,7 +28,15 @@ var Keyring = class {
|
|
|
27
28
|
this._storage = _storage;
|
|
28
29
|
this._keyCache = new ComplexMap(PublicKey.hash);
|
|
29
30
|
this.keysUpdate = new Event();
|
|
30
|
-
invariant(subtleCrypto, "SubtleCrypto not available in this environment."
|
|
31
|
+
invariant(subtleCrypto, "SubtleCrypto not available in this environment.", {
|
|
32
|
+
F: __dxlog_file,
|
|
33
|
+
L: 30,
|
|
34
|
+
S: this,
|
|
35
|
+
A: [
|
|
36
|
+
"subtleCrypto",
|
|
37
|
+
"'SubtleCrypto not available in this environment.'"
|
|
38
|
+
]
|
|
39
|
+
});
|
|
31
40
|
}
|
|
32
41
|
async sign(key, message) {
|
|
33
42
|
const keyPair = await this._getKey(key);
|
|
@@ -58,8 +67,24 @@ var Keyring = class {
|
|
|
58
67
|
await file.close();
|
|
59
68
|
const record = KeyRecord.decode(recordBytes);
|
|
60
69
|
const publicKey = PublicKey.from(record.publicKey);
|
|
61
|
-
invariant(key.equals(publicKey), "Corrupted keyring: Key mismatch"
|
|
62
|
-
|
|
70
|
+
invariant(key.equals(publicKey), "Corrupted keyring: Key mismatch", {
|
|
71
|
+
F: __dxlog_file,
|
|
72
|
+
L: 77,
|
|
73
|
+
S: this,
|
|
74
|
+
A: [
|
|
75
|
+
"key.equals(publicKey)",
|
|
76
|
+
"'Corrupted keyring: Key mismatch'"
|
|
77
|
+
]
|
|
78
|
+
});
|
|
79
|
+
invariant(record.privateKey, "Corrupted keyring: Missing private key", {
|
|
80
|
+
F: __dxlog_file,
|
|
81
|
+
L: 78,
|
|
82
|
+
S: this,
|
|
83
|
+
A: [
|
|
84
|
+
"record.privateKey",
|
|
85
|
+
"'Corrupted keyring: Missing private key'"
|
|
86
|
+
]
|
|
87
|
+
});
|
|
63
88
|
const keyPair = {
|
|
64
89
|
publicKey: await subtleCrypto.importKey("raw", record.publicKey, {
|
|
65
90
|
name: "ECDSA",
|
|
@@ -98,13 +123,25 @@ var Keyring = class {
|
|
|
98
123
|
const keys = [];
|
|
99
124
|
for (const path of await this._storage.list()) {
|
|
100
125
|
const fileName = path.split("/").pop();
|
|
101
|
-
invariant(fileName, "Invalid file name"
|
|
126
|
+
invariant(fileName, "Invalid file name", {
|
|
127
|
+
F: __dxlog_file,
|
|
128
|
+
L: 133,
|
|
129
|
+
S: this,
|
|
130
|
+
A: [
|
|
131
|
+
"fileName",
|
|
132
|
+
"'Invalid file name'"
|
|
133
|
+
]
|
|
134
|
+
});
|
|
102
135
|
keys.push({
|
|
103
136
|
publicKey: PublicKey.fromHex(fileName).asUint8Array()
|
|
104
137
|
});
|
|
105
138
|
}
|
|
106
139
|
return keys;
|
|
107
140
|
}
|
|
141
|
+
async importKeyPair(keyPair) {
|
|
142
|
+
await this._setKey(keyPair);
|
|
143
|
+
return keyPairToPublicKey(keyPair);
|
|
144
|
+
}
|
|
108
145
|
};
|
|
109
146
|
_ts_decorate([
|
|
110
147
|
synchronized
|
|
@@ -115,7 +152,46 @@ _ts_decorate([
|
|
|
115
152
|
var keyPairToPublicKey = async (keyPair) => {
|
|
116
153
|
return PublicKey.from(new Uint8Array(await subtleCrypto.exportKey("raw", keyPair.publicKey)));
|
|
117
154
|
};
|
|
155
|
+
|
|
156
|
+
// packages/core/halo/keyring/src/testing.ts
|
|
157
|
+
import { subtleCrypto as subtleCrypto2 } from "@dxos/crypto";
|
|
158
|
+
var generateJWKKeyPair = async () => {
|
|
159
|
+
const keyPair = await subtleCrypto2.generateKey({
|
|
160
|
+
name: "ECDSA",
|
|
161
|
+
namedCurve: "P-256"
|
|
162
|
+
}, true, [
|
|
163
|
+
"sign",
|
|
164
|
+
"verify"
|
|
165
|
+
]);
|
|
166
|
+
const privateKeyExported = await subtleCrypto2.exportKey("jwk", keyPair.privateKey);
|
|
167
|
+
const publicKeyExported = await subtleCrypto2.exportKey("jwk", keyPair.publicKey);
|
|
168
|
+
const publicKeyBuffer = new Uint8Array(await subtleCrypto2.exportKey("raw", keyPair.publicKey));
|
|
169
|
+
const publicKeyHex = Array.from(publicKeyBuffer).map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
170
|
+
return {
|
|
171
|
+
privateKey: privateKeyExported,
|
|
172
|
+
publicKey: publicKeyExported,
|
|
173
|
+
publicKeyHex
|
|
174
|
+
};
|
|
175
|
+
};
|
|
176
|
+
var parseJWKKeyPair = async (privateKey, publicKey) => {
|
|
177
|
+
return {
|
|
178
|
+
privateKey: await subtleCrypto2.importKey("jwk", privateKey, {
|
|
179
|
+
name: "ECDSA",
|
|
180
|
+
namedCurve: "P-256"
|
|
181
|
+
}, true, [
|
|
182
|
+
"sign"
|
|
183
|
+
]),
|
|
184
|
+
publicKey: await subtleCrypto2.importKey("jwk", publicKey, {
|
|
185
|
+
name: "ECDSA",
|
|
186
|
+
namedCurve: "P-256"
|
|
187
|
+
}, true, [
|
|
188
|
+
"verify"
|
|
189
|
+
])
|
|
190
|
+
};
|
|
191
|
+
};
|
|
118
192
|
export {
|
|
119
|
-
Keyring
|
|
193
|
+
Keyring,
|
|
194
|
+
generateJWKKeyPair,
|
|
195
|
+
parseJWKKeyPair
|
|
120
196
|
};
|
|
121
197
|
//# sourceMappingURL=index.mjs.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../../../src/keyring.ts"],
|
|
4
|
-
"sourcesContent": ["//\n// Copyright 2022 DXOS.org\n//\n\nimport
|
|
5
|
-
"mappings": ";;;AAIA,
|
|
6
|
-
"names": ["
|
|
3
|
+
"sources": ["../../../src/keyring.ts", "../../../src/testing.ts"],
|
|
4
|
+
"sourcesContent": ["//\n// Copyright 2022 DXOS.org\n//\n\nimport { Event, synchronized } from '@dxos/async';\nimport { ProtoCodec } from '@dxos/codec-protobuf';\nimport { subtleCrypto, Signer } from '@dxos/crypto';\nimport { todo } from '@dxos/debug';\nimport { invariant } from '@dxos/invariant';\nimport { PublicKey } from '@dxos/keys';\nimport { schema } from '@dxos/protocols';\nimport { KeyRecord } from '@dxos/protocols/proto/dxos/halo/keyring';\nimport { createStorage, Directory, StorageType } from '@dxos/random-access-storage';\nimport { ComplexMap, arrayToBuffer } from '@dxos/util';\n\nconst KeyRecord: ProtoCodec<KeyRecord> = schema.getCodecForType('dxos.halo.keyring.KeyRecord');\n\n/**\n * Manages keys.\n */\nexport class Keyring implements Signer {\n private readonly _keyCache = new ComplexMap<PublicKey, CryptoKeyPair>(PublicKey.hash);\n readonly keysUpdate = new Event();\n\n constructor(\n private readonly _storage: Directory = createStorage({\n type: StorageType.RAM,\n }).createDirectory('keyring'),\n ) {\n invariant(subtleCrypto, 'SubtleCrypto not available in this environment.');\n }\n\n async sign(key: PublicKey, message: Uint8Array): Promise<Uint8Array> {\n const keyPair = await this._getKey(key);\n\n return new Uint8Array(\n await subtleCrypto.sign(\n {\n name: 'ECDSA',\n hash: 'SHA-256',\n },\n keyPair.privateKey,\n message,\n ),\n );\n }\n\n async createKey(): Promise<PublicKey> {\n const keyPair = await subtleCrypto.generateKey(\n {\n name: 'ECDSA',\n namedCurve: 'P-256',\n },\n true,\n ['sign', 'verify'],\n );\n\n await this._setKey(keyPair);\n\n return keyPairToPublicKey(keyPair);\n }\n\n @synchronized\n private async _getKey(key: PublicKey): Promise<CryptoKeyPair> {\n if (!this._keyCache.has(key)) {\n const file = this._storage.getOrCreateFile(key.toHex());\n const { size } = await file.stat();\n if (size === 0) {\n throw new Error(`Key not found: ${key.toHex()}`);\n }\n\n const recordBytes = await file.read(0, size);\n await file.close();\n\n const record = KeyRecord.decode(recordBytes);\n const publicKey = PublicKey.from(record.publicKey);\n invariant(key.equals(publicKey), 'Corrupted keyring: Key mismatch');\n invariant(record.privateKey, 'Corrupted keyring: Missing private key');\n const keyPair: CryptoKeyPair = {\n publicKey: await subtleCrypto.importKey(\n 'raw',\n record.publicKey,\n {\n name: 'ECDSA',\n namedCurve: 'P-256',\n },\n true,\n ['verify'],\n ),\n privateKey: await subtleCrypto.importKey(\n 'pkcs8',\n record.privateKey,\n {\n name: 'ECDSA',\n namedCurve: 'P-256',\n },\n true,\n ['sign'],\n ),\n };\n\n this._keyCache.set(publicKey, keyPair);\n }\n\n return this._keyCache.get(key)!; // TODO(burdon): Fail if null?\n }\n\n @synchronized\n private async _setKey(keyPair: CryptoKeyPair) {\n const publicKey = await keyPairToPublicKey(keyPair);\n this._keyCache.set(publicKey, keyPair);\n\n const record: KeyRecord = {\n publicKey: publicKey.asUint8Array(),\n privateKey: new Uint8Array(await subtleCrypto.exportKey('pkcs8', keyPair.privateKey)),\n };\n\n const file = this._storage.getOrCreateFile(publicKey.toHex());\n await file.write(0, arrayToBuffer(KeyRecord.encode(record)));\n await file.close();\n this.keysUpdate.emit();\n }\n\n // TODO(burdon): ???\n deleteKey(key: PublicKey): Promise<void> {\n return todo('We need a method to delete a file.');\n }\n\n async list(): Promise<KeyRecord[]> {\n const keys: KeyRecord[] = [];\n for (const path of await this._storage.list()) {\n const fileName = path.split('/').pop(); // get last portion of the path\n invariant(fileName, 'Invalid file name');\n keys.push({ publicKey: PublicKey.fromHex(fileName).asUint8Array() });\n }\n return keys;\n }\n\n async importKeyPair(keyPair: CryptoKeyPair): Promise<PublicKey> {\n await this._setKey(keyPair);\n return keyPairToPublicKey(keyPair);\n }\n}\n\nconst keyPairToPublicKey = async (keyPair: CryptoKeyPair): Promise<PublicKey> => {\n return PublicKey.from(new Uint8Array(await subtleCrypto.exportKey('raw', keyPair.publicKey)));\n};\n", "//\n// Copyright 2023 DXOS.org\n//\n\nimport { subtleCrypto } from '@dxos/crypto';\n\nexport type TestKeyPair = {\n privateKey: JsonWebKey;\n publicKey: JsonWebKey;\n publicKeyHex: string;\n};\n\n/**\n * Generate a key pair which for testing purposes.\n * @returns {Promise<TestKeyPair>}\n */\nexport const generateJWKKeyPair = async (): Promise<TestKeyPair> => {\n const keyPair = await subtleCrypto.generateKey(\n {\n name: 'ECDSA',\n namedCurve: 'P-256',\n },\n true,\n ['sign', 'verify'],\n );\n\n const privateKeyExported = await subtleCrypto.exportKey('jwk', keyPair.privateKey);\n const publicKeyExported = await subtleCrypto.exportKey('jwk', keyPair.publicKey);\n\n // Convert the public key to hex format\n const publicKeyBuffer = new Uint8Array(await subtleCrypto.exportKey('raw', keyPair.publicKey));\n const publicKeyHex = Array.from(publicKeyBuffer)\n .map((byte) => byte.toString(16).padStart(2, '0'))\n .join('');\n\n return {\n privateKey: privateKeyExported,\n publicKey: publicKeyExported,\n publicKeyHex,\n };\n};\n\n/**\n * Parse a key pair from JWK format.\n */\nexport const parseJWKKeyPair = async (privateKey: JsonWebKey, publicKey: JsonWebKey): Promise<CryptoKeyPair> => {\n return {\n privateKey: await subtleCrypto.importKey('jwk', privateKey, { name: 'ECDSA', namedCurve: 'P-256' }, true, ['sign']),\n publicKey: await subtleCrypto.importKey('jwk', publicKey, { name: 'ECDSA', namedCurve: 'P-256' }, true, ['verify']),\n };\n};\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["Event", "synchronized", "subtleCrypto", "todo", "invariant", "PublicKey", "schema", "createStorage", "StorageType", "ComplexMap", "arrayToBuffer", "KeyRecord", "getCodecForType", "Keyring", "constructor", "_storage", "type", "RAM", "createDirectory", "_keyCache", "hash", "keysUpdate", "sign", "key", "message", "keyPair", "_getKey", "Uint8Array", "name", "privateKey", "createKey", "generateKey", "namedCurve", "_setKey", "keyPairToPublicKey", "has", "file", "getOrCreateFile", "toHex", "size", "stat", "Error", "recordBytes", "read", "close", "record", "decode", "publicKey", "from", "equals", "importKey", "set", "get", "asUint8Array", "exportKey", "write", "encode", "emit", "deleteKey", "list", "keys", "path", "fileName", "split", "pop", "push", "fromHex", "importKeyPair", "subtleCrypto", "generateJWKKeyPair", "keyPair", "subtleCrypto", "generateKey", "name", "namedCurve", "privateKeyExported", "exportKey", "privateKey", "publicKeyExported", "publicKey", "publicKeyBuffer", "Uint8Array", "publicKeyHex", "Array", "from", "map", "byte", "toString", "padStart", "join", "parseJWKKeyPair", "importKey"]
|
|
7
7
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"inputs":{"packages/core/halo/keyring/src/keyring.ts":{"bytes":
|
|
1
|
+
{"inputs":{"packages/core/halo/keyring/src/keyring.ts":{"bytes":16577,"imports":[{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/crypto","kind":"import-statement","external":true},{"path":"@dxos/debug","kind":"import-statement","external":true},{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"@dxos/keys","kind":"import-statement","external":true},{"path":"@dxos/protocols","kind":"import-statement","external":true},{"path":"@dxos/random-access-storage","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true}],"format":"esm"},"packages/core/halo/keyring/src/testing.ts":{"bytes":5173,"imports":[{"path":"@dxos/crypto","kind":"import-statement","external":true}],"format":"esm"},"packages/core/halo/keyring/src/index.ts":{"bytes":552,"imports":[{"path":"packages/core/halo/keyring/src/keyring.ts","kind":"import-statement","original":"./keyring"},{"path":"packages/core/halo/keyring/src/testing.ts","kind":"import-statement","original":"./testing"}],"format":"esm"}},"outputs":{"packages/core/halo/keyring/dist/lib/browser/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":10517},"packages/core/halo/keyring/dist/lib/browser/index.mjs":{"imports":[{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/crypto","kind":"import-statement","external":true},{"path":"@dxos/debug","kind":"import-statement","external":true},{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"@dxos/keys","kind":"import-statement","external":true},{"path":"@dxos/protocols","kind":"import-statement","external":true},{"path":"@dxos/random-access-storage","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true},{"path":"@dxos/crypto","kind":"import-statement","external":true}],"exports":["Keyring","generateJWKKeyPair","parseJWKKeyPair"],"entryPoint":"packages/core/halo/keyring/src/index.ts","inputs":{"packages/core/halo/keyring/src/keyring.ts":{"bytesInOutput":4910},"packages/core/halo/keyring/src/index.ts":{"bytesInOutput":0},"packages/core/halo/keyring/src/testing.ts":{"bytesInOutput":1103}},"bytes":6236}}}
|
package/dist/lib/node/index.cjs
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __create = Object.create;
|
|
3
2
|
var __defProp = Object.defineProperty;
|
|
4
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
7
5
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
6
|
var __export = (target, all) => {
|
|
9
7
|
for (var name in all)
|
|
@@ -17,28 +15,22 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
17
15
|
}
|
|
18
16
|
return to;
|
|
19
17
|
};
|
|
20
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
-
mod
|
|
27
|
-
));
|
|
28
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
19
|
|
|
30
20
|
// packages/core/halo/keyring/src/index.ts
|
|
31
21
|
var src_exports = {};
|
|
32
22
|
__export(src_exports, {
|
|
33
|
-
Keyring: () => Keyring
|
|
23
|
+
Keyring: () => Keyring,
|
|
24
|
+
generateJWKKeyPair: () => generateJWKKeyPair,
|
|
25
|
+
parseJWKKeyPair: () => parseJWKKeyPair
|
|
34
26
|
});
|
|
35
27
|
module.exports = __toCommonJS(src_exports);
|
|
36
28
|
|
|
37
29
|
// packages/core/halo/keyring/src/keyring.ts
|
|
38
|
-
var import_tiny_invariant = __toESM(require("tiny-invariant"));
|
|
39
30
|
var import_async = require("@dxos/async");
|
|
40
31
|
var import_crypto = require("@dxos/crypto");
|
|
41
32
|
var import_debug = require("@dxos/debug");
|
|
33
|
+
var import_invariant = require("@dxos/invariant");
|
|
42
34
|
var import_keys = require("@dxos/keys");
|
|
43
35
|
var import_protocols = require("@dxos/protocols");
|
|
44
36
|
var import_random_access_storage = require("@dxos/random-access-storage");
|
|
@@ -53,6 +45,7 @@ function _ts_decorate(decorators, target, key, desc) {
|
|
|
53
45
|
r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
54
46
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
55
47
|
}
|
|
48
|
+
var __dxlog_file = "/home/runner/work/dxos/dxos/packages/core/halo/keyring/src/keyring.ts";
|
|
56
49
|
var KeyRecord = import_protocols.schema.getCodecForType("dxos.halo.keyring.KeyRecord");
|
|
57
50
|
var Keyring = class {
|
|
58
51
|
constructor(_storage = (0, import_random_access_storage.createStorage)({
|
|
@@ -61,7 +54,15 @@ var Keyring = class {
|
|
|
61
54
|
this._storage = _storage;
|
|
62
55
|
this._keyCache = new import_util.ComplexMap(import_keys.PublicKey.hash);
|
|
63
56
|
this.keysUpdate = new import_async.Event();
|
|
64
|
-
(0,
|
|
57
|
+
(0, import_invariant.invariant)(import_crypto.subtleCrypto, "SubtleCrypto not available in this environment.", {
|
|
58
|
+
F: __dxlog_file,
|
|
59
|
+
L: 30,
|
|
60
|
+
S: this,
|
|
61
|
+
A: [
|
|
62
|
+
"subtleCrypto",
|
|
63
|
+
"'SubtleCrypto not available in this environment.'"
|
|
64
|
+
]
|
|
65
|
+
});
|
|
65
66
|
}
|
|
66
67
|
async sign(key, message) {
|
|
67
68
|
const keyPair = await this._getKey(key);
|
|
@@ -92,8 +93,24 @@ var Keyring = class {
|
|
|
92
93
|
await file.close();
|
|
93
94
|
const record = KeyRecord.decode(recordBytes);
|
|
94
95
|
const publicKey = import_keys.PublicKey.from(record.publicKey);
|
|
95
|
-
(0,
|
|
96
|
-
|
|
96
|
+
(0, import_invariant.invariant)(key.equals(publicKey), "Corrupted keyring: Key mismatch", {
|
|
97
|
+
F: __dxlog_file,
|
|
98
|
+
L: 77,
|
|
99
|
+
S: this,
|
|
100
|
+
A: [
|
|
101
|
+
"key.equals(publicKey)",
|
|
102
|
+
"'Corrupted keyring: Key mismatch'"
|
|
103
|
+
]
|
|
104
|
+
});
|
|
105
|
+
(0, import_invariant.invariant)(record.privateKey, "Corrupted keyring: Missing private key", {
|
|
106
|
+
F: __dxlog_file,
|
|
107
|
+
L: 78,
|
|
108
|
+
S: this,
|
|
109
|
+
A: [
|
|
110
|
+
"record.privateKey",
|
|
111
|
+
"'Corrupted keyring: Missing private key'"
|
|
112
|
+
]
|
|
113
|
+
});
|
|
97
114
|
const keyPair = {
|
|
98
115
|
publicKey: await import_crypto.subtleCrypto.importKey("raw", record.publicKey, {
|
|
99
116
|
name: "ECDSA",
|
|
@@ -132,13 +149,25 @@ var Keyring = class {
|
|
|
132
149
|
const keys = [];
|
|
133
150
|
for (const path of await this._storage.list()) {
|
|
134
151
|
const fileName = path.split("/").pop();
|
|
135
|
-
(0,
|
|
152
|
+
(0, import_invariant.invariant)(fileName, "Invalid file name", {
|
|
153
|
+
F: __dxlog_file,
|
|
154
|
+
L: 133,
|
|
155
|
+
S: this,
|
|
156
|
+
A: [
|
|
157
|
+
"fileName",
|
|
158
|
+
"'Invalid file name'"
|
|
159
|
+
]
|
|
160
|
+
});
|
|
136
161
|
keys.push({
|
|
137
162
|
publicKey: import_keys.PublicKey.fromHex(fileName).asUint8Array()
|
|
138
163
|
});
|
|
139
164
|
}
|
|
140
165
|
return keys;
|
|
141
166
|
}
|
|
167
|
+
async importKeyPair(keyPair) {
|
|
168
|
+
await this._setKey(keyPair);
|
|
169
|
+
return keyPairToPublicKey(keyPair);
|
|
170
|
+
}
|
|
142
171
|
};
|
|
143
172
|
_ts_decorate([
|
|
144
173
|
import_async.synchronized
|
|
@@ -149,8 +178,47 @@ _ts_decorate([
|
|
|
149
178
|
var keyPairToPublicKey = async (keyPair) => {
|
|
150
179
|
return import_keys.PublicKey.from(new Uint8Array(await import_crypto.subtleCrypto.exportKey("raw", keyPair.publicKey)));
|
|
151
180
|
};
|
|
181
|
+
|
|
182
|
+
// packages/core/halo/keyring/src/testing.ts
|
|
183
|
+
var import_crypto2 = require("@dxos/crypto");
|
|
184
|
+
var generateJWKKeyPair = async () => {
|
|
185
|
+
const keyPair = await import_crypto2.subtleCrypto.generateKey({
|
|
186
|
+
name: "ECDSA",
|
|
187
|
+
namedCurve: "P-256"
|
|
188
|
+
}, true, [
|
|
189
|
+
"sign",
|
|
190
|
+
"verify"
|
|
191
|
+
]);
|
|
192
|
+
const privateKeyExported = await import_crypto2.subtleCrypto.exportKey("jwk", keyPair.privateKey);
|
|
193
|
+
const publicKeyExported = await import_crypto2.subtleCrypto.exportKey("jwk", keyPair.publicKey);
|
|
194
|
+
const publicKeyBuffer = new Uint8Array(await import_crypto2.subtleCrypto.exportKey("raw", keyPair.publicKey));
|
|
195
|
+
const publicKeyHex = Array.from(publicKeyBuffer).map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
196
|
+
return {
|
|
197
|
+
privateKey: privateKeyExported,
|
|
198
|
+
publicKey: publicKeyExported,
|
|
199
|
+
publicKeyHex
|
|
200
|
+
};
|
|
201
|
+
};
|
|
202
|
+
var parseJWKKeyPair = async (privateKey, publicKey) => {
|
|
203
|
+
return {
|
|
204
|
+
privateKey: await import_crypto2.subtleCrypto.importKey("jwk", privateKey, {
|
|
205
|
+
name: "ECDSA",
|
|
206
|
+
namedCurve: "P-256"
|
|
207
|
+
}, true, [
|
|
208
|
+
"sign"
|
|
209
|
+
]),
|
|
210
|
+
publicKey: await import_crypto2.subtleCrypto.importKey("jwk", publicKey, {
|
|
211
|
+
name: "ECDSA",
|
|
212
|
+
namedCurve: "P-256"
|
|
213
|
+
}, true, [
|
|
214
|
+
"verify"
|
|
215
|
+
])
|
|
216
|
+
};
|
|
217
|
+
};
|
|
152
218
|
// Annotate the CommonJS export names for ESM import in node:
|
|
153
219
|
0 && (module.exports = {
|
|
154
|
-
Keyring
|
|
220
|
+
Keyring,
|
|
221
|
+
generateJWKKeyPair,
|
|
222
|
+
parseJWKKeyPair
|
|
155
223
|
});
|
|
156
224
|
//# sourceMappingURL=index.cjs.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../../../src/index.ts", "../../../src/keyring.ts"],
|
|
4
|
-
"sourcesContent": ["//\n// Copyright 2022 DXOS.org\n//\n\nexport * from './keyring';\n", "//\n// Copyright 2022 DXOS.org\n//\n\nimport
|
|
5
|
-
"mappings": "
|
|
6
|
-
"names": ["KeyRecord", "schema", "getCodecForType", "Keyring", "constructor", "_storage", "createStorage", "type", "StorageType", "RAM", "createDirectory", "_keyCache", "ComplexMap", "PublicKey", "hash", "keysUpdate", "Event", "invariant", "subtleCrypto", "sign", "key", "message", "keyPair", "_getKey", "Uint8Array", "name", "privateKey", "createKey", "generateKey", "namedCurve", "_setKey", "keyPairToPublicKey", "has", "file", "getOrCreateFile", "toHex", "size", "stat", "Error", "recordBytes", "read", "close", "record", "decode", "publicKey", "from", "equals", "importKey", "set", "get", "asUint8Array", "exportKey", "write", "arrayToBuffer", "encode", "emit", "deleteKey", "todo", "list", "keys", "path", "fileName", "split", "pop", "push", "fromHex", "synchronized"]
|
|
3
|
+
"sources": ["../../../src/index.ts", "../../../src/keyring.ts", "../../../src/testing.ts"],
|
|
4
|
+
"sourcesContent": ["//\n// Copyright 2022 DXOS.org\n//\n\nexport * from './keyring';\nexport * from './testing';\n", "//\n// Copyright 2022 DXOS.org\n//\n\nimport { Event, synchronized } from '@dxos/async';\nimport { ProtoCodec } from '@dxos/codec-protobuf';\nimport { subtleCrypto, Signer } from '@dxos/crypto';\nimport { todo } from '@dxos/debug';\nimport { invariant } from '@dxos/invariant';\nimport { PublicKey } from '@dxos/keys';\nimport { schema } from '@dxos/protocols';\nimport { KeyRecord } from '@dxos/protocols/proto/dxos/halo/keyring';\nimport { createStorage, Directory, StorageType } from '@dxos/random-access-storage';\nimport { ComplexMap, arrayToBuffer } from '@dxos/util';\n\nconst KeyRecord: ProtoCodec<KeyRecord> = schema.getCodecForType('dxos.halo.keyring.KeyRecord');\n\n/**\n * Manages keys.\n */\nexport class Keyring implements Signer {\n private readonly _keyCache = new ComplexMap<PublicKey, CryptoKeyPair>(PublicKey.hash);\n readonly keysUpdate = new Event();\n\n constructor(\n private readonly _storage: Directory = createStorage({\n type: StorageType.RAM,\n }).createDirectory('keyring'),\n ) {\n invariant(subtleCrypto, 'SubtleCrypto not available in this environment.');\n }\n\n async sign(key: PublicKey, message: Uint8Array): Promise<Uint8Array> {\n const keyPair = await this._getKey(key);\n\n return new Uint8Array(\n await subtleCrypto.sign(\n {\n name: 'ECDSA',\n hash: 'SHA-256',\n },\n keyPair.privateKey,\n message,\n ),\n );\n }\n\n async createKey(): Promise<PublicKey> {\n const keyPair = await subtleCrypto.generateKey(\n {\n name: 'ECDSA',\n namedCurve: 'P-256',\n },\n true,\n ['sign', 'verify'],\n );\n\n await this._setKey(keyPair);\n\n return keyPairToPublicKey(keyPair);\n }\n\n @synchronized\n private async _getKey(key: PublicKey): Promise<CryptoKeyPair> {\n if (!this._keyCache.has(key)) {\n const file = this._storage.getOrCreateFile(key.toHex());\n const { size } = await file.stat();\n if (size === 0) {\n throw new Error(`Key not found: ${key.toHex()}`);\n }\n\n const recordBytes = await file.read(0, size);\n await file.close();\n\n const record = KeyRecord.decode(recordBytes);\n const publicKey = PublicKey.from(record.publicKey);\n invariant(key.equals(publicKey), 'Corrupted keyring: Key mismatch');\n invariant(record.privateKey, 'Corrupted keyring: Missing private key');\n const keyPair: CryptoKeyPair = {\n publicKey: await subtleCrypto.importKey(\n 'raw',\n record.publicKey,\n {\n name: 'ECDSA',\n namedCurve: 'P-256',\n },\n true,\n ['verify'],\n ),\n privateKey: await subtleCrypto.importKey(\n 'pkcs8',\n record.privateKey,\n {\n name: 'ECDSA',\n namedCurve: 'P-256',\n },\n true,\n ['sign'],\n ),\n };\n\n this._keyCache.set(publicKey, keyPair);\n }\n\n return this._keyCache.get(key)!; // TODO(burdon): Fail if null?\n }\n\n @synchronized\n private async _setKey(keyPair: CryptoKeyPair) {\n const publicKey = await keyPairToPublicKey(keyPair);\n this._keyCache.set(publicKey, keyPair);\n\n const record: KeyRecord = {\n publicKey: publicKey.asUint8Array(),\n privateKey: new Uint8Array(await subtleCrypto.exportKey('pkcs8', keyPair.privateKey)),\n };\n\n const file = this._storage.getOrCreateFile(publicKey.toHex());\n await file.write(0, arrayToBuffer(KeyRecord.encode(record)));\n await file.close();\n this.keysUpdate.emit();\n }\n\n // TODO(burdon): ???\n deleteKey(key: PublicKey): Promise<void> {\n return todo('We need a method to delete a file.');\n }\n\n async list(): Promise<KeyRecord[]> {\n const keys: KeyRecord[] = [];\n for (const path of await this._storage.list()) {\n const fileName = path.split('/').pop(); // get last portion of the path\n invariant(fileName, 'Invalid file name');\n keys.push({ publicKey: PublicKey.fromHex(fileName).asUint8Array() });\n }\n return keys;\n }\n\n async importKeyPair(keyPair: CryptoKeyPair): Promise<PublicKey> {\n await this._setKey(keyPair);\n return keyPairToPublicKey(keyPair);\n }\n}\n\nconst keyPairToPublicKey = async (keyPair: CryptoKeyPair): Promise<PublicKey> => {\n return PublicKey.from(new Uint8Array(await subtleCrypto.exportKey('raw', keyPair.publicKey)));\n};\n", "//\n// Copyright 2023 DXOS.org\n//\n\nimport { subtleCrypto } from '@dxos/crypto';\n\nexport type TestKeyPair = {\n privateKey: JsonWebKey;\n publicKey: JsonWebKey;\n publicKeyHex: string;\n};\n\n/**\n * Generate a key pair which for testing purposes.\n * @returns {Promise<TestKeyPair>}\n */\nexport const generateJWKKeyPair = async (): Promise<TestKeyPair> => {\n const keyPair = await subtleCrypto.generateKey(\n {\n name: 'ECDSA',\n namedCurve: 'P-256',\n },\n true,\n ['sign', 'verify'],\n );\n\n const privateKeyExported = await subtleCrypto.exportKey('jwk', keyPair.privateKey);\n const publicKeyExported = await subtleCrypto.exportKey('jwk', keyPair.publicKey);\n\n // Convert the public key to hex format\n const publicKeyBuffer = new Uint8Array(await subtleCrypto.exportKey('raw', keyPair.publicKey));\n const publicKeyHex = Array.from(publicKeyBuffer)\n .map((byte) => byte.toString(16).padStart(2, '0'))\n .join('');\n\n return {\n privateKey: privateKeyExported,\n publicKey: publicKeyExported,\n publicKeyHex,\n };\n};\n\n/**\n * Parse a key pair from JWK format.\n */\nexport const parseJWKKeyPair = async (privateKey: JsonWebKey, publicKey: JsonWebKey): Promise<CryptoKeyPair> => {\n return {\n privateKey: await subtleCrypto.importKey('jwk', privateKey, { name: 'ECDSA', namedCurve: 'P-256' }, true, ['sign']),\n publicKey: await subtleCrypto.importKey('jwk', publicKey, { name: 'ECDSA', namedCurve: 'P-256' }, true, ['verify']),\n };\n};\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["KeyRecord", "schema", "getCodecForType", "Keyring", "constructor", "_storage", "createStorage", "type", "StorageType", "RAM", "createDirectory", "_keyCache", "ComplexMap", "PublicKey", "hash", "keysUpdate", "Event", "invariant", "subtleCrypto", "sign", "key", "message", "keyPair", "_getKey", "Uint8Array", "name", "privateKey", "createKey", "generateKey", "namedCurve", "_setKey", "keyPairToPublicKey", "has", "file", "getOrCreateFile", "toHex", "size", "stat", "Error", "recordBytes", "read", "close", "record", "decode", "publicKey", "from", "equals", "importKey", "set", "get", "asUint8Array", "exportKey", "write", "arrayToBuffer", "encode", "emit", "deleteKey", "todo", "list", "keys", "path", "fileName", "split", "pop", "push", "fromHex", "importKeyPair", "synchronized", "import_crypto", "generateJWKKeyPair", "keyPair", "subtleCrypto", "generateKey", "name", "namedCurve", "privateKeyExported", "exportKey", "privateKey", "publicKeyExported", "publicKey", "publicKeyBuffer", "Uint8Array", "publicKeyHex", "Array", "from", "map", "byte", "toString", "padStart", "join", "parseJWKKeyPair", "importKey"]
|
|
7
7
|
}
|
package/dist/lib/node/meta.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"inputs":{"packages/core/halo/keyring/src/keyring.ts":{"bytes":
|
|
1
|
+
{"inputs":{"packages/core/halo/keyring/src/keyring.ts":{"bytes":16577,"imports":[{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/crypto","kind":"import-statement","external":true},{"path":"@dxos/debug","kind":"import-statement","external":true},{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"@dxos/keys","kind":"import-statement","external":true},{"path":"@dxos/protocols","kind":"import-statement","external":true},{"path":"@dxos/random-access-storage","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true}],"format":"esm"},"packages/core/halo/keyring/src/testing.ts":{"bytes":5173,"imports":[{"path":"@dxos/crypto","kind":"import-statement","external":true}],"format":"esm"},"packages/core/halo/keyring/src/index.ts":{"bytes":552,"imports":[{"path":"packages/core/halo/keyring/src/keyring.ts","kind":"import-statement","original":"./keyring"},{"path":"packages/core/halo/keyring/src/testing.ts","kind":"import-statement","original":"./testing"}],"format":"esm"}},"outputs":{"packages/core/halo/keyring/dist/lib/node/index.cjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":10618},"packages/core/halo/keyring/dist/lib/node/index.cjs":{"imports":[{"path":"@dxos/async","kind":"require-call","external":true},{"path":"@dxos/crypto","kind":"require-call","external":true},{"path":"@dxos/debug","kind":"require-call","external":true},{"path":"@dxos/invariant","kind":"require-call","external":true},{"path":"@dxos/keys","kind":"require-call","external":true},{"path":"@dxos/protocols","kind":"require-call","external":true},{"path":"@dxos/random-access-storage","kind":"require-call","external":true},{"path":"@dxos/util","kind":"require-call","external":true},{"path":"@dxos/crypto","kind":"require-call","external":true}],"exports":[],"entryPoint":"packages/core/halo/keyring/src/index.ts","inputs":{"packages/core/halo/keyring/src/index.ts":{"bytesInOutput":209},"packages/core/halo/keyring/src/keyring.ts":{"bytesInOutput":5311},"packages/core/halo/keyring/src/testing.ts":{"bytesInOutput":1171}},"bytes":7803}}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AAIA,cAAc,WAAW,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AAIA,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC"}
|
|
@@ -19,6 +19,7 @@ export declare class Keyring implements Signer {
|
|
|
19
19
|
private _setKey;
|
|
20
20
|
deleteKey(key: PublicKey): Promise<void>;
|
|
21
21
|
list(): Promise<KeyRecord[]>;
|
|
22
|
+
importKeyPair(keyPair: CryptoKeyPair): Promise<PublicKey>;
|
|
22
23
|
}
|
|
23
24
|
export {};
|
|
24
25
|
//# sourceMappingURL=keyring.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keyring.d.ts","sourceRoot":"","sources":["../../../src/keyring.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"keyring.d.ts","sourceRoot":"","sources":["../../../src/keyring.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,EAAgB,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAgB,MAAM,EAAE,MAAM,cAAc,CAAC;AAGpD,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEvC,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAiB,SAAS,EAAe,MAAM,6BAA6B,CAAC;AAGpF,QAAA,MAAM,SAAS,EAAE,UAAU,CAAC,SAAS,CAAyD,CAAC;AAE/F;;GAEG;AACH,qBAAa,OAAQ,YAAW,MAAM;IAKlC,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAJ3B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA4D;IACtF,QAAQ,CAAC,UAAU,cAAe;gBAGf,QAAQ,GAAE,SAEE;IAKzB,IAAI,CAAC,GAAG,EAAE,SAAS,EAAE,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;IAe9D,SAAS,IAAI,OAAO,CAAC,SAAS,CAAC;YAgBvB,OAAO;YA6CP,OAAO;IAgBrB,SAAS,CAAC,GAAG,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAIlC,IAAI,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;IAU5B,aAAa,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,SAAS,CAAC;CAIhE"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export type TestKeyPair = {
|
|
2
|
+
privateKey: JsonWebKey;
|
|
3
|
+
publicKey: JsonWebKey;
|
|
4
|
+
publicKeyHex: string;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* Generate a key pair which for testing purposes.
|
|
8
|
+
* @returns {Promise<TestKeyPair>}
|
|
9
|
+
*/
|
|
10
|
+
export declare const generateJWKKeyPair: () => Promise<TestKeyPair>;
|
|
11
|
+
/**
|
|
12
|
+
* Parse a key pair from JWK format.
|
|
13
|
+
*/
|
|
14
|
+
export declare const parseJWKKeyPair: (privateKey: JsonWebKey, publicKey: JsonWebKey) => Promise<CryptoKeyPair>;
|
|
15
|
+
//# sourceMappingURL=testing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../../../src/testing.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,WAAW,GAAG;IACxB,UAAU,EAAE,UAAU,CAAC;IACvB,SAAS,EAAE,UAAU,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,kBAAkB,QAAa,QAAQ,WAAW,CAwB9D,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,eAAe,eAAsB,UAAU,aAAa,UAAU,KAAG,QAAQ,aAAa,CAK1G,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/keyring",
|
|
3
|
-
"version": "0.1.56-main.
|
|
3
|
+
"version": "0.1.56-main.e79d64a",
|
|
4
4
|
"description": "Halo Keyring.",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -16,17 +16,17 @@
|
|
|
16
16
|
"src"
|
|
17
17
|
],
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"
|
|
20
|
-
"@dxos/
|
|
21
|
-
"@dxos/
|
|
22
|
-
"@dxos/
|
|
23
|
-
"@dxos/
|
|
24
|
-
"@dxos/keys": "0.1.56-main.
|
|
25
|
-
"@dxos/log": "0.1.56-main.
|
|
26
|
-
"@dxos/node-std": "0.1.56-main.
|
|
27
|
-
"@dxos/protocols": "0.1.56-main.
|
|
28
|
-
"@dxos/random-access-storage": "0.1.56-main.
|
|
29
|
-
"@dxos/util": "0.1.56-main.
|
|
19
|
+
"@dxos/async": "0.1.56-main.e79d64a",
|
|
20
|
+
"@dxos/codec-protobuf": "0.1.56-main.e79d64a",
|
|
21
|
+
"@dxos/crypto": "0.1.56-main.e79d64a",
|
|
22
|
+
"@dxos/debug": "0.1.56-main.e79d64a",
|
|
23
|
+
"@dxos/invariant": "0.1.56-main.e79d64a",
|
|
24
|
+
"@dxos/keys": "0.1.56-main.e79d64a",
|
|
25
|
+
"@dxos/log": "0.1.56-main.e79d64a",
|
|
26
|
+
"@dxos/node-std": "0.1.56-main.e79d64a",
|
|
27
|
+
"@dxos/protocols": "0.1.56-main.e79d64a",
|
|
28
|
+
"@dxos/random-access-storage": "0.1.56-main.e79d64a",
|
|
29
|
+
"@dxos/util": "0.1.56-main.e79d64a"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"@types/node": "^18.11.9"
|
package/src/index.ts
CHANGED
package/src/keyring.test.ts
CHANGED
|
@@ -10,6 +10,7 @@ import { createStorage, StorageType } from '@dxos/random-access-storage';
|
|
|
10
10
|
import { describe, test } from '@dxos/test';
|
|
11
11
|
|
|
12
12
|
import { Keyring } from './keyring';
|
|
13
|
+
import { generateJWKKeyPair, parseJWKKeyPair } from './testing';
|
|
13
14
|
|
|
14
15
|
describe('Keyring', () => {
|
|
15
16
|
test('sign & verify', async () => {
|
|
@@ -86,5 +87,13 @@ describe('Keyring', () => {
|
|
|
86
87
|
expect(emittedCount).toBe(count);
|
|
87
88
|
});
|
|
88
89
|
|
|
90
|
+
test('import key', async () => {
|
|
91
|
+
const keyring = new Keyring(createStorage({ type: StorageType.RAM }).createDirectory('keyring'));
|
|
92
|
+
|
|
93
|
+
const keyPair = await generateJWKKeyPair();
|
|
94
|
+
const key = await keyring.importKeyPair(await parseJWKKeyPair(keyPair.privateKey, keyPair.publicKey));
|
|
95
|
+
expect(keyPair.publicKeyHex).toEqual(key.toHex());
|
|
96
|
+
});
|
|
97
|
+
|
|
89
98
|
test('delete key', () => {});
|
|
90
99
|
});
|
package/src/keyring.ts
CHANGED
|
@@ -2,12 +2,11 @@
|
|
|
2
2
|
// Copyright 2022 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import invariant from 'tiny-invariant';
|
|
6
|
-
|
|
7
5
|
import { Event, synchronized } from '@dxos/async';
|
|
8
6
|
import { ProtoCodec } from '@dxos/codec-protobuf';
|
|
9
7
|
import { subtleCrypto, Signer } from '@dxos/crypto';
|
|
10
8
|
import { todo } from '@dxos/debug';
|
|
9
|
+
import { invariant } from '@dxos/invariant';
|
|
11
10
|
import { PublicKey } from '@dxos/keys';
|
|
12
11
|
import { schema } from '@dxos/protocols';
|
|
13
12
|
import { KeyRecord } from '@dxos/protocols/proto/dxos/halo/keyring';
|
|
@@ -136,6 +135,11 @@ export class Keyring implements Signer {
|
|
|
136
135
|
}
|
|
137
136
|
return keys;
|
|
138
137
|
}
|
|
138
|
+
|
|
139
|
+
async importKeyPair(keyPair: CryptoKeyPair): Promise<PublicKey> {
|
|
140
|
+
await this._setKey(keyPair);
|
|
141
|
+
return keyPairToPublicKey(keyPair);
|
|
142
|
+
}
|
|
139
143
|
}
|
|
140
144
|
|
|
141
145
|
const keyPairToPublicKey = async (keyPair: CryptoKeyPair): Promise<PublicKey> => {
|
package/src/testing.ts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2023 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { subtleCrypto } from '@dxos/crypto';
|
|
6
|
+
|
|
7
|
+
export type TestKeyPair = {
|
|
8
|
+
privateKey: JsonWebKey;
|
|
9
|
+
publicKey: JsonWebKey;
|
|
10
|
+
publicKeyHex: string;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Generate a key pair which for testing purposes.
|
|
15
|
+
* @returns {Promise<TestKeyPair>}
|
|
16
|
+
*/
|
|
17
|
+
export const generateJWKKeyPair = async (): Promise<TestKeyPair> => {
|
|
18
|
+
const keyPair = await subtleCrypto.generateKey(
|
|
19
|
+
{
|
|
20
|
+
name: 'ECDSA',
|
|
21
|
+
namedCurve: 'P-256',
|
|
22
|
+
},
|
|
23
|
+
true,
|
|
24
|
+
['sign', 'verify'],
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
const privateKeyExported = await subtleCrypto.exportKey('jwk', keyPair.privateKey);
|
|
28
|
+
const publicKeyExported = await subtleCrypto.exportKey('jwk', keyPair.publicKey);
|
|
29
|
+
|
|
30
|
+
// Convert the public key to hex format
|
|
31
|
+
const publicKeyBuffer = new Uint8Array(await subtleCrypto.exportKey('raw', keyPair.publicKey));
|
|
32
|
+
const publicKeyHex = Array.from(publicKeyBuffer)
|
|
33
|
+
.map((byte) => byte.toString(16).padStart(2, '0'))
|
|
34
|
+
.join('');
|
|
35
|
+
|
|
36
|
+
return {
|
|
37
|
+
privateKey: privateKeyExported,
|
|
38
|
+
publicKey: publicKeyExported,
|
|
39
|
+
publicKeyHex,
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Parse a key pair from JWK format.
|
|
45
|
+
*/
|
|
46
|
+
export const parseJWKKeyPair = async (privateKey: JsonWebKey, publicKey: JsonWebKey): Promise<CryptoKeyPair> => {
|
|
47
|
+
return {
|
|
48
|
+
privateKey: await subtleCrypto.importKey('jwk', privateKey, { name: 'ECDSA', namedCurve: 'P-256' }, true, ['sign']),
|
|
49
|
+
publicKey: await subtleCrypto.importKey('jwk', publicKey, { name: 'ECDSA', namedCurve: 'P-256' }, true, ['verify']),
|
|
50
|
+
};
|
|
51
|
+
};
|