@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.
@@ -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
- invariant(record.privateKey, "Corrupted keyring: Missing private key");
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 invariant from 'tiny-invariant';\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 { 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\nconst keyPairToPublicKey = async (keyPair: CryptoKeyPair): Promise<PublicKey> => {\n return PublicKey.from(new Uint8Array(await subtleCrypto.exportKey('raw', keyPair.publicKey)));\n};\n"],
5
- "mappings": ";;;AAIA,OAAOA,eAAe;AAEtB,SAASC,OAAOC,oBAAoB;AAEpC,SAASC,oBAA4B;AACrC,SAASC,YAAY;AACrB,SAASC,iBAAiB;AAC1B,SAASC,cAAc;AAEvB,SAASC,eAA0BC,mBAAmB;AACtD,SAASC,YAAYC,qBAAqB;;;;;;;;;;;AAE1C,IAAMC,YAAmCC,OAAOC,gBAAgB,6BAAA;AAKzD,IAAMC,UAAN,MAAMA;EAIXC,YACmBC,WAAsBC,cAAc;IACnDC,MAAMC,YAAYC;EACpB,CAAA,EAAGC,gBAAgB,SAAA,GACnB;oBAHiBL;SAJFM,YAAY,IAAIC,WAAqCC,UAAUC,IAAI;SAC3EC,aAAa,IAAIC,MAAAA;AAOxBC,cAAUC,cAAc,iDAAA;EAC1B;EAEA,MAAMC,KAAKC,KAAgBC,SAA0C;AACnE,UAAMC,UAAU,MAAM,KAAKC,QAAQH,GAAAA;AAEnC,WAAO,IAAII,WACT,MAAMN,aAAaC,KACjB;MACEM,MAAM;MACNX,MAAM;IACR,GACAQ,QAAQI,YACRL,OAAAA,CAAAA;EAGN;EAEA,MAAMM,YAAgC;AACpC,UAAML,UAAU,MAAMJ,aAAaU,YACjC;MACEH,MAAM;MACNI,YAAY;IACd,GACA,MACA;MAAC;MAAQ;KAAS;AAGpB,UAAM,KAAKC,QAAQR,OAAAA;AAEnB,WAAOS,mBAAmBT,OAAAA;EAC5B;EAEA,MACcC,QAAQH,KAAwC;AAC5D,QAAI,CAAC,KAAKT,UAAUqB,IAAIZ,GAAAA,GAAM;AAC5B,YAAMa,OAAO,KAAK5B,SAAS6B,gBAAgBd,IAAIe,MAAK,CAAA;AACpD,YAAM,EAAEC,KAAI,IAAK,MAAMH,KAAKI,KAAI;AAChC,UAAID,SAAS,GAAG;AACd,cAAM,IAAIE,MAAM,kBAAkBlB,IAAIe,MAAK,GAAI;MACjD;AAEA,YAAMI,cAAc,MAAMN,KAAKO,KAAK,GAAGJ,IAAAA;AACvC,YAAMH,KAAKQ,MAAK;AAEhB,YAAMC,SAAS1C,UAAU2C,OAAOJ,WAAAA;AAChC,YAAMK,YAAY/B,UAAUgC,KAAKH,OAAOE,SAAS;AACjD3B,gBAAUG,IAAI0B,OAAOF,SAAAA,GAAY,iCAAA;AACjC3B,gBAAUyB,OAAOhB,YAAY,wCAAA;AAC7B,YAAMJ,UAAyB;QAC7BsB,WAAW,MAAM1B,aAAa6B,UAC5B,OACAL,OAAOE,WACP;UACEnB,MAAM;UACNI,YAAY;QACd,GACA,MACA;UAAC;SAAS;QAEZH,YAAY,MAAMR,aAAa6B,UAC7B,SACAL,OAAOhB,YACP;UACED,MAAM;UACNI,YAAY;QACd,GACA,MACA;UAAC;SAAO;MAEZ;AAEA,WAAKlB,UAAUqC,IAAIJ,WAAWtB,OAAAA;IAChC;AAEA,WAAO,KAAKX,UAAUsC,IAAI7B,GAAAA;EAC5B;EAEA,MACcU,QAAQR,SAAwB;AAC5C,UAAMsB,YAAY,MAAMb,mBAAmBT,OAAAA;AAC3C,SAAKX,UAAUqC,IAAIJ,WAAWtB,OAAAA;AAE9B,UAAMoB,SAAoB;MACxBE,WAAWA,UAAUM,aAAY;MACjCxB,YAAY,IAAIF,WAAW,MAAMN,aAAaiC,UAAU,SAAS7B,QAAQI,UAAU,CAAA;IACrF;AAEA,UAAMO,OAAO,KAAK5B,SAAS6B,gBAAgBU,UAAUT,MAAK,CAAA;AAC1D,UAAMF,KAAKmB,MAAM,GAAGC,cAAcrD,UAAUsD,OAAOZ,MAAAA,CAAAA,CAAAA;AACnD,UAAMT,KAAKQ,MAAK;AAChB,SAAK1B,WAAWwC,KAAI;EACtB;;EAGAC,UAAUpC,KAA+B;AACvC,WAAOqC,KAAK,oCAAA;EACd;EAEA,MAAMC,OAA6B;AACjC,UAAMC,OAAoB,CAAA;AAC1B,eAAWC,QAAQ,MAAM,KAAKvD,SAASqD,KAAI,GAAI;AAC7C,YAAMG,WAAWD,KAAKE,MAAM,GAAA,EAAKC,IAAG;AACpC9C,gBAAU4C,UAAU,mBAAA;AACpBF,WAAKK,KAAK;QAAEpB,WAAW/B,UAAUoD,QAAQJ,QAAAA,EAAUX,aAAY;MAAG,CAAA;IACpE;AACA,WAAOS;EACT;AACF;;EA3EGO;GA1CU/D,QAAAA,WAAAA,WAAAA,IAAAA;;EAuFV+D;GAvFU/D,QAAAA,WAAAA,WAAAA,IAAAA;AAuHb,IAAM4B,qBAAqB,OAAOT,YAAAA;AAChC,SAAOT,UAAUgC,KAAK,IAAIrB,WAAW,MAAMN,aAAaiC,UAAU,OAAO7B,QAAQsB,SAAS,CAAA,CAAA;AAC5F;",
6
- "names": ["invariant", "Event", "synchronized", "subtleCrypto", "todo", "PublicKey", "schema", "createStorage", "StorageType", "ComplexMap", "arrayToBuffer", "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/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": ";;;AAIA,SAASA,OAAOC,oBAAoB;AAEpC,SAASC,oBAA4B;AACrC,SAASC,YAAY;AACrB,SAASC,iBAAiB;AAC1B,SAASC,iBAAiB;AAC1B,SAASC,cAAc;AAEvB,SAASC,eAA0BC,mBAAmB;AACtD,SAASC,YAAYC,qBAAqB;;;;;;;;;;;;AAE1C,IAAMC,YAAmCL,OAAOM,gBAAgB,6BAAA;AAKzD,IAAMC,UAAN,MAAMA;EAIXC,YACmBC,WAAsBR,cAAc;IACnDS,MAAMR,YAAYS;EACpB,CAAA,EAAGC,gBAAgB,SAAA,GACnB;oBAHiBH;SAJFI,YAAY,IAAIV,WAAqCJ,UAAUe,IAAI;SAC3EC,aAAa,IAAIrB,MAAAA;AAOxBI,cAAUF,cAAc,mDAAA;;;;;;;;;EAC1B;EAEA,MAAMoB,KAAKC,KAAgBC,SAA0C;AACnE,UAAMC,UAAU,MAAM,KAAKC,QAAQH,GAAAA;AAEnC,WAAO,IAAII,WACT,MAAMzB,aAAaoB,KACjB;MACEM,MAAM;MACNR,MAAM;IACR,GACAK,QAAQI,YACRL,OAAAA,CAAAA;EAGN;EAEA,MAAMM,YAAgC;AACpC,UAAML,UAAU,MAAMvB,aAAa6B,YACjC;MACEH,MAAM;MACNI,YAAY;IACd,GACA,MACA;MAAC;MAAQ;KAAS;AAGpB,UAAM,KAAKC,QAAQR,OAAAA;AAEnB,WAAOS,mBAAmBT,OAAAA;EAC5B;EAEA,MACcC,QAAQH,KAAwC;AAC5D,QAAI,CAAC,KAAKJ,UAAUgB,IAAIZ,GAAAA,GAAM;AAC5B,YAAMa,OAAO,KAAKrB,SAASsB,gBAAgBd,IAAIe,MAAK,CAAA;AACpD,YAAM,EAAEC,KAAI,IAAK,MAAMH,KAAKI,KAAI;AAChC,UAAID,SAAS,GAAG;AACd,cAAM,IAAIE,MAAM,kBAAkBlB,IAAIe,MAAK,CAAA,EAAI;MACjD;AAEA,YAAMI,cAAc,MAAMN,KAAKO,KAAK,GAAGJ,IAAAA;AACvC,YAAMH,KAAKQ,MAAK;AAEhB,YAAMC,SAASlC,UAAUmC,OAAOJ,WAAAA;AAChC,YAAMK,YAAY1C,UAAU2C,KAAKH,OAAOE,SAAS;AACjD3C,gBAAUmB,IAAI0B,OAAOF,SAAAA,GAAY,mCAAA;;;;;;;;;AACjC3C,gBAAUyC,OAAOhB,YAAY,0CAAA;;;;;;;;;AAC7B,YAAMJ,UAAyB;QAC7BsB,WAAW,MAAM7C,aAAagD,UAC5B,OACAL,OAAOE,WACP;UACEnB,MAAM;UACNI,YAAY;QACd,GACA,MACA;UAAC;SAAS;QAEZH,YAAY,MAAM3B,aAAagD,UAC7B,SACAL,OAAOhB,YACP;UACED,MAAM;UACNI,YAAY;QACd,GACA,MACA;UAAC;SAAO;MAEZ;AAEA,WAAKb,UAAUgC,IAAIJ,WAAWtB,OAAAA;IAChC;AAEA,WAAO,KAAKN,UAAUiC,IAAI7B,GAAAA;EAC5B;EAEA,MACcU,QAAQR,SAAwB;AAC5C,UAAMsB,YAAY,MAAMb,mBAAmBT,OAAAA;AAC3C,SAAKN,UAAUgC,IAAIJ,WAAWtB,OAAAA;AAE9B,UAAMoB,SAAoB;MACxBE,WAAWA,UAAUM,aAAY;MACjCxB,YAAY,IAAIF,WAAW,MAAMzB,aAAaoD,UAAU,SAAS7B,QAAQI,UAAU,CAAA;IACrF;AAEA,UAAMO,OAAO,KAAKrB,SAASsB,gBAAgBU,UAAUT,MAAK,CAAA;AAC1D,UAAMF,KAAKmB,MAAM,GAAG7C,cAAcC,UAAU6C,OAAOX,MAAAA,CAAAA,CAAAA;AACnD,UAAMT,KAAKQ,MAAK;AAChB,SAAKvB,WAAWoC,KAAI;EACtB;;EAGAC,UAAUnC,KAA+B;AACvC,WAAOpB,KAAK,oCAAA;EACd;EAEA,MAAMwD,OAA6B;AACjC,UAAMC,OAAoB,CAAA;AAC1B,eAAWC,QAAQ,MAAM,KAAK9C,SAAS4C,KAAI,GAAI;AAC7C,YAAMG,WAAWD,KAAKE,MAAM,GAAA,EAAKC,IAAG;AACpC5D,gBAAU0D,UAAU,qBAAA;;;;;;;;;AACpBF,WAAKK,KAAK;QAAElB,WAAW1C,UAAU6D,QAAQJ,QAAAA,EAAUT,aAAY;MAAG,CAAA;IACpE;AACA,WAAOO;EACT;EAEA,MAAMO,cAAc1C,SAA4C;AAC9D,UAAM,KAAKQ,QAAQR,OAAAA;AACnB,WAAOS,mBAAmBT,OAAAA;EAC5B;AACF;;EAhFGxB;GA1CUY,QAAAA,WAAAA,WAAAA,IAAAA;;EAuFVZ;GAvFUY,QAAAA,WAAAA,WAAAA,IAAAA;AA4Hb,IAAMqB,qBAAqB,OAAOT,YAAAA;AAChC,SAAOpB,UAAU2C,KAAK,IAAIrB,WAAW,MAAMzB,aAAaoD,UAAU,OAAO7B,QAAQsB,SAAS,CAAA,CAAA;AAC5F;;;AC9IA,SAASqB,gBAAAA,qBAAoB;AAYtB,IAAMC,qBAAqB,YAAA;AAChC,QAAMC,UAAU,MAAMC,cAAaC,YACjC;IACEC,MAAM;IACNC,YAAY;EACd,GACA,MACA;IAAC;IAAQ;GAAS;AAGpB,QAAMC,qBAAqB,MAAMJ,cAAaK,UAAU,OAAON,QAAQO,UAAU;AACjF,QAAMC,oBAAoB,MAAMP,cAAaK,UAAU,OAAON,QAAQS,SAAS;AAG/E,QAAMC,kBAAkB,IAAIC,WAAW,MAAMV,cAAaK,UAAU,OAAON,QAAQS,SAAS,CAAA;AAC5F,QAAMG,eAAeC,MAAMC,KAAKJ,eAAAA,EAC7BK,IAAI,CAACC,SAASA,KAAKC,SAAS,EAAA,EAAIC,SAAS,GAAG,GAAA,CAAA,EAC5CC,KAAK,EAAA;AAER,SAAO;IACLZ,YAAYF;IACZI,WAAWD;IACXI;EACF;AACF;AAKO,IAAMQ,kBAAkB,OAAOb,YAAwBE,cAAAA;AAC5D,SAAO;IACLF,YAAY,MAAMN,cAAaoB,UAAU,OAAOd,YAAY;MAAEJ,MAAM;MAASC,YAAY;IAAQ,GAAG,MAAM;MAAC;KAAO;IAClHK,WAAW,MAAMR,cAAaoB,UAAU,OAAOZ,WAAW;MAAEN,MAAM;MAASC,YAAY;IAAQ,GAAG,MAAM;MAAC;KAAS;EACpH;AACF;",
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":15150,"imports":[{"path":"tiny-invariant","kind":"import-statement","external":true},{"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/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}]},"packages/core/halo/keyring/src/index.ts":{"bytes":465,"imports":[{"path":"packages/core/halo/keyring/src/keyring.ts","kind":"import-statement","original":"./keyring"}]}},"outputs":{"packages/core/halo/keyring/dist/lib/browser/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":7767},"packages/core/halo/keyring/dist/lib/browser/index.mjs":{"imports":[{"path":"tiny-invariant","kind":"import-statement","external":true},{"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/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}],"exports":["Keyring"],"entryPoint":"packages/core/halo/keyring/src/index.ts","inputs":{"packages/core/halo/keyring/src/keyring.ts":{"bytesInOutput":4047},"packages/core/halo/keyring/src/index.ts":{"bytesInOutput":0}},"bytes":4183}}}
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}}}
@@ -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, import_tiny_invariant.default)(import_crypto.subtleCrypto, "SubtleCrypto not available in this environment.");
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, import_tiny_invariant.default)(key.equals(publicKey), "Corrupted keyring: Key mismatch");
96
- (0, import_tiny_invariant.default)(record.privateKey, "Corrupted keyring: Missing private key");
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, import_tiny_invariant.default)(fileName, "Invalid file name");
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 invariant from 'tiny-invariant';\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 { 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\nconst keyPairToPublicKey = async (keyPair: CryptoKeyPair): Promise<PublicKey> => {\n return PublicKey.from(new Uint8Array(await subtleCrypto.exportKey('raw', keyPair.publicKey)));\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", "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
  }
@@ -1 +1 @@
1
- {"inputs":{"packages/core/halo/keyring/src/keyring.ts":{"bytes":15150,"imports":[{"path":"tiny-invariant","kind":"import-statement","external":true},{"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/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}]},"packages/core/halo/keyring/src/index.ts":{"bytes":465,"imports":[{"path":"packages/core/halo/keyring/src/keyring.ts","kind":"import-statement","original":"./keyring"}]}},"outputs":{"packages/core/halo/keyring/dist/lib/node/index.cjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":7734},"packages/core/halo/keyring/dist/lib/node/index.cjs":{"imports":[{"path":"tiny-invariant","kind":"require-call","external":true},{"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/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}],"exports":[],"entryPoint":"packages/core/halo/keyring/src/index.ts","inputs":{"packages/core/halo/keyring/src/index.ts":{"bytesInOutput":119},"packages/core/halo/keyring/src/keyring.ts":{"bytesInOutput":4478}},"bytes":6219}}}
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,2 +1,3 @@
1
1
  export * from './keyring';
2
+ export * from './testing';
2
3
  //# sourceMappingURL=index.d.ts.map
@@ -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":"AAMA,OAAO,EAAE,KAAK,EAAgB,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAgB,MAAM,EAAE,MAAM,cAAc,CAAC;AAEpD,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;CASnC"}
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.e47dfd1",
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
- "tiny-invariant": "^1.3.1",
20
- "@dxos/async": "0.1.56-main.e47dfd1",
21
- "@dxos/codec-protobuf": "0.1.56-main.e47dfd1",
22
- "@dxos/crypto": "0.1.56-main.e47dfd1",
23
- "@dxos/debug": "0.1.56-main.e47dfd1",
24
- "@dxos/keys": "0.1.56-main.e47dfd1",
25
- "@dxos/log": "0.1.56-main.e47dfd1",
26
- "@dxos/node-std": "0.1.56-main.e47dfd1",
27
- "@dxos/protocols": "0.1.56-main.e47dfd1",
28
- "@dxos/random-access-storage": "0.1.56-main.e47dfd1",
29
- "@dxos/util": "0.1.56-main.e47dfd1"
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
@@ -3,3 +3,4 @@
3
3
  //
4
4
 
5
5
  export * from './keyring';
6
+ export * from './testing';
@@ -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
+ };