@dxos/keyring 0.1.56-next.a63ce79 → 0.1.56

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.
@@ -19,7 +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
+ var __dxlog_file = "/mnt/ramdisk/work/packages/core/halo/keyring/src/keyring.ts";
23
23
  var KeyRecord = schema.getCodecForType("dxos.halo.keyring.KeyRecord");
24
24
  var Keyring = class {
25
25
  constructor(_storage = createStorage({
@@ -138,6 +138,10 @@ var Keyring = class {
138
138
  }
139
139
  return keys;
140
140
  }
141
+ async importKeyPair(keyPair) {
142
+ await this._setKey(keyPair);
143
+ return keyPairToPublicKey(keyPair);
144
+ }
141
145
  };
142
146
  _ts_decorate([
143
147
  synchronized
@@ -148,7 +152,46 @@ _ts_decorate([
148
152
  var keyPairToPublicKey = async (keyPair) => {
149
153
  return PublicKey.from(new Uint8Array(await subtleCrypto.exportKey("raw", keyPair.publicKey)));
150
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
+ };
151
192
  export {
152
- Keyring
193
+ Keyring,
194
+ generateJWKKeyPair,
195
+ parseJWKKeyPair
153
196
  };
154
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 { 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\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": ["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"]
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":16115,"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/index.ts":{"bytes":465,"imports":[{"path":"packages/core/halo/keyring/src/keyring.ts","kind":"import-statement","original":"./keyring"}],"format":"esm"}},"outputs":{"packages/core/halo/keyring/dist/lib/browser/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":7671},"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}],"exports":["Keyring"],"entryPoint":"packages/core/halo/keyring/src/index.ts","inputs":{"packages/core/halo/keyring/src/keyring.ts":{"bytesInOutput":4800},"packages/core/halo/keyring/src/index.ts":{"bytesInOutput":0}},"bytes":4936}}}
1
+ {"inputs":{"packages/core/halo/keyring/src/keyring.ts":{"bytes":16567,"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":5163,"imports":[{"path":"@dxos/crypto","kind":"import-statement","external":true}],"format":"esm"},"packages/core/halo/keyring/src/index.ts":{"bytes":542,"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":4900},"packages/core/halo/keyring/src/index.ts":{"bytesInOutput":0},"packages/core/halo/keyring/src/testing.ts":{"bytesInOutput":1103}},"bytes":6226}}}
@@ -20,7 +20,9 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // packages/core/halo/keyring/src/index.ts
21
21
  var src_exports = {};
22
22
  __export(src_exports, {
23
- Keyring: () => Keyring
23
+ Keyring: () => Keyring,
24
+ generateJWKKeyPair: () => generateJWKKeyPair,
25
+ parseJWKKeyPair: () => parseJWKKeyPair
24
26
  });
25
27
  module.exports = __toCommonJS(src_exports);
26
28
 
@@ -43,7 +45,7 @@ function _ts_decorate(decorators, target, key, desc) {
43
45
  r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
44
46
  return c > 3 && r && Object.defineProperty(target, key, r), r;
45
47
  }
46
- var __dxlog_file = "/home/runner/work/dxos/dxos/packages/core/halo/keyring/src/keyring.ts";
48
+ var __dxlog_file = "/mnt/ramdisk/work/packages/core/halo/keyring/src/keyring.ts";
47
49
  var KeyRecord = import_protocols.schema.getCodecForType("dxos.halo.keyring.KeyRecord");
48
50
  var Keyring = class {
49
51
  constructor(_storage = (0, import_random_access_storage.createStorage)({
@@ -162,6 +164,10 @@ var Keyring = class {
162
164
  }
163
165
  return keys;
164
166
  }
167
+ async importKeyPair(keyPair) {
168
+ await this._setKey(keyPair);
169
+ return keyPairToPublicKey(keyPair);
170
+ }
165
171
  };
166
172
  _ts_decorate([
167
173
  import_async.synchronized
@@ -172,8 +178,47 @@ _ts_decorate([
172
178
  var keyPairToPublicKey = async (keyPair) => {
173
179
  return import_keys.PublicKey.from(new Uint8Array(await import_crypto.subtleCrypto.exportKey("raw", keyPair.publicKey)));
174
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
+ };
175
218
  // Annotate the CommonJS export names for ESM import in node:
176
219
  0 && (module.exports = {
177
- Keyring
220
+ Keyring,
221
+ generateJWKKeyPair,
222
+ parseJWKKeyPair
178
223
  });
179
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 { 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\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":16115,"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/index.ts":{"bytes":465,"imports":[{"path":"packages/core/halo/keyring/src/keyring.ts","kind":"import-statement","original":"./keyring"}],"format":"esm"}},"outputs":{"packages/core/halo/keyring/dist/lib/node/index.cjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":7741},"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}],"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":5201}},"bytes":6345}}}
1
+ {"inputs":{"packages/core/halo/keyring/src/keyring.ts":{"bytes":16567,"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":5163,"imports":[{"path":"@dxos/crypto","kind":"import-statement","external":true}],"format":"esm"},"packages/core/halo/keyring/src/index.ts":{"bytes":542,"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":5301},"packages/core/halo/keyring/src/testing.ts":{"bytesInOutput":1171}},"bytes":7793}}}
@@ -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":"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;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-next.a63ce79",
3
+ "version": "0.1.56",
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
- "@dxos/async": "0.1.56-next.a63ce79",
20
- "@dxos/codec-protobuf": "0.1.56-next.a63ce79",
21
- "@dxos/crypto": "0.1.56-next.a63ce79",
22
- "@dxos/debug": "0.1.56-next.a63ce79",
23
- "@dxos/invariant": "0.1.56-next.a63ce79",
24
- "@dxos/keys": "0.1.56-next.a63ce79",
25
- "@dxos/log": "0.1.56-next.a63ce79",
26
- "@dxos/node-std": "0.1.56-next.a63ce79",
27
- "@dxos/protocols": "0.1.56-next.a63ce79",
28
- "@dxos/random-access-storage": "0.1.56-next.a63ce79",
29
- "@dxos/util": "0.1.56-next.a63ce79"
19
+ "@dxos/async": "0.1.56",
20
+ "@dxos/codec-protobuf": "0.1.56",
21
+ "@dxos/crypto": "0.1.56",
22
+ "@dxos/debug": "0.1.56",
23
+ "@dxos/invariant": "0.1.56",
24
+ "@dxos/keys": "0.1.56",
25
+ "@dxos/log": "0.1.56",
26
+ "@dxos/node-std": "0.1.56",
27
+ "@dxos/protocols": "0.1.56",
28
+ "@dxos/random-access-storage": "0.1.56",
29
+ "@dxos/util": "0.1.56"
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
@@ -135,6 +135,11 @@ export class Keyring implements Signer {
135
135
  }
136
136
  return keys;
137
137
  }
138
+
139
+ async importKeyPair(keyPair: CryptoKeyPair): Promise<PublicKey> {
140
+ await this._setKey(keyPair);
141
+ return keyPairToPublicKey(keyPair);
142
+ }
138
143
  }
139
144
 
140
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
+ };