Add comprehensive installation and setup documentation

- Add GETTING_STARTED.md with quick start guide and development modes
- Add INSTALL.sh automated installation script
- Add INSTALLATION_CHECKLIST.md, INSTALLATION_SUCCESS.md, and INSTALLATION_SUMMARY.md
- Add QUICK_REFERENCE.md for common commands
- Add SETUP_GUIDE.md with detailed setup instructions
- Update README.md with improved project overview
- Add did-wallet app dependencies and node_modules
This commit is contained in:
Dorian
2026-01-27 17:18:21 +00:00
parent a81f655133
commit 0d073fa89e
22658 changed files with 4494151 additions and 6 deletions
+41
View File
@@ -0,0 +1,41 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
/**
* Represents a Web5 Identity with its DID and metadata.
*/
export class BearerIdentity {
constructor({ did, metadata }) {
this.did = did;
this.metadata = metadata;
}
/**
* Converts a `BearerIdentity` object to a portable format containing the DID and metadata
* associated with the Identity.
*
* @example
* ```ts
* // Assuming `identity` is an instance of BearerIdentity.
* const portableIdentity = await identity.export();
* // portableIdentity now contains the and metadata.
* ```
*
* @returns A `PortableIdentity` containing the DID and metadata associated with the
* `BearerIdentity`.
*/
export() {
return __awaiter(this, void 0, void 0, function* () {
return {
portableDid: yield this.did.export(),
metadata: this.metadata
};
});
}
}
//# sourceMappingURL=bearer-identity.js.map
@@ -0,0 +1 @@
{"version":3,"file":"bearer-identity.js","sourceRoot":"","sources":["../../src/bearer-identity.ts"],"names":[],"mappings":";;;;;;;;;AAGA;;GAEG;AACH,MAAM,OAAO,cAAc;IAOzB,YAAY,EAAE,GAAG,EAAE,QAAQ,EAG1B;QACC,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;QACf,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,CAAC;IAED;;;;;;;;;;;;;OAaG;IACU,MAAM;;YACjB,OAAO;gBACL,WAAW,EAAG,MAAM,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE;gBACrC,QAAQ,EAAM,IAAI,CAAC,QAAQ;aAC5B,CAAC;QACJ,CAAC;KAAA;CACF"}
+346
View File
@@ -0,0 +1,346 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { Sha2Algorithm, computeJwkThumbprint } from '@web5/crypto';
import { HkdfAlgorithm } from './prototyping/crypto/algorithms/hkdf.js';
import { EcdsaAlgorithm } from './prototyping/crypto/algorithms/ecdsa.js';
import { EdDsaAlgorithm } from './prototyping/crypto/algorithms/eddsa.js';
import { AesKwAlgorithm } from './prototyping/crypto/algorithms/aes-kw.js';
import { Pbkdf2Algorithm } from './prototyping/crypto/algorithms/pbkdf2.js';
import { AesGcmAlgorithm } from './prototyping/crypto/algorithms/aes-gcm.js';
import { CryptoError, CryptoErrorCode } from './prototyping/crypto/crypto-error.js';
/**
* `supportedAlgorithms` is an object mapping algorithm names to their respective implementations
* Each entry in this map specifies the algorithm name and its associated properties, including the
* implementation class and any relevant names or identifiers for the algorithm. This structure
* allows for easy retrieval and instantiation of algorithm implementations based on the algorithm
* name or key specification. It facilitates the support of multiple algorithms within the
* `LocalKeyManager` class.
*/
const supportedAlgorithms = {
'AES-GCM': {
implementation: AesGcmAlgorithm,
names: ['A128GCM', 'A192GCM', 'A256GCM'],
operations: ['bytesToPrivateKey', 'decrypt', 'encrypt', 'generateKey'],
},
'AES-KW': {
implementation: AesKwAlgorithm,
names: ['A128KW', 'A192KW', 'A256KW'],
operations: ['bytesToPrivateKey', 'generateKey', 'privateKeyToBytes', 'wrapKey', 'unwrapKey'],
},
'Ed25519': {
implementation: EdDsaAlgorithm,
names: ['Ed25519'],
operations: ['bytesToPrivateKey', 'bytesToPublicKey', 'generateKey', 'sign', 'verify'],
},
'HKDF': {
implementation: HkdfAlgorithm,
names: ['HKDF-256', 'HKDF-384', 'HKDF-512'],
operations: ['deriveKey', 'deriveKeyBytes'],
},
'PBKDF2': {
implementation: Pbkdf2Algorithm,
names: ['PBES2-HS256+A128KW', 'PBES2-HS384+A192KW', 'PBES2-HS512+A256KW'],
operations: ['deriveKey', 'deriveKeyBytes'],
},
'secp256k1': {
implementation: EcdsaAlgorithm,
names: ['ES256K', 'secp256k1'],
operations: ['bytesToPrivateKey', 'bytesToPublicKey', 'generateKey', 'sign', 'verify'],
},
'secp256r1': {
implementation: EcdsaAlgorithm,
names: ['ES256', 'secp256r1'],
operations: ['bytesToPrivateKey', 'bytesToPublicKey', 'generateKey', 'sign', 'verify'],
},
'SHA-256': {
implementation: Sha2Algorithm,
names: ['SHA-256'],
operations: ['digest'],
}
};
export class AgentCryptoApi {
constructor() {
/**
* A private map that stores instances of cryptographic algorithm implementations. Each key in
* this map is an `AlgorithmConstructor`, and its corresponding value is an instance of a class
* that implements a specific cryptographic algorithm. This map is used to cache and reuse
* instances for performance optimization, ensuring that each algorithm is instantiated only once.
*/
this._algorithmInstances = new Map();
}
bytesToPrivateKey({ algorithm: algorithmIdentifier, privateKeyBytes }) {
return __awaiter(this, void 0, void 0, function* () {
// Determine the algorithm name based on the given algorithm identifier.
const algorithm = this.getAlgorithmName({ algorithm: algorithmIdentifier });
// Get the key converter based on the algorithm name.
const keyConverter = this.getAlgorithm({ algorithm });
// Convert the byte array to a JWK.
const privateKey = yield keyConverter.bytesToPrivateKey({ algorithm: algorithmIdentifier, privateKeyBytes });
return privateKey;
});
}
bytesToPublicKey({ algorithm: algorithmIdentifier, publicKeyBytes }) {
return __awaiter(this, void 0, void 0, function* () {
// Determine the algorithm name based on the given algorithm identifier.
const algorithm = this.getAlgorithmName({ algorithm: algorithmIdentifier });
// Get the key converter based on the algorithm name.
const keyConverter = this.getAlgorithm({ algorithm });
// Convert the byte array to a JWK.
const publicKey = yield keyConverter.bytesToPublicKey({ algorithm: algorithmIdentifier, publicKeyBytes });
return publicKey;
});
}
decrypt(params) {
return __awaiter(this, void 0, void 0, function* () {
// Determine the algorithm name based on the JWK's `alg` property.
const algorithm = this.getAlgorithmName({ key: params.key });
// Get the cipher algorithm based on the algorithm name.
const cipher = this.getAlgorithm({ algorithm });
// Decrypt the data.
return yield cipher.decrypt(params);
});
}
deriveKey(params) {
var _a, _b;
return __awaiter(this, void 0, void 0, function* () {
// Determine the algorithm name based on the given algorithm identifier.
const algorithm = this.getAlgorithmName({ algorithm: params.algorithm });
// Get the key derivation function based on the algorithm name.
const kdf = this.getAlgorithm({ algorithm });
let derivedKeyAlgorithm;
switch (params.algorithm) {
case 'HKDF-256':
case 'HKDF-384':
case 'HKDF-512': {
derivedKeyAlgorithm = params.derivedKeyAlgorithm;
break;
}
case 'PBES2-HS256+A128KW':
case 'PBES2-HS384+A192KW':
case 'PBES2-HS512+A256KW': {
derivedKeyAlgorithm = params.algorithm.split(/[-+]/)[2];
break;
}
default:
throw new CryptoError(CryptoErrorCode.AlgorithmNotSupported, `The specified "algorithm" is not supported: ${params.algorithm}`);
}
// Determine the bit length of the derived key based on the given algorithm.
const length = +((_b = (_a = derivedKeyAlgorithm.match(/\d+/)) === null || _a === void 0 ? void 0 : _a[0]) !== null && _b !== void 0 ? _b : -1);
if (length === -1) {
throw new CryptoError(CryptoErrorCode.AlgorithmNotSupported, `The derived key algorithm" is not supported: ${derivedKeyAlgorithm}`);
}
// Derive the byte array.
const privateKeyBytes = yield kdf.deriveKeyBytes(Object.assign(Object.assign({}, params), { length }));
return yield this.bytesToPrivateKey({ algorithm: derivedKeyAlgorithm, privateKeyBytes });
});
}
deriveKeyBytes(params) {
return __awaiter(this, void 0, void 0, function* () {
// Determine the algorithm name based on the given algorithm identifier.
const algorithm = this.getAlgorithmName({ algorithm: params.algorithm });
// Get the key derivation function based on the algorithm name.
const kdf = this.getAlgorithm({ algorithm });
// Derive the byte array.
const derivedKeyBytes = yield kdf.deriveKeyBytes(params);
return derivedKeyBytes;
});
}
/**
* Generates a hash digest of the provided data.
*
* @remarks
* A digest is the output of the hash function. It's a fixed-size string of bytes that uniquely
* represents the data input into the hash function. The digest is often used for data integrity
* checks, as any alteration in the input data results in a significantly different digest.
*
* It takes the algorithm identifier of the hash function and data to digest as input and returns
* the digest of the data.
*
* @example
* ```ts
* const cryptoApi = new AgentCryptoApi();
* const data = new Uint8Array([...]);
* const digest = await cryptoApi.digest({ algorithm: 'SHA-256', data });
* ```
*
* @param params - The parameters for the digest operation.
* @param params.algorithm - The name of hash function to use.
* @param params.data - The data to digest.
*
* @returns A Promise which will be fulfilled with the hash digest.
*/
digest({ algorithm, data }) {
return __awaiter(this, void 0, void 0, function* () {
// Get the hash function implementation based on the specified `algorithm` parameter.
const hasher = this.getAlgorithm({ algorithm });
// Compute the hash.
const hash = yield hasher.digest({ algorithm, data });
return hash;
});
}
encrypt(params) {
return __awaiter(this, void 0, void 0, function* () {
// If th
// Determine the algorithm name based on the JWK's `alg` property.
const algorithm = this.getAlgorithmName({ key: params.key });
// Get the cipher algorithm based on the algorithm name.
const cipher = this.getAlgorithm({ algorithm });
// Encrypt the data and return the ciphertext.
return yield cipher.encrypt(params);
});
}
generateKey(params) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
// Determine the algorithm name based on the given algorithm identifier.
const algorithm = this.getAlgorithmName({ algorithm: params.algorithm });
// Get the key generator implementation based on the algorithm.
const keyGenerator = this.getAlgorithm({ algorithm });
// Generate the key.
const privateKey = yield keyGenerator.generateKey({ algorithm: params.algorithm });
// If the key ID is undefined, set it to the JWK thumbprint.
(_a = privateKey.kid) !== null && _a !== void 0 ? _a : (privateKey.kid = yield computeJwkThumbprint({ jwk: privateKey }));
return privateKey;
});
}
// ! TODO: Remove this once the `Dsa` interface is updated in @web5/crypto to remove KMS-specific methods.
getKeyUri(_params) {
return __awaiter(this, void 0, void 0, function* () {
throw new Error('Method not implemented.');
});
}
getPublicKey({ key }) {
return __awaiter(this, void 0, void 0, function* () {
// Determine the algorithm name based on the JWK's `alg` and `crv` properties.
const algorithm = this.getAlgorithmName({ key });
// Get the key generator based on the algorithm name.
const keyGenerator = this.getAlgorithm({ algorithm });
// Get the public key properties from the private JWK.
const publicKey = yield keyGenerator.getPublicKey({ key });
return publicKey;
});
}
privateKeyToBytes({ privateKey }) {
return __awaiter(this, void 0, void 0, function* () {
// Determine the algorithm name based on the JWK's `alg` property.
const algorithm = this.getAlgorithmName({ key: privateKey });
// Get the key converter based on the algorithm name.
const keyConverter = this.getAlgorithm({ algorithm });
// Convert the JWK to a byte array.
const privateKeyBytes = yield keyConverter.privateKeyToBytes({ privateKey });
return privateKeyBytes;
});
}
publicKeyToBytes({ publicKey }) {
return __awaiter(this, void 0, void 0, function* () {
// Determine the algorithm name based on the JWK's `alg` property.
const algorithm = this.getAlgorithmName({ key: publicKey });
// Get the key converter based on the algorithm name.
const keyConverter = this.getAlgorithm({ algorithm });
// Convert the JWK to a byte array.
const publicKeyBytes = yield keyConverter.publicKeyToBytes({ publicKey });
return publicKeyBytes;
});
}
sign({ key, data }) {
return __awaiter(this, void 0, void 0, function* () {
// Determine the algorithm name based on the JWK's `alg` and `crv` properties.
const algorithm = this.getAlgorithmName({ key });
// Get the signature algorithm based on the algorithm name.
const signer = this.getAlgorithm({ algorithm });
// Sign the data.
const signature = signer.sign({ data, key });
return signature;
});
}
unwrapKey(params) {
return __awaiter(this, void 0, void 0, function* () {
// Determine the algorithm name based on the JWK's `alg` property.
const algorithm = this.getAlgorithmName({ key: params.decryptionKey });
// Get the key wrapping algorithm based on the algorithm name.
const keyWrapper = this.getAlgorithm({ algorithm });
// decrypt the key and return the ciphertext.
return yield keyWrapper.unwrapKey(params);
});
}
verify({ key, signature, data }) {
return __awaiter(this, void 0, void 0, function* () {
// Determine the algorithm name based on the JWK's `alg` and `crv` properties.
const algorithm = this.getAlgorithmName({ key });
// Get the signature algorithm based on the algorithm name.
const signer = this.getAlgorithm({ algorithm });
// Verify the signature.
const isSignatureValid = signer.verify({ key, signature, data });
return isSignatureValid;
});
}
wrapKey(params) {
return __awaiter(this, void 0, void 0, function* () {
// Determine the algorithm name based on the JWK's `alg` property.
const algorithm = this.getAlgorithmName({ key: params.encryptionKey });
// Get the key wrapping algorithm based on the algorithm name.
const keyWrapper = this.getAlgorithm({ algorithm });
// Encrypt the key and return the ciphertext.
return yield keyWrapper.wrapKey(params);
});
}
/**
* Retrieves an algorithm implementation instance based on the provided algorithm name.
*
* @remarks
* This method checks if the requested algorithm is supported and returns a cached instance
* if available. If an instance does not exist, it creates and caches a new one. This approach
* optimizes performance by reusing algorithm instances across cryptographic operations.
*
* @example
* ```ts
* const signer = this.getAlgorithm({ algorithm: 'Ed25519' });
* ```
*
* @param params - The parameters for retrieving the algorithm implementation.
* @param params.algorithm - The name of the algorithm to retrieve.
*
* @returns An instance of the requested algorithm implementation.
*
* @throws Error if the requested algorithm is not supported.
*/
getAlgorithm({ algorithm }) {
var _a;
// Check if algorithm is supported.
const AlgorithmImplementation = (_a = supportedAlgorithms[algorithm]) === null || _a === void 0 ? void 0 : _a['implementation'];
if (!AlgorithmImplementation) {
throw new CryptoError(CryptoErrorCode.AlgorithmNotSupported, `Algorithm not supported: ${algorithm}`);
}
// Check if instance already exists for the `AlgorithmImplementation`.
if (!this._algorithmInstances.has(AlgorithmImplementation)) {
// If not, create a new instance and store it in the cache
this._algorithmInstances.set(AlgorithmImplementation, new AlgorithmImplementation());
}
// Return the cached instance
return this._algorithmInstances.get(AlgorithmImplementation);
}
getAlgorithmName({ algorithm, key }) {
var _a;
const algProperty = (_a = key === null || key === void 0 ? void 0 : key.alg) !== null && _a !== void 0 ? _a : algorithm;
const crvProperty = key === null || key === void 0 ? void 0 : key.crv;
for (const algorithmIdentifier of Object.keys(supportedAlgorithms)) {
const algorithmNames = supportedAlgorithms[algorithmIdentifier].names;
if (algProperty && algorithmNames.includes(algProperty)) {
return algorithmIdentifier;
}
else if (crvProperty && algorithmNames.includes(crvProperty)) {
return algorithmIdentifier;
}
}
throw new CryptoError(CryptoErrorCode.AlgorithmNotSupported, `Algorithm not supported based on provided input: alg=${algProperty}, crv=${crvProperty}. ` +
'Please check the documentation for the list of supported algorithms.');
}
}
//# sourceMappingURL=crypto-api.js.map
File diff suppressed because one or more lines are too long
+193
View File
@@ -0,0 +1,193 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { BearerDid, Did, UniversalResolver } from '@web5/dids';
import { InMemoryDidStore } from './store-did.js';
import { DidResolverCacheMemory } from './prototyping/dids/resolver-cache-memory.js';
export var DidInterface;
(function (DidInterface) {
DidInterface["Create"] = "Create";
// Deactivate = 'Deactivate',
DidInterface["Resolve"] = "Resolve";
// Update = 'Update'
})(DidInterface || (DidInterface = {}));
export function isDidRequest(didRequest, messageType) {
return didRequest.messageType === messageType;
}
export class AgentDidApi extends UniversalResolver {
constructor({ agent, didMethods, resolverCache, store }) {
if (!didMethods) {
throw new TypeError(`AgentDidApi: Required parameter missing: 'didMethods'`);
}
// Initialize the DID resolver with the given DID methods and resolver cache, or use a default
// in-memory cache if none is provided.
super({
didResolvers: didMethods,
cache: resolverCache !== null && resolverCache !== void 0 ? resolverCache : new DidResolverCacheMemory()
});
this._didMethods = new Map();
this._agent = agent;
// If `store` is not given, use an in-memory store by default.
this._store = store !== null && store !== void 0 ? store : new InMemoryDidStore();
for (const didMethod of didMethods) {
this._didMethods.set(didMethod.methodName, didMethod);
}
}
/**
* Retrieves the `Web5PlatformAgent` execution context.
*
* @returns The `Web5PlatformAgent` instance that represents the current execution context.
* @throws Will throw an error if the `agent` instance property is undefined.
*/
get agent() {
if (this._agent === undefined) {
throw new Error('AgentDidApi: Unable to determine agent execution context.');
}
return this._agent;
}
set agent(agent) {
this._agent = agent;
}
create({ method, tenant, options, store }) {
return __awaiter(this, void 0, void 0, function* () {
// Get the DID method implementation, which also verifies the method is supported.
const didMethod = this.getMethod(method);
// Create the DID and store the generated keys in the Agent's key manager.
const bearerDid = yield didMethod.create({ keyManager: this.agent.keyManager, options });
// Persist the DID to the store, by default, unless the `store` option is set to false.
if (store !== null && store !== void 0 ? store : true) {
// Data stored in the Agent's DID store must be in PortableDid format.
const { uri, document, metadata } = bearerDid;
const portableDid = { uri, document, metadata };
// Unless an existing `tenant` is specified, a record that includes the DID's URI, document,
// and metadata will be stored under a new tenant controlled by the newly created DID.
yield this._store.set({
id: portableDid.uri,
data: portableDid,
agent: this.agent,
tenant: tenant !== null && tenant !== void 0 ? tenant : portableDid.uri,
preventDuplicates: false,
useCache: true
});
}
return bearerDid;
});
}
export({ didUri, tenant }) {
return __awaiter(this, void 0, void 0, function* () {
// Attempt to retrieve the DID from the agent's DID store.
const bearerDid = yield this.get({ didUri, tenant });
if (!bearerDid) {
throw new Error(`AgentDidApi: Failed to export due to DID not found: ${didUri}`);
}
// If the DID was found, return the DID in a portable format, and if supported by the Agent's
// key manager, the private key material.
const portableDid = yield bearerDid.export();
return portableDid;
});
}
get({ didUri, tenant }) {
return __awaiter(this, void 0, void 0, function* () {
const portableDid = yield this._store.get({ id: didUri, agent: this.agent, tenant, useCache: true });
if (!portableDid)
return undefined;
const bearerDid = yield BearerDid.import({ portableDid, keyManager: this.agent.keyManager });
return bearerDid;
});
}
getSigningMethod({ didUri, methodId }) {
return __awaiter(this, void 0, void 0, function* () {
// Verify the DID method is supported.
const parsedDid = Did.parse(didUri);
if (!parsedDid) {
throw new Error(`Invalid DID URI: ${didUri}`);
}
// Get the DID method implementation, which also verifies the method is supported.
const didMethod = this.getMethod(parsedDid.method);
// Resolve the DID document.
const { didDocument, didResolutionMetadata } = yield this.resolve(didUri);
if (!didDocument) {
throw new Error(`DID resolution failed for '${didUri}': ${JSON.stringify(didResolutionMetadata)}`);
}
// Retrieve the method-specific verification method to be used for signing operations.
const verificationMethod = yield didMethod.getSigningMethod({ didDocument, methodId });
return verificationMethod;
});
}
import({ portableDid, tenant }) {
return __awaiter(this, void 0, void 0, function* () {
// If private keys are present in the PortableDid, import the key material into the Agent's key
// manager. Validate that the key material for every verification method in the DID document is
// present in the key manager.
const bearerDid = yield BearerDid.import({ keyManager: this.agent.keyManager, portableDid });
// Only the DID URI, document, and metadata are stored in the Agent's DID store.
const { uri, document, metadata } = bearerDid;
const portableDidWithoutKeys = { uri, document, metadata };
// Store the DID in the agent's DID store.
// Unless an existing `tenant` is specified, a record that includes the DID's URI, document,
// and metadata will be stored under a new tenant controlled by the imported DID.
yield this._store.set({
id: portableDidWithoutKeys.uri,
data: portableDidWithoutKeys,
agent: this.agent,
tenant: tenant !== null && tenant !== void 0 ? tenant : portableDidWithoutKeys.uri,
preventDuplicates: true,
useCache: true
});
return bearerDid;
});
}
processRequest(request) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
// Process Create DID request.
if (isDidRequest(request, DidInterface.Create)) {
try {
const bearerDid = yield this.create(Object.assign({}, request.messageParams));
const response = {
result: {
uri: bearerDid.uri,
document: bearerDid.document,
metadata: bearerDid.metadata,
},
ok: true,
status: { code: 201, message: 'Created' }
};
return response;
}
catch (error) {
return {
ok: false,
status: { code: 500, message: (_a = error.message) !== null && _a !== void 0 ? _a : 'Unknown error occurred' }
};
}
}
// Process Resolve DID request.
if (isDidRequest(request, DidInterface.Resolve)) {
const { didUri, options } = request.messageParams;
const resolutionResult = yield this.resolve(didUri, options);
const response = {
result: resolutionResult,
ok: true,
status: { code: 200, message: 'OK' }
};
return response;
}
throw new Error(`AgentDidApi: Unsupported request type: ${request.messageType}`);
});
}
getMethod(methodName) {
const didMethodApi = this._didMethods.get(methodName);
if (didMethodApi === undefined) {
throw new Error(`DID Method not supported: ${methodName}`);
}
return didMethodApi;
}
}
//# sourceMappingURL=did-api.js.map
File diff suppressed because one or more lines are too long
+337
View File
@@ -0,0 +1,337 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { Convert, NodeStream } from '@web5/common';
import { utils as cryptoUtils } from '@web5/crypto';
import { DidDht, DidJwk, DidResolverCacheLevel, UniversalResolver } from '@web5/dids';
import { Cid, DataStoreLevel, Dwn, DwnMethodName, EventLogLevel, Message, MessageStoreLevel } from '@tbd54566975/dwn-sdk-js';
import { DwnInterface, dwnMessageConstructors } from './types/dwn.js';
import { blobToIsomorphicNodeReadable, getDwnServiceEndpointUrls, isRecordsWrite, webReadableToIsomorphicNodeReadable } from './utils.js';
export function isDwnRequest(dwnRequest, messageType) {
return dwnRequest.messageType === messageType;
}
export function isDwnMessage(messageType, message) {
const incomingMessageInterfaceName = message.descriptor.interface + message.descriptor.method;
return incomingMessageInterfaceName === messageType;
}
export class AgentDwnApi {
constructor({ agent, dwn }) {
// If an agent is provided, set it as the execution context for this API.
this._agent = agent;
// Set the DWN instance for this API.
this._dwn = dwn;
}
/**
* Retrieves the `Web5PlatformAgent` execution context.
*
* @returns The `Web5PlatformAgent` instance that represents the current execution context.
* @throws Will throw an error if the `agent` instance property is undefined.
*/
get agent() {
if (this._agent === undefined) {
throw new Error('AgentDwnApi: Unable to determine agent execution context.');
}
return this._agent;
}
set agent(agent) {
this._agent = agent;
}
/**
* Public getter for the DWN instance used by this API.
*
* Notes:
* - This getter is public to allow advanced developers to access the DWN instance directly.
* However, it is recommended to use the `processRequest` method to interact with the DWN
* instance to ensure that the DWN message is constructed correctly.
* - The getter is named `node` to avoid confusion with the `dwn` property of the
* `Web5PlatformAgent`. In other words, so that a developer can call `agent.dwn.node` to access
* the DWN instance and not `agent.dwn.dwn`.
*/
get node() {
return this._dwn;
}
static createDwn({ dataPath, dataStore, didResolver, eventLog, eventStream, messageStore, tenantGate }) {
return __awaiter(this, void 0, void 0, function* () {
dataStore !== null && dataStore !== void 0 ? dataStore : (dataStore = new DataStoreLevel({ blockstoreLocation: `${dataPath}/DWN_DATASTORE` }));
didResolver !== null && didResolver !== void 0 ? didResolver : (didResolver = new UniversalResolver({
didResolvers: [DidDht, DidJwk],
cache: new DidResolverCacheLevel({ location: `${dataPath}/DID_RESOLVERCACHE` }),
}));
eventLog !== null && eventLog !== void 0 ? eventLog : (eventLog = new EventLogLevel({ location: `${dataPath}/DWN_EVENTLOG` }));
messageStore !== null && messageStore !== void 0 ? messageStore : (messageStore = new MessageStoreLevel(({
blockstoreLocation: `${dataPath}/DWN_MESSAGESTORE`,
indexLocation: `${dataPath}/DWN_MESSAGEINDEX`
})));
return yield Dwn.create({ dataStore, didResolver, eventLog, eventStream, messageStore, tenantGate });
});
}
processRequest(request) {
return __awaiter(this, void 0, void 0, function* () {
// Constructs a DWN message. and if there is a data payload, transforms the data to a Node
// Readable stream.
const { message, dataStream } = yield this.constructDwnMessage({ request });
// Extracts the optional subscription handler from the request to pass into `processMessage.
const { subscriptionHandler } = request;
// Conditionally processes the message with the DWN instance:
// - If `store` is not explicitly set to false, it sends the message to the DWN node for
// processing, passing along the target DID, the message, and any associated data stream.
// - If `store` is set to false, it immediately returns a simulated 'accepted' status without
// storing the message/data in the DWN node.
const reply = (request.store !== false)
? yield this._dwn.processMessage(request.target, message, { dataStream, subscriptionHandler })
: { status: { code: 202, detail: 'Accepted' } };
// Returns an object containing the reply from processing the message, the original message,
// and the content identifier (CID) of the message.
return {
reply,
message,
messageCid: yield Message.getCid(message),
};
});
}
sendRequest(request) {
return __awaiter(this, void 0, void 0, function* () {
// First, confirm the target DID can be dereferenced and extract the DWN service endpoint URLs.
const dwnEndpointUrls = yield getDwnServiceEndpointUrls(request.target, this.agent.did);
if (dwnEndpointUrls.length === 0) {
throw new Error(`AgentDwnApi: DID Service is missing or malformed: ${request.target}#dwn`);
}
let messageCid;
let message;
let data;
let subscriptionHandler;
// If `messageCid` is given, retrieve message and data, if any.
if ('messageCid' in request) {
({ message, data } = yield this.getDwnMessage({
author: request.author,
messageCid: request.messageCid,
messageType: request.messageType
}));
messageCid = request.messageCid;
}
else {
// Otherwise, construct a new message.
({ message } = yield this.constructDwnMessage({ request }));
if (request.dataStream && !(request.dataStream instanceof Blob)) {
throw new Error('AgentDwnApi: DataStream must be provided as a Blob');
}
data = request.dataStream;
subscriptionHandler = request.subscriptionHandler;
}
// Send the RPC request to the target DID's DWN service endpoint using the Agent's RPC client.
const reply = yield this.sendDwnRpcRequest({
targetDid: request.target,
dwnEndpointUrls,
message,
data,
subscriptionHandler
});
// If the message CID was not given in the `request`, compute it.
messageCid !== null && messageCid !== void 0 ? messageCid : (messageCid = yield Message.getCid(message));
// Returns an object containing the reply from processing the message, the original message,
// and the content identifier (CID) of the message.
return { reply, message, messageCid };
});
}
sendDwnRpcRequest({ targetDid, dwnEndpointUrls, message, data, subscriptionHandler }) {
return __awaiter(this, void 0, void 0, function* () {
const errorMessages = [];
if (message.descriptor.method === DwnMethodName.Subscribe && subscriptionHandler === undefined) {
throw new Error('AgentDwnApi: Subscription handler is required for subscription requests.');
}
// Try sending to author's publicly addressable DWNs until the first request succeeds.
for (let dwnUrl of dwnEndpointUrls) {
try {
if (subscriptionHandler !== undefined) {
// we get the server info to check if the server supports WebSocket for subscription requests
const serverInfo = yield this.agent.rpc.getServerInfo(dwnUrl);
if (!serverInfo.webSocketSupport) {
// If the server does not support WebSocket, add an error message and continue to the next URL.
errorMessages.push({
url: dwnUrl,
message: 'WebSocket support is not enabled on the server.'
});
continue;
}
// If the server supports WebSocket, replace the subscription URL with a socket transport.
// For `http` we use the unsecured `ws` protocol, and for `https` we use the secured `wss` protocol.
const parsedUrl = new URL(dwnUrl);
parsedUrl.protocol = parsedUrl.protocol === 'http:' ? 'ws:' : 'wss:';
dwnUrl = parsedUrl.toString();
}
const dwnReply = yield this.agent.rpc.sendDwnRequest({
dwnUrl,
targetDid,
message,
data,
subscriptionHandler
});
return dwnReply;
}
catch (error) {
errorMessages.push({
url: dwnUrl,
message: (error instanceof Error) ? error.message : 'Unknown error',
});
}
}
throw new Error(`Failed to send DWN RPC request: ${JSON.stringify(errorMessages)}`);
});
}
constructDwnMessage({ request }) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
const rawMessage = request.rawMessage;
let readableStream;
// TODO: Consider refactoring to move data transformations imposed by fetch() limitations to the HTTP transport-related methods.
if (isDwnRequest(request, DwnInterface.RecordsWrite)) {
const messageParams = request.messageParams;
if (request.dataStream && !(messageParams === null || messageParams === void 0 ? void 0 : messageParams.data)) {
const { dataStream } = request;
let isomorphicNodeReadable;
if (dataStream instanceof Blob) {
isomorphicNodeReadable = blobToIsomorphicNodeReadable(dataStream);
readableStream = blobToIsomorphicNodeReadable(dataStream);
}
else if (dataStream instanceof ReadableStream) {
const [forCid, forProcessMessage] = dataStream.tee();
isomorphicNodeReadable = webReadableToIsomorphicNodeReadable(forCid);
readableStream = webReadableToIsomorphicNodeReadable(forProcessMessage);
}
if (!rawMessage) {
// @ts-ignore
messageParams.dataCid = yield Cid.computeDagPbCidFromStream(isomorphicNodeReadable);
// @ts-ignore
(_a = messageParams.dataSize) !== null && _a !== void 0 ? _a : (messageParams.dataSize = isomorphicNodeReadable['bytesRead']);
}
}
}
// Determine the signer for the message.
const signer = yield this.getSigner(request.author);
const dwnMessageConstructor = dwnMessageConstructors[request.messageType];
const dwnMessage = rawMessage ? yield dwnMessageConstructor.parse(rawMessage) : yield dwnMessageConstructor.create(Object.assign(Object.assign({}, request.messageParams), { signer }));
if (isRecordsWrite(dwnMessage) && request.signAsOwner) {
yield dwnMessage.signAsOwner(signer);
}
return { message: dwnMessage.message, dataStream: readableStream };
});
}
getSigner(author) {
return __awaiter(this, void 0, void 0, function* () {
// If the author is the Agent's DID, use the Agent's signer.
if (author === this.agent.agentDid.uri) {
const signer = yield this.agent.agentDid.getSigner();
return {
algorithm: signer.algorithm,
keyId: signer.keyId,
sign: (data) => __awaiter(this, void 0, void 0, function* () {
return yield signer.sign({ data });
})
};
}
else {
// Otherwise, use the author's DID to determine the signing method.
try {
const signingMethod = yield this.agent.did.getSigningMethod({ didUri: author });
if (!signingMethod.publicKeyJwk) {
throw new Error(`Verification method '${signingMethod.id}' does not contain a public key in JWK format`);
}
// Compute the key URI of the verification method's public key.
const keyUri = yield this.agent.keyManager.getKeyUri({ key: signingMethod.publicKeyJwk });
// Verify that the key is present in the key manager. If not, an error is thrown.
const publicKey = yield this.agent.keyManager.getPublicKey({ keyUri });
// Bind the Agent's Key Manager to the signer.
const keyManager = this.agent.keyManager;
return {
algorithm: cryptoUtils.getJoseSignatureAlgorithmFromPublicKey(publicKey),
keyId: signingMethod.id,
sign: (data) => __awaiter(this, void 0, void 0, function* () {
return yield keyManager.sign({ data, keyUri: keyUri });
})
};
}
catch (error) {
throw new Error(`AgentDwnApi: Unable to get signer for author '${author}': ${error.message}`);
}
}
});
}
/**
* FURTHER REFACTORING NEEDED BELOW THIS LINE
*/
getDwnMessage({ author, messageCid }) {
return __awaiter(this, void 0, void 0, function* () {
const signer = yield this.getSigner(author);
// Construct a MessagesGet message to fetch the message.
const messagesGet = yield dwnMessageConstructors[DwnInterface.MessagesGet].create({
messageCids: [messageCid],
signer
});
const result = yield this._dwn.processMessage(author, messagesGet.message);
if (!(result.entries && result.entries.length === 1)) {
throw new Error('AgentDwnApi: Expected 1 message entry in the MessagesGet response but received none or more than one.');
}
const [messageEntry] = result.entries;
const message = messageEntry.message;
if (!message) {
throw new Error(`AgentDwnApi: Message not found with CID: ${messageCid}`);
}
let dwnMessageWithBlob = { message };
// isRecordsWrite(message) && (dwnMessage.data = await this.getDataForRecordsWrite({ author, message, messageEntry, messageType, signer }));
// If the message is a RecordsWrite, either data will be present,
// OR we have to fetch it using a RecordsRead.
if (isRecordsWrite(messageEntry)) {
if (messageEntry.encodedData) {
const dataBytes = Convert.base64Url(messageEntry.encodedData).toUint8Array();
// TODO: test adding the messageEntry.message.descriptor.dataFormat to the Blob constructor.
dwnMessageWithBlob.data = new Blob([dataBytes]);
}
else {
const recordsRead = yield dwnMessageConstructors[DwnInterface.RecordsRead].create({
filter: {
recordId: messageEntry.message.recordId
},
signer
});
const reply = yield this._dwn.processMessage(author, recordsRead.message);
if (reply.status.code >= 400) {
const { status: { code, detail } } = reply;
throw new Error(`AgentDwnApi: (${code}) Failed to read data associated with record ${messageEntry.message.recordId}. ${detail}}`);
}
else if (reply.record) {
const dataBytes = yield NodeStream.consumeToBytes({ readable: reply.record.data });
dwnMessageWithBlob.data = new Blob([dataBytes]);
}
}
}
return dwnMessageWithBlob;
});
}
/**
* TODO: Refactor this to consolidate logic in AgentDwnApi and SyncEngineLevel.
* ADDED TO GET SYNC WORKING
* - createMessage()
* - processMessage()
*/
createMessage({ author, messageParams, messageType }) {
return __awaiter(this, void 0, void 0, function* () {
// Determine the signer for the message.
const signer = yield this.getSigner(author);
const dwnMessageConstructor = dwnMessageConstructors[messageType];
const dwnMessage = yield dwnMessageConstructor.create(Object.assign(Object.assign({}, messageParams), { signer }));
return dwnMessage;
});
}
processMessage({ dataStream, message, targetDid }) {
return __awaiter(this, void 0, void 0, function* () {
return yield this._dwn.processMessage(targetDid, message, { dataStream });
});
}
}
//# sourceMappingURL=dwn-api.js.map
File diff suppressed because one or more lines are too long
+726
View File
@@ -0,0 +1,726 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { HDKey } from 'ed25519-keygen/hdkey';
import { BearerDid, DidDht } from '@web5/dids';
import { Convert, MemoryStore } from '@web5/common';
import { wordlist } from '@scure/bip39/wordlists/english';
import { generateMnemonic, mnemonicToSeed, validateMnemonic } from '@scure/bip39';
import { AgentCryptoApi } from './crypto-api.js';
import { LocalKeyManager } from './local-key-manager.js';
import { isPortableDid } from './prototyping/dids/utils.js';
import { DeterministicKeyGenerator } from './utils-internal.js';
import { CompactJwe } from './prototyping/crypto/jose/jwe-compact.js';
/**
* Type guard function to check if a given object is an empty string or a string containing only
* whitespace.
*
* This is an internal utility function used to validate password inputs, ensuring they are not
* empty or filled with only whitespace characters, which are considered invalid for password
* purposes.
*
* @param obj - The object to be checked, typically expected to be a password string.
* @returns A boolean value indicating whether the object is an empty string or a string with only
* whitespace.
*/
function isEmptyString(obj) {
return typeof obj !== 'string' || obj.trim().length === 0;
}
/**
* Type guard function to check if a given object conforms to the {@link IdentityVaultBackup}
* interface.
*
* This function is an internal utility meant to ensure the integrity and structure of the data
* assumed to be an {@link IdentityVaultBackup}. It verifies the presence and types of the
* `dateCreated`, `size`, and `data` properties, aligning with the expected structure of a backup
* object in the context of an {@link IdentityVault}.
*
* @param obj - The object to be verified against the {@link IdentityVaultBackup} interface.
* @returns A boolean value indicating whether the object is a valid {@link IdentityVaultBackup}.
*/
function isIdentityVaultBackup(obj) {
return typeof obj === 'object' && obj !== null
&& 'dateCreated' in obj && typeof obj.dateCreated === 'string'
&& 'size' in obj && typeof obj.size === 'number'
&& 'data' in obj && typeof obj.data === 'string';
}
/**
* Internal-only type guard function that checks if a given object conforms to the
* {@link IdentityVaultStatus} interface.
*
* This function is utilized within the {@link HdIdentityVault} implementation to ensure the
* integrity of the object representing the vault's status, verifying the presence and types of
* required properties. It aasserts the presence and correct types of `initialized`, `lastBackup`,
* and `lastRestore` properties, ensuring they align with the expected structure of an identity
* vault's status.
*
* @param obj - The object to be checked against the {{@link IdentityVaultStatus} interface.
* @returns A boolean indicating whether the object is an instance of {@link IdentityVaultStatus}.
*/
function isIdentityVaultStatus(obj) {
return typeof obj === 'object' && obj !== null
&& 'initialized' in obj && typeof obj.initialized === 'boolean'
&& 'lastBackup' in obj
&& 'lastRestore' in obj;
}
/**
* The `HdIdentityVault` class provides secure storage and management of identity data.
*
* The `HdIdentityVault` class implements the `IdentityVault` interface, providing secure storage
* and management of identity data with an added layer of security using Hierarchical Deterministic
* (HD) key derivation based on the SLIP-0010 standard for Ed25519 keys. It enhances identity
* protection by generating and securing the identity using a derived HD key, allowing for the
* deterministic regeneration of keys from a recovery phrase.
*
* The vault is capable of:
* - Secure initialization with a password and an optional recovery phrase, employing HD key
* derivation.
* - Encrypting the identity data using a derived content encryption key (CEK) which is securely
* encrypted and stored, accessible only by the correct password.
* - Securely backing up and restoring the vaults contents, including the HD-derived keys and
* associated DID.
* - Locking and unlocking the vault, which encrypts and decrypts the CEK for secure access to the
* vault's contents.
* - Managing the DID associated with the identity, providing a secure identity layer for
* applications.
*
* Usage involves initializing the vault with a secure password (and optionally a recovery phrase),
* which then allows for the secure storage, backup, and retrieval of the identity data.
*
* Note: Ensure the password is strong and securely managed, as it is crucial for the security of the
* vault's encrypted contents.
*
* @example
* ```typescript
* const vault = new HdIdentityVault();
* await vault.initialize({ password: 'secure-unique-phrase', recoveryPhrase: 'twelve words ...' });
* const backup = await vault.backup();
* await vault.restore({ backup, password: 'secure-unique-phrase' });
* ```
*/
export class HdIdentityVault {
/**
* Constructs an instance of `HdIdentityVault`, initializing the key derivation factor and data
* store. It sets the default key derivation work factor and initializes the internal data store,
* either with the provided store or a default in-memory store. It also establishes the initial
* status of the vault as uninitialized and locked.
*
* @param params - Optional parameters when constructing a vault instance.
* @param params.keyDerivationWorkFactor - Optionally set the computational effort for key derivation.
* @param params.store - Optionally specify a custom key-value store for vault data.
*/
constructor({ keyDerivationWorkFactor, store } = {}) {
/** Provides cryptographic functions needed for secure storage and management of the vault. */
this.crypto = new AgentCryptoApi();
this._keyDerivationWorkFactor = keyDerivationWorkFactor !== null && keyDerivationWorkFactor !== void 0 ? keyDerivationWorkFactor : 210000;
this._store = store !== null && store !== void 0 ? store : new MemoryStore();
}
/**
* Creates a backup of the vault's current state, including the encrypted DID and content
* encryption key, and returns it as an `IdentityVaultBackup` object. The backup includes a
* Base64Url-encoded string representing the vault's encrypted data, encapsulating the
* {@link PortableDid}, the content encryption key, and the vault's status.
*
* This method ensures that the vault is initialized and unlocked before proceeding with the
* backup operation.
*
* @throws Error if the vault is not initialized or is locked, preventing the backup.
* @returns A promise that resolves to the `IdentityVaultBackup` object containing the vault's
* encrypted backup data.
*/
backup() {
return __awaiter(this, void 0, void 0, function* () {
// Verify the identity vault has already been initialized and unlocked.
if (this.isLocked() || (yield this.isInitialized()) === false) {
throw new Error('HdIdentityVault: Unable to proceed with the backup operation because the identity vault ' +
'has not been initialized and unlocked. Please ensure the vault is properly initialized ' +
'with a secure password before attempting to backup its contents.');
}
// Encode the encrypted CEK and DID as a single Base64Url string.
const backupData = {
did: yield this.getStoredDid(),
contentEncryptionKey: yield this.getStoredContentEncryptionKey(),
status: yield this.getStatus()
};
const backupDataString = Convert.object(backupData).toBase64Url();
// Create a backup object containing the encrypted vault contents.
const backup = {
data: backupDataString,
dateCreated: new Date().toISOString(),
size: backupDataString.length
};
// Update the last backup timestamp in the data store.
yield this.setStatus({ lastBackup: backup.dateCreated });
return backup;
});
}
/**
* Changes the password used to secure the vault.
*
* This method decrypts the existing content encryption key (CEK) with the old password, then
* re-encrypts it with the new password, updating the vault's stored encrypted CEK. It ensures
* that the vault is initialized and unlocks the vault if the password is successfully changed.
*
* @param params - Parameters required for changing the vault password.
* @param params.oldPassword - The current password used to unlock the vault.
* @param params.newPassword - The new password to replace the existing one.
* @throws Error if the vault is not initialized or the old password is incorrect.
* @returns A promise that resolves when the password change is complete.
*/
changePassword({ oldPassword, newPassword }) {
return __awaiter(this, void 0, void 0, function* () {
// Verify the identity vault has already been initialized.
if ((yield this.isInitialized()) === false) {
throw new Error('HdIdentityVault: Unable to proceed with the change password operation because the ' +
'identity vault has not been initialized. Please ensure the vault is properly ' +
'initialized with a secure password before trying again.');
}
// Lock the vault.
yield this.lock();
// Retrieve the content encryption key (CEK) record as a compact JWE from the data store.
const cekJwe = yield this.getStoredContentEncryptionKey();
// Decrypt the compact JWE using the given `oldPassword` to verify it is correct.
let protectedHeader;
let contentEncryptionKey;
try {
let contentEncryptionKeyBytes;
({ plaintext: contentEncryptionKeyBytes, protectedHeader } = yield CompactJwe.decrypt({
jwe: cekJwe,
key: Convert.string(oldPassword).toUint8Array(),
crypto: this.crypto,
keyManager: new LocalKeyManager()
}));
contentEncryptionKey = Convert.uint8Array(contentEncryptionKeyBytes).toObject();
}
catch (error) {
throw new Error(`HdIdentityVault: Unable to change the vault password due to an incorrectly entered old password.`);
}
// Re-encrypt the vault content encryption key (CEK) using the new password.
const newCekJwe = yield CompactJwe.encrypt({
key: Convert.string(newPassword).toUint8Array(),
protectedHeader,
plaintext: Convert.object(contentEncryptionKey).toUint8Array(),
crypto: this.crypto,
keyManager: new LocalKeyManager()
});
// Update the vault with the new CEK JWE.
yield this._store.set('contentEncryptionKey', newCekJwe);
// Update the vault CEK in memory, effectively unlocking the vault.
this._contentEncryptionKey = contentEncryptionKey;
});
}
/**
* Retrieves the DID (Decentralized Identifier) associated with the vault.
*
* This method ensures the vault is initialized and unlocked before decrypting and returning the
* DID. The DID is stored encrypted and is decrypted using the vault's content encryption key.
*
* @throws Error if the vault is not initialized, is locked, or the DID cannot be decrypted.
* @returns A promise that resolves with a {@link BearerDid}.
*/
getDid() {
return __awaiter(this, void 0, void 0, function* () {
// Verify the identity vault is unlocked.
if (this.isLocked()) {
throw new Error(`HdIdentityVault: Vault has not been initialized and unlocked.`);
}
// Retrieve the encrypted DID record as compact JWE from the vault store.
const didJwe = yield this.getStoredDid();
// Decrypt the compact JWE to obtain the PortableDid as a byte array.
const { plaintext: portableDidBytes } = yield CompactJwe.decrypt({
jwe: didJwe,
key: this._contentEncryptionKey,
crypto: this.crypto,
keyManager: new LocalKeyManager()
});
// Convert the DID from a byte array to PortableDid format.
const portableDid = Convert.uint8Array(portableDidBytes).toObject();
if (!isPortableDid(portableDid)) {
throw new Error('HdIdentityVault: Unable to decode malformed DID in identity vault');
}
// Return the DID in Bearer DID format.
return yield BearerDid.import({ portableDid });
});
}
/**
* Fetches the current status of the `HdIdentityVault`, providing details on whether it's
* initialized and the timestamps of the last backup and restore operations.
*
* @returns A promise that resolves with the current status of the `HdIdentityVault`, detailing
* its initialization, lock state, and the timestamps of the last backup and restore.
*/
getStatus() {
return __awaiter(this, void 0, void 0, function* () {
const storedStatus = yield this._store.get('vaultStatus');
// On the first run, the store will not contain an IdentityVaultStatus object yet, so return an
// uninitialized status.
if (!storedStatus) {
return {
initialized: false,
lastBackup: null,
lastRestore: null
};
}
const vaultStatus = Convert.string(storedStatus).toObject();
if (!isIdentityVaultStatus(vaultStatus)) {
throw new Error('HdIdentityVault: Invalid IdentityVaultStatus object in store');
}
return vaultStatus;
});
}
/**
* Initializes the `HdIdentityVault` with a password and an optional recovery phrase.
*
* If a recovery phrase is not provided, a new one is generated. This process sets up the vault,
* deriving the necessary cryptographic keys and preparing the vault for use. It ensures the vault
* is ready to securely store and manage identity data.
*
* @example
* ```ts
* const identityVault = new HdIdentityVault();
* const recoveryPhrase = await identityVault.initialize({
* password: 'your-secure-phrase'
* });
* console.log('Vault initialized. Recovery phrase:', recoveryPhrase);
* ```
*
* @param params - The initialization parameters.
* @param params.password - The password used to secure the vault.
* @param params.recoveryPhrase - An optional 12-word recovery phrase for key derivation. If
* omitted, a new recovery is generated.
* @returns A promise that resolves with the recovery phrase used during the initialization, which
* should be securely stored by the user.
*/
initialize({ password, recoveryPhrase }) {
return __awaiter(this, void 0, void 0, function* () {
/**
* STEP 0: Validate the input parameters and verify the identity vault is not already
* initialized.
*/
// Verify that the identity vault was not previously initialized.
if (yield this.isInitialized()) {
throw new Error(`HdIdentityVault: Vault has already been initialized.`);
}
// Verify that the password is not empty.
if (isEmptyString(password)) {
throw new Error(`HdIdentityVault: The password is required and cannot be blank. Please provide a ' +
'valid, non-empty password.`);
}
// If provided, verify that the recovery phrase is not empty.
if (recoveryPhrase && isEmptyString(recoveryPhrase)) {
throw new Error(`HdIdentityVault: The password is required and cannot be blank. Please provide a ' +
'valid, non-empty password.`);
}
/**
* STEP 1: Derive a Hierarchical Deterministic (HD) key pair from the given (or generated)
* recoveryPhrase.
*/
// Generate a 12-word (128-bit) mnemonic, if one was not provided.
recoveryPhrase !== null && recoveryPhrase !== void 0 ? recoveryPhrase : (recoveryPhrase = generateMnemonic(wordlist, 128));
// Validate the mnemonic for being 12-24 words contained in `wordlist`.
if (!validateMnemonic(recoveryPhrase, wordlist)) {
throw new Error('HdIdentityVault: The provided recovery phrase is invalid. Please ensure that the ' +
'recovery phrase is a correctly formatted series of 12 words.');
}
// Derive a root seed from the mnemonic.
const rootSeed = yield mnemonicToSeed(recoveryPhrase);
// Derive a root key for the DID from the root seed.
const rootHdKey = HDKey.fromMasterSeed(rootSeed);
/**
* STEP 2: Derive the vault HD key pair from the root key.
*/
// The vault HD key is derived using account 0 and index 0 so that it can be
// deterministically re-derived. The vault key pair serves as input keying material for:
// - deriving the vault content encryption key (CEK)
// - deriving the salt that serves as input to derive the key that encrypts the vault CEK
const vaultHdKey = rootHdKey.derive(`m/44'/0'/0'/0'/0'`);
/**
* STEP 3: Derive the vault Content Encryption Key (CEK) from the vault private
* key and a non-secret static info value.
*/
// A non-secret static info value is combined with the vault private key as input to HKDF
// (Hash-based Key Derivation Function) to derive a 32-byte content encryption key (CEK).
const contentEncryptionKey = yield this.crypto.deriveKey({
algorithm: 'HKDF-512',
baseKeyBytes: vaultHdKey.privateKey,
salt: '',
info: 'vault_cek',
derivedKeyAlgorithm: 'A256GCM' // derived key algorithm
});
/**
* STEP 4: Using the given `password` and a `salt` derived from the vault public key, encrypt
* the vault CEK and store it in the data store as a compact JWE.
*/
// A non-secret static info value is combined with the vault public key as input to HKDF
// (Hash-based Key Derivation Function) to derive a new 32-byte salt.
const saltInput = yield this.crypto.deriveKeyBytes({
algorithm: 'HKDF-512',
baseKeyBytes: vaultHdKey.publicKey,
salt: '',
info: 'vault_unlock_salt',
length: 256, // derived key length, in bits
});
// Construct the JWE header.
const cekJweProtectedHeader = {
alg: 'PBES2-HS512+A256KW',
enc: 'A256GCM',
cty: 'text/plain',
p2c: this._keyDerivationWorkFactor,
p2s: Convert.uint8Array(saltInput).toBase64Url()
};
// Encrypt the vault content encryption key (CEK) to compact JWE format.
const cekJwe = yield CompactJwe.encrypt({
key: Convert.string(password).toUint8Array(),
protectedHeader: cekJweProtectedHeader,
plaintext: Convert.object(contentEncryptionKey).toUint8Array(),
crypto: this.crypto,
keyManager: new LocalKeyManager()
});
// Store the compact JWE in the data store.
yield this._store.set('contentEncryptionKey', cekJwe);
/**
* STEP 5: Create a DID using identity, signing, and encryption keys derived from the root key.
*/
// Derive the identity key pair using index 0 and convert to JWK format.
// Note: The account is set to Unix epoch time so that in the future, the keys for a DID DHT
// document can be deterministically derived based on the versionId returned in a DID
// resolution result.
const identityHdKey = rootHdKey.derive(`m/44'/0'/1708523827'/0'/0'`);
const identityPrivateKey = yield this.crypto.bytesToPrivateKey({
algorithm: 'Ed25519',
privateKeyBytes: identityHdKey.privateKey
});
// Derive the signing key using index 1 and convert to JWK format.
let signingHdKey = rootHdKey.derive(`m/44'/0'/1708523827'/0'/1'`);
const signingPrivateKey = yield this.crypto.bytesToPrivateKey({
algorithm: 'Ed25519',
privateKeyBytes: signingHdKey.privateKey
});
// TODO: Enable this once DID DHT supports X25519 keys.
// Derive the encryption key using index 1 and convert to JWK format.
// const encryptionHdKey = rootHdKey.derive(`m/44'/0'/1708523827'/0'/1'`);
// const encryptionKeyEd25519 = await this.crypto.bytesToPrivateKey({
// algorithm : 'Ed25519',
// privateKeyBytes : encryptionHdKey.privateKey
// });
// const encryptionPrivateKey = await Ed25519.convertPrivateKeyToX25519({ privateKey: encryptionKeyEd25519 });
// Add the identity and signing keys to the deterministic key generator so that when the DID is
// created it will use the derived keys.
const deterministicKeyGenerator = new DeterministicKeyGenerator();
yield deterministicKeyGenerator.addPredefinedKeys({
privateKeys: [identityPrivateKey, signingPrivateKey]
});
// Create the DID using the derived identity, signing, and encryption keys.
const did = yield DidDht.create({
keyManager: deterministicKeyGenerator,
options: {
verificationMethods: [
{
algorithm: 'Ed25519',
id: 'sig',
purposes: ['assertionMethod', 'authentication']
},
// TODO: Enable this once DID DHT supports X25519 keys.
// {
// algorithm : 'X25519',
// id : 'enc',
// purposes : ['keyAgreement']
// }
]
}
});
/**
* STEP 6: Convert the DID to portable format and store it in the data store as a
* compact JWE.
*/
// Convert the DID to a portable format.
const portableDid = yield did.export();
// Construct the JWE header.
const didJweProtectedHeader = {
alg: 'dir',
enc: 'A256GCM',
cty: 'json'
};
// Encrypt the DID to compact JWE format.
const didJwe = yield CompactJwe.encrypt({
key: contentEncryptionKey,
plaintext: Convert.object(portableDid).toUint8Array(),
protectedHeader: didJweProtectedHeader,
crypto: this.crypto,
keyManager: new LocalKeyManager()
});
// Store the compact JWE in the data store.
yield this._store.set('did', didJwe);
/**
* STEP 7: Set the vault CEK (effectively unlocking the vault), set the status to initialized,
* and return the mnemonic used to generate the vault key.
*/
this._contentEncryptionKey = contentEncryptionKey;
yield this.setStatus({ initialized: true });
// Return the recovery phrase in case it was generated so that it can be displayed to the user
// for safekeeping.
return recoveryPhrase;
});
}
/**
* Determines whether the vault has been initialized.
*
* This method checks the vault's current status to determine if it has been
* initialized. Initialization is a prerequisite for most operations on the vault,
* ensuring that it is ready for use.
*
* @example
* ```ts
* const isInitialized = await identityVault.isInitialized();
* console.log('Is the vault initialized?', isInitialized);
* ```
*
* @returns A promise that resolves to `true` if the vault has been initialized, otherwise `false`.
*/
isInitialized() {
return __awaiter(this, void 0, void 0, function* () {
return this.getStatus().then(({ initialized }) => initialized);
});
}
/**
* Checks if the vault is currently locked.
*
* This method assesses the vault's current state to determine if it is locked.
* A locked vault restricts access to its contents, requiring the correct password
* to unlock and access the stored identity data. The vault must be unlocked to
* perform operations that access or modify its contents.
*
* @example
* ```ts
* const isLocked = await identityVault.isLocked();
* console.log('Is the vault locked?', isLocked);
* ```
*
* @returns `true` if the vault is locked, otherwise `false`.
*/
isLocked() {
return !this._contentEncryptionKey;
}
/**
* Locks the `HdIdentityVault`, securing its contents by clearing the in-memory encryption key.
*
* This method ensures that the vault's sensitive data cannot be accessed without unlocking the
* vault again with the correct password. It's an essential security feature for safeguarding
* the vault's contents against unauthorized access.
*
* @example
* ```ts
* const identityVault = new HdIdentityVault();
* await identityVault.lock();
* console.log('Vault is now locked.');
* ```
* @throws An error if the identity vault has not been initialized.
* @returns A promise that resolves when the vault is successfully locked.
*/
lock() {
return __awaiter(this, void 0, void 0, function* () {
// Verify the identity vault has already been initialized.
if ((yield this.isInitialized()) === false) {
throw new Error(`HdIdentityVault: Lock operation failed. Vault has not been initialized.`);
}
// Clear the vault content encryption key (CEK), effectively locking the vault.
if (this._contentEncryptionKey)
this._contentEncryptionKey.k = '';
this._contentEncryptionKey = undefined;
});
}
/**
* Restores the vault's data from a backup object, decrypting and reinitializing the vault's
* content with the provided backup data.
*
* This operation is crucial for data recovery scenarios, allowing users to regain access to their
* encrypted data using a previously saved backup and their password.
*
* @example
* ```ts
* const identityVault = new HdIdentityVault();
* await identityVault.initialize({ password: 'your-secure-phrase' });
* // Create a backup of the vault's contents.
* const backup = await identityVault.backup();
* // Restore the vault with the same password.
* await identityVault.restore({ backup: backup, password: 'your-secure-phrase' });
* console.log('Vault restored successfully.');
* ```
*
* @param params - The parameters required for the restore operation.
* @param params.backup - The backup object containing the encrypted vault data.
* @param params.password - The password used to encrypt the backup, necessary for decryption.
* @returns A promise that resolves when the vault has been successfully restored.
* @throws An error if the backup object is invalid or if the password is incorrect.
*/
restore({ backup, password }) {
return __awaiter(this, void 0, void 0, function* () {
// Validate the backup object.
if (!isIdentityVaultBackup(backup)) {
throw new Error(`HdIdentityVault: Restore operation failed due to invalid backup object.`);
}
// Temporarily save the status and contents of the data store while attempting to restore the
// backup so that they are not lost in case the restore operation fails.
let previousStatus;
let previousContentEncryptionKey;
let previousDid;
try {
previousDid = yield this.getStoredDid();
previousContentEncryptionKey = yield this.getStoredContentEncryptionKey();
previousStatus = yield this.getStatus();
}
catch (_a) {
throw new Error('HdIdentityVault: The restore operation cannot proceed because the existing vault ' +
'contents are missing or inaccessible. If the problem persists consider re-initializing ' +
'the vault and retrying the restore.');
}
try {
// Convert the backup data to a JSON object.
const backupData = Convert.base64Url(backup.data).toObject();
// Restore the backup to the data store.
yield this._store.set('did', backupData.did);
yield this._store.set('contentEncryptionKey', backupData.contentEncryptionKey);
yield this.setStatus(backupData.status);
// Attempt to unlock the vault with the given `password`.
yield this.unlock({ password });
}
catch (error) {
// If the restore operation fails, revert the data store to the status and contents that were
// saved before the restore operation was attempted.
yield this.setStatus(previousStatus);
yield this._store.set('contentEncryptionKey', previousContentEncryptionKey);
yield this._store.set('did', previousDid);
throw new Error('HdIdentityVault: Restore operation failed due to invalid backup data or an incorrect ' +
'password. Please verify the password is correct for the provided backup and try again.');
}
// Update the last restore timestamp in the data store.
yield this.setStatus({ lastRestore: new Date().toISOString() });
});
}
/**
* Unlocks the vault by decrypting the stored content encryption key (CEK) using the provided
* password.
*
* This method is essential for accessing the vault's encrypted contents, enabling the decryption
* of stored data and the execution of further operations requiring the vault to be unlocked.
*
* @example
* ```ts
* const identityVault = new HdIdentityVault();
* await identityVault.initialize({ password: 'your-initial-phrase' });
* // Unlock the vault with the correct password before accessing its contents
* await identityVault.unlock({ password: 'your-initial-phrase' });
* console.log('Vault unlocked successfully.');
* ```
*
*
* @param params - The parameters required for the unlock operation.
* @param params.password - The password used to encrypt the vault's CEK, necessary for
* decryption.
* @returns A promise that resolves when the vault has been successfully unlocked.
* @throws An error if the vault has not been initialized or if the provided password is
* incorrect.
*/
unlock({ password }) {
return __awaiter(this, void 0, void 0, function* () {
// Lock the vault.
yield this.lock();
// Retrieve the content encryption key (CEK) record as a compact JWE from the data store.
const cekJwe = yield this.getStoredContentEncryptionKey();
// Decrypt the compact JWE.
try {
const { plaintext: contentEncryptionKeyBytes } = yield CompactJwe.decrypt({
jwe: cekJwe,
key: Convert.string(password).toUint8Array(),
crypto: this.crypto,
keyManager: new LocalKeyManager()
});
const contentEncryptionKey = Convert.uint8Array(contentEncryptionKeyBytes).toObject();
// Save the content encryption key in memory, thereby unlocking the vault.
this._contentEncryptionKey = contentEncryptionKey;
}
catch (error) {
throw new Error(`HdIdentityVault: Unable to unlock the vault due to an incorrect password.`);
}
});
}
/**
* Retrieves the Decentralized Identifier (DID) associated with the identity vault from the vault
* store.
*
* This DID is encrypted in compact JWE format and needs to be decrypted after the vault is
* unlocked. The method is intended to be used internally within the HdIdentityVault class to access
* the encrypted PortableDid.
*
* @returns A promise that resolves to the encrypted DID stored in the vault as a compact JWE.
* @throws Will throw an error if the DID cannot be retrieved from the vault.
*/
getStoredDid() {
return __awaiter(this, void 0, void 0, function* () {
// Retrieve the DID record as a compact JWE from the data store.
const didJwe = yield this._store.get('did');
if (!didJwe) {
throw new Error('HdIdentityVault: Unable to retrieve the DID record from the vault. Please check the ' +
'vault status and if the problem persists consider re-initializing the vault and ' +
'restoring the contents from a previous backup.');
}
return didJwe;
});
}
/**
* Retrieves the encrypted Content Encryption Key (CEK) from the vault's storage.
*
* This CEK is used for encrypting and decrypting the vault's contents. It is stored as a
* compact JWE and should be decrypted with the user's password to be used for further
* cryptographic operations.
*
* @returns A promise that resolves to the stored CEK as a string in compact JWE format.
* @throws Will throw an error if the CEK cannot be retrieved, indicating potential issues with
* the vault's integrity or state.
*/
getStoredContentEncryptionKey() {
return __awaiter(this, void 0, void 0, function* () {
// Retrieve the content encryption key (CEK) record as a compact JWE from the data store.
const cekJwe = yield this._store.get('contentEncryptionKey');
if (!cekJwe) {
throw new Error('HdIdentityVault: Unable to retrieve the Content Encryption Key record from the vault. ' +
'Please check the vault status and if the problem persists consider re-initializing the ' +
'vault and restoring the contents from a previous backup.');
}
return cekJwe;
});
}
/**
* Updates the status of the `HdIdentityVault`, reflecting changes in its initialization, lock
* state, and the timestamps of the last backup and restore operations.
*
* This method directly manipulates the internal state stored in the vault's key-value store.
*
* @param params - The status properties to be updated.
* @param params.initialized - Updates the initialization state of the vault.
* @param params.lastBackup - Updates the timestamp of the last successful backup.
* @param params.lastRestore - Updates the timestamp of the last successful restore.
* @returns A promise that resolves to a boolean indicating successful status update.
* @throws Will throw an error if the status cannot be updated in the key-value store.
*/
setStatus({ initialized, lastBackup, lastRestore }) {
return __awaiter(this, void 0, void 0, function* () {
// Get the current status values from the store, if any.
let vaultStatus = yield this.getStatus();
// Update the status properties with new values specified, if any.
vaultStatus.initialized = initialized !== null && initialized !== void 0 ? initialized : vaultStatus.initialized;
vaultStatus.lastBackup = lastBackup !== null && lastBackup !== void 0 ? lastBackup : vaultStatus.lastBackup;
vaultStatus.lastRestore = lastRestore !== null && lastRestore !== void 0 ? lastRestore : vaultStatus.lastRestore;
// Write the changes to the store.
yield this._store.set('vaultStatus', JSON.stringify(vaultStatus));
return true;
});
}
}
//# sourceMappingURL=hd-identity-vault.js.map
File diff suppressed because one or more lines are too long
+164
View File
@@ -0,0 +1,164 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { BearerIdentity } from './bearer-identity.js';
import { isPortableDid } from './prototyping/dids/utils.js';
import { InMemoryIdentityStore } from './store-identity.js';
export function isPortableIdentity(obj) {
// Validate that the given value is an object that has the necessary properties of PortableIdentity.
return !(!obj || typeof obj !== 'object' || obj === null)
&& 'did' in obj
&& 'metadata' in obj
&& isPortableDid(obj.did);
}
export class AgentIdentityApi {
constructor({ agent, store } = {}) {
this._agent = agent;
// If `store` is not given, use an in-memory store by default.
this._store = store !== null && store !== void 0 ? store : new InMemoryIdentityStore();
}
/**
* Retrieves the `Web5PlatformAgent` execution context.
*
* @returns The `Web5PlatformAgent` instance that represents the current execution context.
* @throws Will throw an error if the `agent` instance property is undefined.
*/
get agent() {
if (this._agent === undefined) {
throw new Error('AgentIdentityApi: Unable to determine agent execution context.');
}
return this._agent;
}
set agent(agent) {
this._agent = agent;
}
create({ metadata, didMethod = 'dht', didOptions, store, tenant }) {
return __awaiter(this, void 0, void 0, function* () {
// Unless an existing `tenant` is specified, a record that includes the DID's URI, document,
// and metadata will be stored under a new tenant controlled by the newly created DID.
const bearerDid = yield this.agent.did.create({
method: didMethod,
options: didOptions,
store,
tenant
});
// Create the BearerIdentity object.
const identity = new BearerIdentity({
did: bearerDid,
metadata: Object.assign(Object.assign({}, metadata), { uri: bearerDid.uri, tenant: tenant !== null && tenant !== void 0 ? tenant : bearerDid.uri })
});
// Persist the Identity to the store, by default, unless the `store` option is set to false.
if (store !== null && store !== void 0 ? store : true) {
yield this._store.set({
id: identity.did.uri,
data: identity.metadata,
agent: this.agent,
tenant: identity.metadata.tenant,
preventDuplicates: false,
useCache: true
});
}
return identity;
});
}
export({ didUri, tenant }) {
return __awaiter(this, void 0, void 0, function* () {
// Attempt to retrieve the Identity from the Agent's Identity store.
const bearerIdentity = yield this.get({ didUri, tenant });
if (!bearerIdentity) {
throw new Error(`AgentIdentityApi: Failed to export due to Identity not found: ${didUri}`);
}
// If the Identity was found, return the Identity in a portable format, and if supported by the
// Agent's key manager, the private key material.
const portableIdentity = yield bearerIdentity.export();
return portableIdentity;
});
}
get({ didUri, tenant }) {
return __awaiter(this, void 0, void 0, function* () {
// Attempt to retrieve the Identity from the Agent's Identity store.
const storedIdentity = yield this._store.get({ id: didUri, agent: this.agent, tenant, useCache: true });
// If the Identity is not found in the store, return undefined.
if (!storedIdentity)
return undefined;
// Retrieve the DID from the Agent's DID store using the tenant value from the stored
// Identity's metadata.
const storedDid = yield this.agent.did.get({ didUri, tenant: storedIdentity.tenant });
// If the Identity is present but the DID is not found, throw an error.
if (!storedDid) {
throw new Error(`AgentIdentityApi: Identity is present in the store but DID is missing: ${didUri}`);
}
// Create the BearerIdentity object.
const identity = new BearerIdentity({ did: storedDid, metadata: storedIdentity });
return identity;
});
}
import({ portableIdentity }) {
return __awaiter(this, void 0, void 0, function* () {
// Import the PortableDid to the Agent's DID store.
const storedDid = yield this.agent.did.import({
portableDid: portableIdentity.portableDid,
tenant: portableIdentity.metadata.tenant
});
// Verify the DID is present in the Agent's DID store.
if (!storedDid) {
throw new Error(`AgentIdentityApi: Failed to import Identity: ${portableIdentity.metadata.uri}`);
}
// Create the BearerIdentity object.
const identity = new BearerIdentity({ did: storedDid, metadata: portableIdentity.metadata });
// Store the Identity metadata in the Agent's Identity store.
yield this._store.set({
id: identity.did.uri,
data: identity.metadata,
agent: this.agent,
tenant: identity.metadata.tenant,
preventDuplicates: true,
useCache: true
});
return identity;
});
}
list({ tenant } = {}) {
return __awaiter(this, void 0, void 0, function* () {
// Retrieve the list of Identities from the Agent's Identity store.
const storedIdentities = yield this._store.list({ agent: this.agent, tenant });
const identities = [];
for (const metadata of storedIdentities) {
const identity = yield this.get({ didUri: metadata.uri, tenant: metadata.tenant });
identities.push(identity);
}
return identities;
});
}
manage({ portableIdentity }) {
return __awaiter(this, void 0, void 0, function* () {
// Retrieve the DID using the `tenant` stored in the given Identity's metadata.
const storedDid = yield this.agent.did.get({
didUri: portableIdentity.metadata.uri,
tenant: portableIdentity.metadata.tenant
});
// Verify the DID is present in the DID store.
if (!storedDid) {
throw new Error(`AgentIdentityApi: Failed to manage Identity: ${portableIdentity.metadata.uri}`);
}
// Create the BearerIdentity object.
const identity = new BearerIdentity({ did: storedDid, metadata: portableIdentity.metadata });
// Store the Identity metadata in the Agent's Identity store.
yield this._store.set({
id: identity.did.uri,
data: identity.metadata,
agent: this.agent,
preventDuplicates: true,
useCache: true
});
return identity;
});
}
}
//# sourceMappingURL=identity-api.js.map
@@ -0,0 +1 @@
{"version":3,"file":"identity-api.js","sourceRoot":"","sources":["../../src/identity-api.ts"],"names":[],"mappings":";;;;;;;;;AAQA,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5D,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAmB5D,MAAM,UAAU,kBAAkB,CAAC,GAAY;IAC7C,oGAAoG;IACpG,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,CAAC;WACpD,KAAK,IAAI,GAAG;WACZ,UAAU,IAAI,GAAG;WACjB,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAC9B,CAAC;AAED,MAAM,OAAO,gBAAgB;IAW3B,YAAY,EAAE,KAAK,EAAE,KAAK,KAAqC,EAAE;QAC/D,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;QAEpB,8DAA8D;QAC9D,IAAI,CAAC,MAAM,GAAG,KAAK,aAAL,KAAK,cAAL,KAAK,GAAI,IAAI,qBAAqB,EAAE,CAAC;IACrD,CAAC;IAED;;;;;OAKG;IACH,IAAI,KAAK;QACP,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS,EAAE;YAC7B,MAAM,IAAI,KAAK,CAAC,gEAAgE,CAAC,CAAC;SACnF;QAED,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;IAED,IAAI,KAAK,CAAC,KAAqC;QAC7C,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;IACtB,CAAC;IAEY,MAAM,CAAC,EAAE,QAAQ,EAAE,SAAS,GAAG,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EACzC;;YAEjC,4FAA4F;YAC5F,sFAAsF;YACtF,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC;gBAC5C,MAAM,EAAI,SAAS;gBACnB,OAAO,EAAG,UAAU;gBACpB,KAAK;gBACL,MAAM;aACP,CAAC,CAAC;YAEH,oCAAoC;YACpC,MAAM,QAAQ,GAAG,IAAI,cAAc,CAAC;gBAClC,GAAG,EAAQ,SAAS;gBACpB,QAAQ,kCAAQ,QAAQ,KAAE,GAAG,EAAE,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,aAAN,MAAM,cAAN,MAAM,GAAI,SAAS,CAAC,GAAG,GAAE;aAChF,CAAC,CAAC;YAEH,4FAA4F;YAC5F,IAAI,KAAK,aAAL,KAAK,cAAL,KAAK,GAAI,IAAI,EAAE;gBACjB,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC;oBACpB,EAAE,EAAkB,QAAQ,CAAC,GAAG,CAAC,GAAG;oBACpC,IAAI,EAAgB,QAAQ,CAAC,QAAQ;oBACrC,KAAK,EAAe,IAAI,CAAC,KAAK;oBAC9B,MAAM,EAAc,QAAQ,CAAC,QAAQ,CAAC,MAAM;oBAC5C,iBAAiB,EAAG,KAAK;oBACzB,QAAQ,EAAY,IAAI;iBACzB,CAAC,CAAC;aACJ;YAED,OAAO,QAAQ,CAAC;QAClB,CAAC;KAAA;IAEY,MAAM,CAAC,EAAE,MAAM,EAAE,MAAM,EAGnC;;YACC,oEAAoE;YACpE,MAAM,cAAc,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;YAE1D,IAAI,CAAC,cAAc,EAAE;gBACnB,MAAM,IAAI,KAAK,CAAC,iEAAiE,MAAM,EAAE,CAAC,CAAC;aAC5F;YAED,+FAA+F;YAC/F,iDAAiD;YACjD,MAAM,gBAAgB,GAAG,MAAM,cAAc,CAAC,MAAM,EAAE,CAAC;YAEvD,OAAO,gBAAgB,CAAC;QAC1B,CAAC;KAAA;IAEY,GAAG,CAAC,EAAE,MAAM,EAAE,MAAM,EAGhC;;YACC,oEAAoE;YACpE,MAAM,cAAc,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;YAExG,+DAA+D;YAC/D,IAAI,CAAC,cAAc;gBAAE,OAAO,SAAS,CAAC;YAEtC,qFAAqF;YACrF,uBAAuB;YACvB,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,CAAC,MAAM,EAAE,CAAC,CAAC;YAEtF,uEAAuE;YACvE,IAAI,CAAC,SAAS,EAAE;gBACd,MAAM,IAAI,KAAK,CAAC,0EAA0E,MAAM,EAAE,CAAC,CAAC;aACrG;YAED,oCAAoC;YACpC,MAAM,QAAQ,GAAG,IAAI,cAAc,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,QAAQ,EAAE,cAAc,EAAE,CAAC,CAAC;YAElF,OAAO,QAAQ,CAAC;QAClB,CAAC;KAAA;IAEY,MAAM,CAAC,EAAE,gBAAgB,EAErC;;YACC,mDAAmD;YACnD,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC;gBAC5C,WAAW,EAAG,gBAAgB,CAAC,WAAW;gBAC1C,MAAM,EAAQ,gBAAgB,CAAC,QAAQ,CAAC,MAAM;aAC/C,CAAC,CAAC;YAEH,sDAAsD;YACtD,IAAI,CAAC,SAAS,EAAE;gBACd,MAAM,IAAI,KAAK,CAAC,gDAAgD,gBAAgB,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC;aAClG;YAED,oCAAoC;YACpC,MAAM,QAAQ,GAAG,IAAI,cAAc,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,QAAQ,EAAE,gBAAgB,CAAC,QAAQ,EAAE,CAAC,CAAC;YAE7F,6DAA6D;YAC7D,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC;gBACpB,EAAE,EAAkB,QAAQ,CAAC,GAAG,CAAC,GAAG;gBACpC,IAAI,EAAgB,QAAQ,CAAC,QAAQ;gBACrC,KAAK,EAAe,IAAI,CAAC,KAAK;gBAC9B,MAAM,EAAc,QAAQ,CAAC,QAAQ,CAAC,MAAM;gBAC5C,iBAAiB,EAAG,IAAI;gBACxB,QAAQ,EAAY,IAAI;aACzB,CAAC,CAAC;YAEH,OAAO,QAAQ,CAAC;QAClB,CAAC;KAAA;IAEY,IAAI,CAAC,EAAE,MAAM,KAEtB,EAAE;;YACJ,mEAAmE;YACnE,MAAM,gBAAgB,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;YAE/E,MAAM,UAAU,GAAqB,EAAE,CAAC;YAExC,KAAK,MAAM,QAAQ,IAAI,gBAAgB,EAAE;gBACvC,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;gBACnF,UAAU,CAAC,IAAI,CAAC,QAAS,CAAC,CAAC;aAC5B;YAED,OAAO,UAAU,CAAC;QACpB,CAAC;KAAA;IAEY,MAAM,CAAC,EAAE,gBAAgB,EAErC;;YACC,+EAA+E;YAC/E,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC;gBACzC,MAAM,EAAG,gBAAgB,CAAC,QAAQ,CAAC,GAAG;gBACtC,MAAM,EAAG,gBAAgB,CAAC,QAAQ,CAAC,MAAM;aAC1C,CAAC,CAAC;YAEH,8CAA8C;YAC9C,IAAI,CAAC,SAAS,EAAE;gBACd,MAAM,IAAI,KAAK,CAAC,gDAAgD,gBAAgB,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC;aAClG;YAED,oCAAoC;YACpC,MAAM,QAAQ,GAAG,IAAI,cAAc,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,QAAQ,EAAE,gBAAgB,CAAC,QAAQ,EAAE,CAAC,CAAC;YAE7F,6DAA6D;YAC7D,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC;gBACpB,EAAE,EAAkB,QAAQ,CAAC,GAAG,CAAC,GAAG;gBACpC,IAAI,EAAgB,QAAQ,CAAC,QAAQ;gBACrC,KAAK,EAAe,IAAI,CAAC,KAAK;gBAC9B,iBAAiB,EAAG,IAAI;gBACxB,QAAQ,EAAY,IAAI;aACzB,CAAC,CAAC;YAEH,OAAO,QAAQ,CAAC;QAClB,CAAC;KAAA;CACF"}
+18
View File
@@ -0,0 +1,18 @@
export * from './types/dwn.js';
export * from './bearer-identity.js';
export * from './crypto-api.js';
export * from './did-api.js';
export * from './dwn-api.js';
export * from './hd-identity-vault.js';
export * from './identity-api.js';
export * from './local-key-manager.js';
export * from './rpc-client.js';
export * from './store-data.js';
export * from './store-did.js';
export * from './store-identity.js';
export * from './store-key.js';
export * from './sync-api.js';
export * from './sync-engine-level.js';
export * from './test-harness.js';
export * from './utils.js';
//# sourceMappingURL=index.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AACA,cAAc,gBAAgB,CAAC;AAO/B,cAAc,sBAAsB,CAAC;AACrC,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,wBAAwB,CAAC;AACvC,cAAc,mBAAmB,CAAC;AAClC,cAAc,wBAAwB,CAAC;AACvC,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,qBAAqB,CAAC;AACpC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,wBAAwB,CAAC;AACvC,cAAe,mBAAmB,CAAC;AACnC,cAAc,YAAY,CAAC"}
+488
View File
@@ -0,0 +1,488 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
import { isPrivateJwk, Sha2Algorithm, EcdsaAlgorithm, EdDsaAlgorithm, AesGcmAlgorithm, KEY_URI_PREFIX_JWK, computeJwkThumbprint, } from '@web5/crypto';
import { InMemoryKeyStore } from './store-key.js';
import { AesKwAlgorithm } from './prototyping/crypto/algorithms/aes-kw.js';
import { CryptoError, CryptoErrorCode } from './prototyping/crypto/crypto-error.js';
/**
* `supportedAlgorithms` is an object mapping algorithm names to their respective implementations
* Each entry in this map specifies the algorithm name and its associated properties, including the
* implementation class and any relevant names or identifiers for the algorithm. This structure
* allows for easy retrieval and instantiation of algorithm implementations based on the algorithm
* name or key specification. It facilitates the support of multiple algorithms within the
* `LocalKeyManager` class.
*/
const supportedAlgorithms = {
'AES-GCM': {
implementation: AesGcmAlgorithm,
names: ['A128GCM', 'A192GCM', 'A256GCM'],
},
'AES-KW': {
implementation: AesKwAlgorithm,
names: ['A128KW', 'A192KW', 'A256KW'],
},
'Ed25519': {
implementation: EdDsaAlgorithm,
names: ['Ed25519'],
},
'secp256k1': {
implementation: EcdsaAlgorithm,
names: ['ES256K', 'secp256k1'],
},
'secp256r1': {
implementation: EcdsaAlgorithm,
names: ['ES256', 'secp256r1'],
},
'SHA-256': {
implementation: Sha2Algorithm,
names: ['SHA-256']
}
};
export class LocalKeyManager {
constructor({ agent, keyStore } = {}) {
/**
* A private map that stores instances of cryptographic algorithm implementations. Each key in
* this map is an `AlgorithmConstructor`, and its corresponding value is an instance of a class
* that implements a specific cryptographic algorithm. This map is used to cache and reuse
* instances for performance optimization, ensuring that each algorithm is instantiated only once.
*/
this._algorithmInstances = new Map();
this._agent = agent;
this._keyStore = keyStore !== null && keyStore !== void 0 ? keyStore : new InMemoryKeyStore();
}
/**
* Retrieves the `Web5PlatformAgent` execution context.
*
* @returns The `Web5PlatformAgent` instance that represents the current execution context.
* @throws Will throw an error if the `agent` instance property is undefined.
*/
get agent() {
if (this._agent === undefined) {
throw new Error('LocalKeyManager: Unable to determine agent execution context.');
}
return this._agent;
}
set agent(agent) {
this._agent = agent;
}
decrypt(_a) {
var { keyUri } = _a, params = __rest(_a, ["keyUri"]);
return __awaiter(this, void 0, void 0, function* () {
// Get the private key from the key store.
const privateKey = yield this.getPrivateKey({ keyUri });
// Determine the algorithm name based on the JWK's `alg` property.
const algorithm = this.getAlgorithmName({ key: privateKey });
// Get the cipher algorithm based on the algorithm name.
const cipher = this.getAlgorithm({ algorithm });
// Encrypt the data.
const ciphertext = yield cipher.decrypt(Object.assign({ key: privateKey }, params));
return ciphertext;
});
}
digest(_params) {
throw new Error('Method not implemented.');
}
encrypt(_a) {
var { keyUri } = _a, params = __rest(_a, ["keyUri"]);
return __awaiter(this, void 0, void 0, function* () {
// Get the private key from the key store.
const privateKey = yield this.getPrivateKey({ keyUri });
// Determine the algorithm name based on the JWK's `alg` property.
const algorithm = this.getAlgorithmName({ key: privateKey });
// Get the cipher algorithm based on the algorithm name.
const cipher = this.getAlgorithm({ algorithm });
// Encrypt the data.
const ciphertext = yield cipher.encrypt(Object.assign({ key: privateKey }, params));
return ciphertext;
});
}
/**
* Exports a private key identified by the provided key URI from the local KMS.
*
* @remarks
* This method retrieves the key from the key store and returns it. It is primarily used
* for extracting keys for backup or transfer purposes.
*
* @example
* ```ts
* const keyManager = new LocalKeyManager();
* const keyUri = await keyManager.generateKey({ algorithm: 'Ed25519' });
* const privateKey = await keyManager.exportKey({ keyUri });
* ```
*
* @param params - Parameters for exporting the key.
* @param params.keyUri - The key URI identifying the key to export.
*
* @returns A Promise resolving to the JWK representation of the exported key.
*/
exportKey({ keyUri }) {
return __awaiter(this, void 0, void 0, function* () {
// Get the private key from the key store.
const privateKey = yield this.getPrivateKey({ keyUri });
return privateKey;
});
}
/**
* Generates a new cryptographic key in the local KMS with the specified algorithm and returns a
* unique key URI which can be used to reference the key in subsequent operations.
*
* @example
* ```ts
* const keyManager = new LocalKeyManager();
* const keyUri = await keyManager.generateKey({ algorithm: 'Ed25519' });
* console.log(keyUri); // Outputs the key URI
* ```
*
* @param params - The parameters for key generation.
* @param params.algorithm - The algorithm to use for key generation, defined in `SupportedAlgorithm`.
*
* @returns A Promise that resolves to the key URI, a unique identifier for the generated key.
*/
generateKey({ algorithm: algorithmIdentifier }) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
// Determine the algorithm name based on the given algorithm identifier.
const algorithm = this.getAlgorithmName({ key: { alg: algorithmIdentifier } });
// Get the key generator implementation based on the algorithm.
const keyGenerator = this.getAlgorithm({ algorithm });
// Generate the key.
const privateKey = yield keyGenerator.generateKey({ algorithm: algorithmIdentifier });
// If the key ID is undefined, set it to the JWK thumbprint.
(_a = privateKey.kid) !== null && _a !== void 0 ? _a : (privateKey.kid = yield computeJwkThumbprint({ jwk: privateKey }));
// Compute the key URI for the key.
const keyUri = yield this.getKeyUri({ key: privateKey });
// Store the key in the key store.
yield this._keyStore.set({
id: keyUri,
data: privateKey,
agent: this.agent,
preventDuplicates: false,
useCache: true
});
return keyUri;
});
}
/**
* Computes the Key URI for a given public JWK (JSON Web Key).
*
* @remarks
* This method generates a {@link https://datatracker.ietf.org/doc/html/rfc3986 | URI}
* (Uniform Resource Identifier) for the given JWK, which uniquely identifies the key across all
* `CryptoApi` implementations. The key URI is constructed by appending the
* {@link https://datatracker.ietf.org/doc/html/rfc7638 | JWK thumbprint} to the prefix
* `urn:jwk:`. The JWK thumbprint is deterministically computed from the JWK and is consistent
* regardless of property order or optional property inclusion in the JWK. This ensures that the
* same key material represented as a JWK will always yield the same thumbprint, and therefore,
* the same key URI.
*
* @example
* ```ts
* const keyManager = new LocalKeyManager();
* const keyUri = await keyManager.generateKey({ algorithm: 'Ed25519' });
* const publicKey = await keyManager.getPublicKey({ keyUri });
* const keyUriFromPublicKey = await keyManager.getKeyUri({ key: publicKey });
* console.log(keyUri === keyUriFromPublicKey); // Outputs `true`
* ```
*
* @param params - The parameters for getting the key URI.
* @param params.key - The JWK for which to compute the key URI.
*
* @returns A Promise that resolves to the key URI as a string.
*/
getKeyUri({ key }) {
return __awaiter(this, void 0, void 0, function* () {
// Compute the JWK thumbprint.
const jwkThumbprint = yield computeJwkThumbprint({ jwk: key });
// Construct the key URI by appending the JWK thumbprint to the key URI prefix.
const keyUri = `${KEY_URI_PREFIX_JWK}${jwkThumbprint}`;
return keyUri;
});
}
/**
* Retrieves the public key associated with a previously generated private key, identified by
* the provided key URI.
*
* @example
* ```ts
* const keyManager = new LocalKeyManager();
* const keyUri = await keyManager.generateKey({ algorithm: 'Ed25519' });
* const publicKey = await keyManager.getPublicKey({ keyUri });
* ```
*
* @param params - The parameters for retrieving the public key.
* @param params.keyUri - The key URI of the private key to retrieve the public key for.
*
* @returns A Promise that resolves to the public key in JWK format.
*/
getPublicKey({ keyUri }) {
return __awaiter(this, void 0, void 0, function* () {
// Get the private key from the key store.
const privateKey = yield this.getPrivateKey({ keyUri });
// Determine the algorithm name based on the JWK's `alg` and `crv` properties.
const algorithm = this.getAlgorithmName({ key: privateKey });
// Get the key generator based on the algorithm name.
const keyGenerator = this.getAlgorithm({ algorithm });
// Get the public key properties from the private JWK.
const publicKey = yield keyGenerator.getPublicKey({ key: privateKey });
return publicKey;
});
}
/**
* Imports a private key into the local KMS.
*
* @remarks
* This method stores the provided JWK in the key store, making it available for subsequent
* cryptographic operations. It is particularly useful for initializing the KMS with pre-existing
* keys or for restoring keys from backups.
*
* Note that, if defined, the `kid` (key ID) property of the JWK is used as the key URI for the
* imported key. If the `kid` property is not provided, the key URI is computed from the JWK
* thumbprint of the key.
*
* @example
* ```ts
* const keyManager = new LocalKeyManager();
* const privateKey = { ... } // A private key in JWK format
* const keyUri = await keyManager.importKey({ key: privateKey });
* ```
*
* @param params - Parameters for importing the key.
* @param params.key - The private key to import to in JWK format.
*
* @returns A Promise resolving to the key URI, uniquely identifying the imported key.
*/
importKey({ key }) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
if (!isPrivateJwk(key))
throw new TypeError('Invalid key provided. Must be a private key in JWK format.');
// Make a deep copy of the key to avoid mutating the original.
const privateKey = structuredClone(key);
// If the key ID is undefined, set it to the JWK thumbprint.
(_a = privateKey.kid) !== null && _a !== void 0 ? _a : (privateKey.kid = yield computeJwkThumbprint({ jwk: privateKey }));
// Compute the key URI for the key.
const keyUri = yield this.getKeyUri({ key: privateKey });
// Store the key in the key store.
yield this._keyStore.set({
id: keyUri,
data: privateKey,
agent: this.agent,
preventDuplicates: true,
useCache: true
});
return keyUri;
});
}
/**
* Signs the provided data using the private key identified by the provided key URI.
*
* @remarks
* This method uses the signature algorithm determined by the `alg` and/or `crv` properties of the
* private key identified by the provided key URI to sign the provided data. The signature can
* later be verified by parties with access to the corresponding public key, ensuring that the
* data has not been tampered with and was indeed signed by the holder of the private key.
*
* @example
* ```ts
* const keyManager = new LocalKeyManager();
* const keyUri = await keyManager.generateKey({ algorithm: 'Ed25519' });
* const data = new TextEncoder().encode('Message to sign');
* const signature = await keyManager.sign({ keyUri, data });
* ```
*
* @param params - The parameters for the signing operation.
* @param params.keyUri - The key URI of the private key to use for signing.
* @param params.data - The data to sign.
*
* @returns A Promise resolving to the digital signature as a `Uint8Array`.
*/
sign({ keyUri, data }) {
return __awaiter(this, void 0, void 0, function* () {
// Get the private key from the key store.
const privateKey = yield this.getPrivateKey({ keyUri });
// Determine the algorithm name based on the JWK's `alg` and `crv` properties.
const algorithm = this.getAlgorithmName({ key: privateKey });
// Get the signature algorithm based on the algorithm name.
const signer = this.getAlgorithm({ algorithm });
// Sign the data.
const signature = signer.sign({ data, key: privateKey });
return signature;
});
}
unwrapKey({ wrappedKeyBytes, wrappedKeyAlgorithm, decryptionKeyUri }) {
return __awaiter(this, void 0, void 0, function* () {
// Get the private key from the key store.
const decryptionKey = yield this.getPrivateKey({ keyUri: decryptionKeyUri });
// Determine the algorithm name based on the JWK's `alg` property.
const algorithm = this.getAlgorithmName({ key: decryptionKey });
// Get the key wrapping algorithm based on the algorithm name.
const keyWrapper = this.getAlgorithm({ algorithm });
// Decrypt the key.
const unwrappedKey = yield keyWrapper.unwrapKey({ wrappedKeyBytes, wrappedKeyAlgorithm, decryptionKey });
return unwrappedKey;
});
}
/**
* Verifies a digital signature associated the provided data using the provided key.
*
* @remarks
* This method uses the signature algorithm determined by the `alg` and/or `crv` properties of the
* provided key to check the validity of a digital signature against the original data. It
* confirms whether the signature was created by the holder of the corresponding private key and
* that the data has not been tampered with.
*
* @example
* ```ts
* const keyManager = new LocalKeyManager();
* const keyUri = await keyManager.generateKey({ algorithm: 'Ed25519' });
* const data = new TextEncoder().encode('Message to sign');
* const signature = await keyManager.sign({ keyUri, data });
* const isSignatureValid = await keyManager.verify({ keyUri, data, signature });
* ```
*
* @param params - The parameters for the verification operation.
* @param params.key - The key to use for verification.
* @param params.signature - The signature to verify.
* @param params.data - The data to verify.
*
* @returns A Promise resolving to a boolean indicating whether the signature is valid.
*/
verify({ key, signature, data }) {
return __awaiter(this, void 0, void 0, function* () {
// Determine the algorithm name based on the JWK's `alg` and `crv` properties.
const algorithm = this.getAlgorithmName({ key });
// Get the signature algorithm based on the algorithm name.
const signer = this.getAlgorithm({ algorithm });
// Verify the signature.
const isSignatureValid = signer.verify({ key, signature, data });
return isSignatureValid;
});
}
wrapKey({ unwrappedKey, encryptionKeyUri }) {
return __awaiter(this, void 0, void 0, function* () {
// Get the private key from the key store.
const encryptionKey = yield this.getPrivateKey({ keyUri: encryptionKeyUri });
// Determine the algorithm name based on the JWK's `alg` property.
const algorithm = this.getAlgorithmName({ key: encryptionKey });
// Get the key wrapping algorithm based on the algorithm name.
const keyWrapper = this.getAlgorithm({ algorithm });
// Encrypt the key.
const wrappedKeyBytes = yield keyWrapper.wrapKey({ unwrappedKey, encryptionKey });
return wrappedKeyBytes;
});
}
/**
* Retrieves an algorithm implementation instance based on the provided algorithm name.
*
* @remarks
* This method checks if the requested algorithm is supported and returns a cached instance
* if available. If an instance does not exist, it creates and caches a new one. This approach
* optimizes performance by reusing algorithm instances across cryptographic operations.
*
* @example
* ```ts
* const signer = this.getAlgorithm({ algorithm: 'Ed25519' });
* ```
*
* @param params - The parameters for retrieving the algorithm implementation.
* @param params.algorithm - The name of the algorithm to retrieve.
*
* @returns An instance of the requested algorithm implementation.
*
* @throws Error if the requested algorithm is not supported.
*/
getAlgorithm({ algorithm }) {
var _a;
// Check if algorithm is supported.
const AlgorithmImplementation = (_a = supportedAlgorithms[algorithm]) === null || _a === void 0 ? void 0 : _a['implementation'];
if (!AlgorithmImplementation) {
throw new CryptoError(CryptoErrorCode.AlgorithmNotSupported, `Algorithm not supported: ${algorithm}`);
}
// Check if instance already exists for the `AlgorithmImplementation`.
if (!this._algorithmInstances.has(AlgorithmImplementation)) {
// If not, create a new instance and store it in the cache
this._algorithmInstances.set(AlgorithmImplementation, new AlgorithmImplementation());
}
// Return the cached instance
return this._algorithmInstances.get(AlgorithmImplementation);
}
/**
* Determines the algorithm name based on the key's properties.
*
* @remarks
* This method facilitates the identification of the correct algorithm for cryptographic
* operations based on the `alg` or `crv` properties of a {@link Jwk | JWK}.
*
* @example
* ```ts
* const publicKey = { ... }; // Public key in JWK format
* const algorithm = this.getAlgorithmName({ key: publicKey });
* ```
*
* @param params - The parameters for determining the algorithm name.
* @param params.key - A JWK containing the `alg` or `crv` properties.
*
* @returns The algorithm name associated with the key.
*
* @throws Error if the algorithm name cannot be determined from the provided input.
*/
getAlgorithmName({ key }) {
const algProperty = key.alg;
const crvProperty = key.crv;
for (const algorithmIdentifier of Object.keys(supportedAlgorithms)) {
const algorithmNames = supportedAlgorithms[algorithmIdentifier].names;
if (algProperty && algorithmNames.includes(algProperty)) {
return algorithmIdentifier;
}
else if (crvProperty && algorithmNames.includes(crvProperty)) {
return algorithmIdentifier;
}
}
throw new CryptoError(CryptoErrorCode.AlgorithmNotSupported, `Algorithm not supported based on provided input: alg=${algProperty}, crv=${crvProperty}. ` +
'Please check the documentation for the list of supported algorithms.');
}
/**
* Retrieves a private key from the key store based on the provided key URI.
*
* @example
* ```ts
* const privateKey = this.getPrivateKey({ keyUri: 'urn:jwk:...' });
* ```
*
* @param params - Parameters for retrieving the private key.
* @param params.keyUri - The key URI identifying the private key to retrieve.
*
* @returns A Promise resolving to the JWK representation of the private key.
*
* @throws Error if the key is not found in the key store.
*/
getPrivateKey({ keyUri }) {
return __awaiter(this, void 0, void 0, function* () {
// Get the private key from the key store.
const privateKey = yield this._keyStore.get({ id: keyUri, agent: this.agent, useCache: true });
if (!privateKey) {
throw new Error(`Key not found: ${keyUri}`);
}
return privateKey;
});
}
}
//# sourceMappingURL=local-key-manager.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,2 @@
export {};
//# sourceMappingURL=dwn-rpc-types.js.map
@@ -0,0 +1 @@
{"version":3,"file":"dwn-rpc-types.js","sourceRoot":"","sources":["../../../../src/prototyping/clients/dwn-rpc-types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,74 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import ms from 'ms';
import { TtlCache } from '@web5/common';
export class DwnServerInfoCacheMemory {
constructor({ ttl = '15m' } = {}) {
this.cache = new TtlCache({ ttl: ms(ttl) });
}
/**
* Retrieves a DWN ServerInfo entry from the cache.
*
* If the cached item has exceeded its TTL, it's scheduled for deletion and undefined is returned.
*
* @param dwnUrl - The DWN URL endpoint string used as the key for getting the entry.
* @returns The cached DWN ServerInfo entry or undefined if not found or expired.
*/
get(dwnUrl) {
return __awaiter(this, void 0, void 0, function* () {
return this.cache.get(dwnUrl);
});
}
/**
* Stores a DWN ServerInfo entry in the cache with a TTL.
*
* @param dwnUrl - The DWN URL endpoint string used as the key for storing the entry.
* @param value - The DWN ServerInfo entry to be cached.
* @returns A promise that resolves when the operation is complete.
*/
set(dwnUrl, value) {
return __awaiter(this, void 0, void 0, function* () {
this.cache.set(dwnUrl, value);
});
}
/**
* Deletes a DWN ServerInfo entry from the cache.
*
* @param dwnUrl - The DWN URL endpoint string used as the key for deletion.
* @returns A promise that resolves when the operation is complete.
*/
delete(dwnUrl) {
return __awaiter(this, void 0, void 0, function* () {
this.cache.delete(dwnUrl);
});
}
/**
* Clears all entries from the cache.
*
* @returns A promise that resolves when the operation is complete.
*/
clear() {
return __awaiter(this, void 0, void 0, function* () {
this.cache.clear();
});
}
/**
* This method is a no-op but exists to be consistent with other DWN ServerInfo Cache
* implementations.
*
* @returns A promise that resolves immediately.
*/
close() {
return __awaiter(this, void 0, void 0, function* () {
// No-op since there is no underlying store to close.
});
}
}
//# sourceMappingURL=dwn-server-info-cache-memory.js.map
@@ -0,0 +1 @@
{"version":3,"file":"dwn-server-info-cache-memory.js","sourceRoot":"","sources":["../../../../src/prototyping/clients/dwn-server-info-cache-memory.ts"],"names":[],"mappings":";;;;;;;;;AACA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAkBxC,MAAM,OAAO,wBAAwB;IAGnC,YAAY,EAAE,GAAG,GAAG,KAAK,KAAoC,EAAE;QAC7D,IAAI,CAAC,KAAK,GAAG,IAAI,QAAQ,CAAC,EAAE,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC9C,CAAC;IAED;;;;;;;OAOG;IACU,GAAG,CAAC,MAAc;;YAC7B,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAChC,CAAC;KAAA;IAED;;;;;;OAMG;IACU,GAAG,CAAC,MAAc,EAAE,KAAiB;;YAChD,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;QAChC,CAAC;KAAA;IAED;;;;;OAKG;IACU,MAAM,CAAC,MAAc;;YAChC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAC5B,CAAC;KAAA;IAED;;;;OAIG;IACU,KAAK;;YAChB,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACrB,CAAC;KAAA;IAED;;;;;OAKG;IACU,KAAK;;YAChB,qDAAqD;QACvD,CAAC;KAAA;CACF"}
@@ -0,0 +1,102 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { createJsonRpcRequest, parseJson } from './json-rpc.js';
import { utils as cryptoUtils } from '@web5/crypto';
import { DwnServerInfoCacheMemory } from './dwn-server-info-cache-memory.js';
/**
* HTTP client that can be used to communicate with Dwn Servers
*/
export class HttpDwnRpcClient {
constructor(serverInfoCache) {
this.serverInfoCache = serverInfoCache !== null && serverInfoCache !== void 0 ? serverInfoCache : new DwnServerInfoCacheMemory();
}
get transportProtocols() { return ['http:', 'https:']; }
sendDwnRequest(request) {
return __awaiter(this, void 0, void 0, function* () {
const requestId = cryptoUtils.randomUuid();
const jsonRpcRequest = createJsonRpcRequest(requestId, 'dwn.processMessage', {
target: request.targetDid,
message: request.message
});
const fetchOpts = {
method: 'POST',
headers: {
'dwn-request': JSON.stringify(jsonRpcRequest)
}
};
if (request.data) {
// @ts-expect-error TODO: REMOVE
fetchOpts.headers['content-type'] = 'application/octet-stream';
// @ts-expect-error TODO: REMOVE
fetchOpts['body'] = request.data;
}
const resp = yield fetch(request.dwnUrl, fetchOpts);
let dwnRpcResponse;
// check to see if response is in header first. if it is, that means the response is a ReadableStream
let dataStream;
const { headers } = resp;
if (headers.has('dwn-response')) {
// @ts-expect-error TODO: REMOVE
const jsonRpcResponse = parseJson(headers.get('dwn-response'));
if (jsonRpcResponse == null) {
throw new Error(`failed to parse json rpc response. dwn url: ${request.dwnUrl}`);
}
dataStream = resp.body;
dwnRpcResponse = jsonRpcResponse;
}
else {
// TODO: wonder if i need to try/catch this?
const responseBody = yield resp.text();
dwnRpcResponse = JSON.parse(responseBody);
}
if (dwnRpcResponse.error) {
const { code, message } = dwnRpcResponse.error;
throw new Error(`(${code}) - ${message}`);
}
const { reply } = dwnRpcResponse.result;
if (dataStream) {
reply['record']['data'] = dataStream;
}
return reply;
});
}
getServerInfo(dwnUrl) {
return __awaiter(this, void 0, void 0, function* () {
const serverInfo = yield this.serverInfoCache.get(dwnUrl);
if (serverInfo) {
return serverInfo;
}
const url = new URL(dwnUrl);
// add `/info` to the dwn server url path
url.pathname.endsWith('/') ? url.pathname += 'info' : url.pathname += '/info';
try {
const response = yield fetch(url.toString());
if (response.ok) {
const results = yield response.json();
// explicitly return and cache only the desired properties.
const serverInfo = {
registrationRequirements: results.registrationRequirements,
maxFileSize: results.maxFileSize,
webSocketSupport: results.webSocketSupport,
};
this.serverInfoCache.set(dwnUrl, serverInfo);
return serverInfo;
}
else {
throw new Error(`HTTP (${response.status}) - ${response.statusText}`);
}
}
catch (error) {
throw new Error(`Error encountered while processing response from ${url.toString()}: ${error.message}`);
}
});
}
}
//# sourceMappingURL=http-dwn-rpc-client.js.map
@@ -0,0 +1 @@
{"version":3,"file":"http-dwn-rpc-client.js","sourceRoot":"","sources":["../../../../src/prototyping/clients/http-dwn-rpc-client.ts"],"names":[],"mappings":";;;;;;;;;AAGA,OAAO,EAAE,oBAAoB,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAChE,OAAO,EAAE,KAAK,IAAI,WAAW,EAAE,MAAM,cAAc,CAAC;AAEpD,OAAO,EAAE,wBAAwB,EAAE,MAAM,mCAAmC,CAAC;AAE7E;;GAEG;AACH,MAAM,OAAO,gBAAgB;IAE3B,YAAY,eAAoC;QAC9C,IAAI,CAAC,eAAe,GAAG,eAAe,aAAf,eAAe,cAAf,eAAe,GAAI,IAAI,wBAAwB,EAAE,CAAC;IAC3E,CAAC;IAED,IAAI,kBAAkB,KAAK,OAAO,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;IAElD,cAAc,CAAC,OAAsB;;YACzC,MAAM,SAAS,GAAG,WAAW,CAAC,UAAU,EAAE,CAAC;YAC3C,MAAM,cAAc,GAAG,oBAAoB,CAAC,SAAS,EAAE,oBAAoB,EAAE;gBAC3E,MAAM,EAAI,OAAO,CAAC,SAAS;gBAC3B,OAAO,EAAG,OAAO,CAAC,OAAO;aAC1B,CAAC,CAAC;YAEH,MAAM,SAAS,GAAG;gBAChB,MAAM,EAAI,MAAM;gBAChB,OAAO,EAAG;oBACR,aAAa,EAAE,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC;iBAC9C;aACF,CAAC;YAEF,IAAI,OAAO,CAAC,IAAI,EAAE;gBAChB,gCAAgC;gBAChC,SAAS,CAAC,OAAO,CAAC,cAAc,CAAC,GAAG,0BAA0B,CAAC;gBAC/D,gCAAgC;gBAChC,SAAS,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;aAClC;YAED,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;YACpD,IAAI,cAA+B,CAAC;YAEpC,qGAAqG;YACrG,IAAI,UAAU,CAAC;YACf,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;YACzB,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE;gBAC/B,gCAAgC;gBAChC,MAAM,eAAe,GAAG,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAoB,CAAC;gBAElF,IAAI,eAAe,IAAI,IAAI,EAAE;oBAC3B,MAAM,IAAI,KAAK,CAAC,+CAA+C,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;iBAClF;gBAED,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC;gBACvB,cAAc,GAAG,eAAe,CAAC;aAClC;iBAAM;gBACL,4CAA4C;gBAC5C,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;gBACvC,cAAc,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;aAC3C;YAED,IAAI,cAAc,CAAC,KAAK,EAAE;gBACxB,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,cAAc,CAAC,KAAK,CAAC;gBAC/C,MAAM,IAAI,KAAK,CAAC,IAAI,IAAI,OAAO,OAAO,EAAE,CAAC,CAAC;aAC3C;YAED,MAAM,EAAE,KAAK,EAAE,GAAG,cAAc,CAAC,MAAM,CAAC;YACxC,IAAI,UAAU,EAAE;gBACd,KAAK,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,GAAG,UAAU,CAAC;aACtC;YAED,OAAO,KAAuB,CAAC;QACjC,CAAC;KAAA;IAEK,aAAa,CAAC,MAAc;;YAChC,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YAC1D,IAAI,UAAU,EAAE;gBACd,OAAO,UAAU,CAAC;aACnB;YAED,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC;YAE5B,yCAAyC;YACzC,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,IAAI,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,IAAI,OAAO,CAAC;YAE9E,IAAI;gBACF,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC;gBAC7C,IAAG,QAAQ,CAAC,EAAE,EAAE;oBACd,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAgB,CAAC;oBAEpD,2DAA2D;oBAC3D,MAAM,UAAU,GAAG;wBACjB,wBAAwB,EAAG,OAAO,CAAC,wBAAwB;wBAC3D,WAAW,EAAgB,OAAO,CAAC,WAAW;wBAC9C,gBAAgB,EAAW,OAAO,CAAC,gBAAgB;qBACpD,CAAC;oBACF,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;oBAE7C,OAAO,UAAU,CAAC;iBACnB;qBAAM;oBACL,MAAM,IAAI,KAAK,CAAC,SAAS,QAAQ,CAAC,MAAM,OAAO,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;iBACvE;aACF;YAAC,OAAM,KAAU,EAAE;gBAClB,MAAM,IAAI,KAAK,CAAC,oDAAoD,GAAG,CAAC,QAAQ,EAAE,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;aACzG;QACH,CAAC;KAAA;CACF"}
@@ -0,0 +1,150 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { utils as cryptoUtils } from '@web5/crypto';
import IsomorphicWebSocket from 'isomorphic-ws';
import { createJsonRpcSubscriptionRequest, parseJson } from './json-rpc.js';
// These were arbitrarily chosen, but can be modified via connect options
const CONNECT_TIMEOUT = 3000;
const RESPONSE_TIMEOUT = 30000;
/**
* JSON RPC Socket Client for WebSocket request/response and long-running subscriptions.
*
* NOTE: This is temporarily copied over from https://github.com/TBD54566975/dwn-server/blob/main/src/json-rpc-socket.ts
* This was done in order to avoid taking a dependency on the `dwn-server`, until a future time when there will be a `clients` package.
*/
export class JsonRpcSocket {
constructor(socket, responseTimeout) {
this.socket = socket;
this.responseTimeout = responseTimeout;
this.messageHandlers = new Map();
}
static connect(url, options = {}) {
return __awaiter(this, void 0, void 0, function* () {
const { connectTimeout = CONNECT_TIMEOUT, responseTimeout = RESPONSE_TIMEOUT, onclose, onerror } = options;
const socket = new IsomorphicWebSocket(url);
if (!onclose) {
socket.onclose = () => {
console.info(`JSON RPC Socket close ${url}`);
};
}
else {
socket.onclose = onclose;
}
if (!onerror) {
socket.onerror = (error) => {
console.error(`JSON RPC Socket error ${url}`, error);
};
}
else {
socket.onerror = onerror;
}
return new Promise((resolve, reject) => {
socket.addEventListener('open', () => {
const jsonRpcSocket = new JsonRpcSocket(socket, responseTimeout);
socket.addEventListener('message', (event) => {
const jsonRpcResponse = parseJson(event.data);
const handler = jsonRpcSocket.messageHandlers.get(jsonRpcResponse.id);
if (handler) {
handler(event);
}
});
resolve(jsonRpcSocket);
});
socket.addEventListener('error', (error) => {
reject(error);
});
setTimeout(() => reject, connectTimeout);
});
});
}
close() {
this.socket.close();
}
/**
* Sends a JSON-RPC request through the socket and waits for a single response.
*/
request(request) {
return __awaiter(this, void 0, void 0, function* () {
return new Promise((resolve, reject) => {
var _a;
(_a = request.id) !== null && _a !== void 0 ? _a : (request.id = cryptoUtils.randomUuid());
const handleResponse = (event) => {
const jsonRpsResponse = parseJson(event.data);
if (jsonRpsResponse.id === request.id) {
// if the incoming response id matches the request id, we will remove the listener and resolve the response
this.messageHandlers.delete(request.id);
return resolve(jsonRpsResponse);
}
};
// add the listener to the map of message handlers
this.messageHandlers.set(request.id, handleResponse);
this.send(request);
// reject this promise if we don't receive any response back within the timeout period
setTimeout(() => {
this.messageHandlers.delete(request.id);
reject(new Error('request timed out'));
}, this.responseTimeout);
});
});
}
/**
* Sends a JSON-RPC request through the socket and keeps a listener open to read associated responses as they arrive.
* Returns a close method to clean up the listener.
*/
subscribe(request, listener) {
return __awaiter(this, void 0, void 0, function* () {
if (!request.method.startsWith('rpc.subscribe.')) {
throw new Error('subscribe rpc requests must include the `rpc.subscribe` prefix');
}
if (!request.subscription) {
throw new Error('subscribe rpc requests must include subscribe options');
}
const subscriptionId = request.subscription.id;
const socketEventListener = (event) => {
const jsonRpcResponse = parseJson(event.data.toString());
if (jsonRpcResponse.id === subscriptionId) {
if (jsonRpcResponse.error !== undefined) {
// remove the event listener upon receipt of a JSON RPC Error.
this.messageHandlers.delete(subscriptionId);
this.closeSubscription(subscriptionId);
}
listener(jsonRpcResponse);
}
};
this.messageHandlers.set(subscriptionId, socketEventListener);
const response = yield this.request(request);
if (response.error) {
this.messageHandlers.delete(subscriptionId);
return { response };
}
// clean up listener and create a `rpc.subscribe.close` message to use when closing this JSON RPC subscription
const close = () => __awaiter(this, void 0, void 0, function* () {
this.messageHandlers.delete(subscriptionId);
yield this.closeSubscription(subscriptionId);
});
return {
response,
close
};
});
}
closeSubscription(id) {
const requestId = cryptoUtils.randomUuid();
const request = createJsonRpcSubscriptionRequest(requestId, 'close', id, {});
return this.request(request);
}
/**
* Sends a JSON-RPC request through the socket. You must subscribe to a message listener separately to capture the response.
*/
send(request) {
this.socket.send(JSON.stringify(request));
}
}
//# sourceMappingURL=json-rpc-socket.js.map
@@ -0,0 +1 @@
{"version":3,"file":"json-rpc-socket.js","sourceRoot":"","sources":["../../../../src/prototyping/clients/json-rpc-socket.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,57 @@
export var JsonRpcErrorCodes;
(function (JsonRpcErrorCodes) {
// JSON-RPC 2.0 pre-defined errors
JsonRpcErrorCodes[JsonRpcErrorCodes["InvalidRequest"] = -32600] = "InvalidRequest";
JsonRpcErrorCodes[JsonRpcErrorCodes["MethodNotFound"] = -32601] = "MethodNotFound";
JsonRpcErrorCodes[JsonRpcErrorCodes["InvalidParams"] = -32602] = "InvalidParams";
JsonRpcErrorCodes[JsonRpcErrorCodes["InternalError"] = -32603] = "InternalError";
JsonRpcErrorCodes[JsonRpcErrorCodes["ParseError"] = -32700] = "ParseError";
JsonRpcErrorCodes[JsonRpcErrorCodes["TransportError"] = -32300] = "TransportError";
// App defined errors
JsonRpcErrorCodes[JsonRpcErrorCodes["BadRequest"] = -50400] = "BadRequest";
JsonRpcErrorCodes[JsonRpcErrorCodes["Unauthorized"] = -50401] = "Unauthorized";
JsonRpcErrorCodes[JsonRpcErrorCodes["Forbidden"] = -50403] = "Forbidden";
})(JsonRpcErrorCodes || (JsonRpcErrorCodes = {}));
export const createJsonRpcErrorResponse = (id, code, message, data) => {
const error = { code, message, data };
return {
jsonrpc: '2.0',
id,
error,
};
};
export const createJsonRpcRequest = (id, method, params) => {
return {
jsonrpc: '2.0',
id,
method,
params,
};
};
export const createJsonRpcSubscriptionRequest = (id, method, subscriptionId, params) => {
return {
jsonrpc: '2.0',
id,
method: `rpc.subscribe.${method}`,
params,
subscription: {
id: subscriptionId,
}
};
};
export const createJsonRpcSuccessResponse = (id, result) => {
return {
jsonrpc: '2.0',
id,
result,
};
};
export function parseJson(text) {
try {
return JSON.parse(text);
}
catch (_a) {
return null;
}
}
//# sourceMappingURL=json-rpc.js.map
@@ -0,0 +1 @@
{"version":3,"file":"json-rpc.js","sourceRoot":"","sources":["../../../../src/prototyping/clients/json-rpc.ts"],"names":[],"mappings":"AAmBA,MAAM,CAAN,IAAY,iBAaX;AAbD,WAAY,iBAAiB;IAC3B,kCAAkC;IAClC,kFAAuB,CAAA;IACvB,kFAAuB,CAAA;IACvB,gFAAsB,CAAA;IACtB,gFAAsB,CAAA;IACtB,0EAAmB,CAAA;IACnB,kFAAuB,CAAA;IAEvB,qBAAqB;IACrB,0EAAmB,CAAA;IACnB,8EAAqB,CAAA;IACrB,wEAAkB,CAAA;AACpB,CAAC,EAbW,iBAAiB,KAAjB,iBAAiB,QAa5B;AAkBD,MAAM,CAAC,MAAM,0BAA0B,GAAG,CACxC,EAAa,EACb,IAAuB,EACvB,OAAe,EACf,IAAU,EACY,EAAE;IACxB,MAAM,KAAK,GAAiB,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IACpD,OAAO;QACL,OAAO,EAAE,KAAK;QACd,EAAE;QACF,KAAK;KACN,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAClC,EAAa,EACb,MAAc,EACd,MAAsB,EACN,EAAE;IAClB,OAAO;QACL,OAAO,EAAE,KAAK;QACd,EAAE;QACF,MAAM;QACN,MAAM;KACP,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,gCAAgC,GAAG,CAC9C,EAAa,EACb,MAAc,EACd,cAAyB,EACzB,MAAY,EACI,EAAE;IAClB,OAAO;QACL,OAAO,EAAQ,KAAK;QACpB,EAAE;QACF,MAAM,EAAS,iBAAiB,MAAM,EAAE;QACxC,MAAM;QACN,YAAY,EAAG;YACb,EAAE,EAAE,cAAc;SACnB;KACF,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAC1C,EAAa,EACb,MAAW,EACa,EAAE;IAC1B,OAAO;QACL,OAAO,EAAE,KAAK;QACd,EAAE;QACF,MAAM;KACP,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,IAAI;QACF,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;KACzB;IAAC,WAAM;QACN,OAAO,IAAI,CAAC;KACb;AACH,CAAC"}
@@ -0,0 +1,2 @@
export {};
//# sourceMappingURL=server-info-types.js.map
@@ -0,0 +1 @@
{"version":3,"file":"server-info-types.js","sourceRoot":"","sources":["../../../../src/prototyping/clients/server-info-types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,90 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { utils as cryptoUtils } from '@web5/crypto';
import { createJsonRpcRequest, createJsonRpcSubscriptionRequest } from './json-rpc.js';
import { JsonRpcSocket } from './json-rpc-socket.js';
export class WebSocketDwnRpcClient {
get transportProtocols() { return ['ws:', 'wss:']; }
sendDwnRequest(request, jsonRpcSocketOptions) {
return __awaiter(this, void 0, void 0, function* () {
// validate that the dwn URL provided is a valid WebSocket URL
const url = new URL(request.dwnUrl);
if (url.protocol !== 'ws:' && url.protocol !== 'wss:') {
throw new Error(`Invalid websocket protocol ${url.protocol}`);
}
// check if there is already a connection to this host, if it does not exist, initiate a new connection
const hasConnection = WebSocketDwnRpcClient.connections.has(url.host);
if (!hasConnection) {
try {
const socket = yield JsonRpcSocket.connect(url.toString(), jsonRpcSocketOptions);
const subscriptions = new Map();
WebSocketDwnRpcClient.connections.set(url.host, { socket, subscriptions });
}
catch (error) {
throw new Error(`Error connecting to ${url.host}: ${error.message}`);
}
}
const connection = WebSocketDwnRpcClient.connections.get(url.host);
const { targetDid, message, subscriptionHandler } = request;
if (subscriptionHandler) {
return WebSocketDwnRpcClient.subscriptionRequest(connection, targetDid, message, subscriptionHandler);
}
return WebSocketDwnRpcClient.processMessage(connection, targetDid, message);
});
}
static processMessage(connection, target, message) {
return __awaiter(this, void 0, void 0, function* () {
const requestId = cryptoUtils.randomUuid();
const request = createJsonRpcRequest(requestId, 'dwn.processMessage', { target, message });
const { socket } = connection;
const response = yield socket.request(request);
const { error, result } = response;
if (error !== undefined) {
throw new Error(`error sending DWN request: ${error.message}`);
}
return result.reply;
});
}
static subscriptionRequest(connection, target, message, messageHandler) {
return __awaiter(this, void 0, void 0, function* () {
const requestId = cryptoUtils.randomUuid();
const subscriptionId = cryptoUtils.randomUuid();
const request = createJsonRpcSubscriptionRequest(requestId, 'dwn.processMessage', subscriptionId, { target, message });
const { socket, subscriptions } = connection;
const { response, close } = yield socket.subscribe(request, (response) => {
const { result, error } = response;
if (error) {
// if there is an error, close the subscription and delete it from the connection
const subscription = subscriptions.get(subscriptionId);
if (subscription) {
subscription.close();
}
subscriptions.delete(subscriptionId);
return;
}
const { event } = result;
messageHandler(event);
});
const { error, result } = response;
if (error) {
throw new Error(`could not subscribe via jsonrpc socket: ${error.message}`);
}
const { reply } = result;
if (reply.subscription && close) {
subscriptions.set(subscriptionId, Object.assign(Object.assign({}, reply.subscription), { close }));
reply.subscription.close = close;
}
return reply;
});
}
}
// a map of dwn host to WebSocket connection
WebSocketDwnRpcClient.connections = new Map();
//# sourceMappingURL=web-socket-clients.js.map
@@ -0,0 +1 @@
{"version":3,"file":"web-socket-clients.js","sourceRoot":"","sources":["../../../../src/prototyping/clients/web-socket-clients.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
export function hasDuplicateProperties(...objects) {
const propertySet = new Set();
const objectsWithoutUndefined = objects.filter(Boolean); // Remove any undefined values
for (const obj of objectsWithoutUndefined) {
for (const key in obj) {
if (propertySet.has(key)) {
return true; // Return true if a duplicate property is found
}
propertySet.add(key);
}
}
return false; // Return false if no duplicates are found
}
//# sourceMappingURL=object.js.map
@@ -0,0 +1 @@
{"version":3,"file":"object.js","sourceRoot":"","sources":["../../../../src/prototyping/common/object.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,sBAAsB,CAAC,GAAG,OAA+C;IACvF,MAAM,WAAW,GAAG,IAAI,GAAG,EAAU,CAAC;IACtC,MAAM,uBAAuB,GAAG,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,8BAA8B;IAEvF,KAAK,MAAM,GAAG,IAAI,uBAAuB,EAAE;QACzC,KAAK,MAAM,GAAG,IAAI,GAAG,EAAE;YACrB,IAAI,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE;gBACxB,OAAO,IAAI,CAAC,CAAC,+CAA+C;aAC7D;YACD,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;SACtB;KACF;IAED,OAAO,KAAK,CAAC,CAAC,0CAA0C;AAC1D,CAAC"}
@@ -0,0 +1,2 @@
export {};
//# sourceMappingURL=type-utils.js.map
@@ -0,0 +1 @@
{"version":3,"file":"type-utils.js","sourceRoot":"","sources":["../../../../src/prototyping/common/type-utils.ts"],"names":[],"mappings":""}
@@ -0,0 +1,147 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { AesGcm, CryptoAlgorithm } from '@web5/crypto';
/**
* The `AesGcmAlgorithm` class provides a concrete implementation for cryptographic operations using
* the AES algorithm in Galois/Counter Mode (GCM). This class implements both
* {@link Cipher | `Cipher`} and { @link KeyGenerator | `KeyGenerator`} interfaces, providing
* key generation, encryption, and decryption features.
*
* This class is typically accessed through implementations that extend the
* {@link CryptoApi | `CryptoApi`} interface.
*/
export class AesGcmAlgorithm extends CryptoAlgorithm {
bytesToPrivateKey({ privateKeyBytes }) {
return __awaiter(this, void 0, void 0, function* () {
// Convert the byte array to a JWK.
const privateKey = yield AesGcm.bytesToPrivateKey({ privateKeyBytes });
// Set the `alg` property based on the key length.
privateKey.alg = { 16: 'A128GCM', 24: 'A192GCM', 32: 'A256GCM' }[privateKeyBytes.length];
return privateKey;
});
}
/**
* Decrypts the provided data using AES-GCM.
*
* @remarks
* This method performs AES-GCM decryption on the given encrypted data using the specified key.
* It requires an initialization vector (IV), the encrypted data along with the decryption key,
* and optionally, additional authenticated data (AAD). The method returns the decrypted data as a
* Uint8Array. The optional `tagLength` parameter specifies the size in bits of the authentication
* tag used when encrypting the data. If not specified, the default tag length of 128 bits is
* used.
*
* @example
* ```ts
* const aesGcm = new AesGcmAlgorithm();
* const encryptedData = new Uint8Array([...]); // Encrypted data
* const iv = new Uint8Array([...]); // Initialization vector used during encryption
* const additionalData = new Uint8Array([...]); // Optional additional authenticated data
* const key = { ... }; // A Jwk object representing the AES key
* const decryptedData = await aesGcm.decrypt({
* data: encryptedData,
* iv,
* additionalData,
* key,
* tagLength: 128 // Optional tag length in bits
* });
* ```
*
* @param params - The parameters for the decryption operation.
*
* @returns A Promise that resolves to the decrypted data as a Uint8Array.
*/
decrypt(params) {
return __awaiter(this, void 0, void 0, function* () {
const plaintext = AesGcm.decrypt(params);
return plaintext;
});
}
/**
* Encrypts the provided data using AES-GCM.
*
* @remarks
* This method performs AES-GCM encryption on the given data using the specified key.
* It requires an initialization vector (IV), the encrypted data along with the decryption key,
* and optionally, additional authenticated data (AAD). The method returns the encrypted data as a
* Uint8Array. The optional `tagLength` parameter specifies the size in bits of the authentication
* tag generated in the encryption operation and used for authentication in the corresponding
* decryption. If not specified, the default tag length of 128 bits is used.
*
* @example
* ```ts
* const aesGcm = new AesGcmAlgorithm();
* const data = new TextEncoder().encode('Messsage');
* const iv = new Uint8Array([...]); // Initialization vector
* const additionalData = new Uint8Array([...]); // Optional additional authenticated data
* const key = { ... }; // A Jwk object representing an AES key
* const encryptedData = await aesGcm.encrypt({
* data,
* iv,
* additionalData,
* key,
* tagLength: 128 // Optional tag length in bits
* });
* ```
*
* @param params - The parameters for the encryption operation.
*
* @returns A Promise that resolves to the encrypted data as a Uint8Array.
*/
encrypt(params) {
return __awaiter(this, void 0, void 0, function* () {
const ciphertext = AesGcm.encrypt(params);
return ciphertext;
});
}
/**
* Generates a symmetric key for AES in Galois/Counter Mode (GCM) in JSON Web Key (JWK) format.
*
* @remarks
* This method generates a symmetric AES key for use in GCM mode, based on the specified
* `algorithm` parameter which determines the key length. It uses cryptographically secure random
* number generation to ensure the uniqueness and security of the key. The key is returned in JWK
* format.
*
* The generated key includes the following components:
* - `kty`: Key Type, set to 'oct' for Octet Sequence.
* - `k`: The symmetric key component, base64url-encoded.
* - `kid`: Key ID, generated based on the JWK thumbprint.
*
* @example
* ```ts
* const aesGcm = new AesGcmAlgorithm();
* const privateKey = await aesGcm.generateKey({ algorithm: 'A256GCM' });
* ```
*
* @param params - The parameters for the key generation.
*
* @returns A Promise that resolves to the generated symmetric key in JWK format.
*/
generateKey({ algorithm }) {
return __awaiter(this, void 0, void 0, function* () {
// Map algorithm name to key length.
const length = { A128GCM: 128, A192GCM: 192, A256GCM: 256 }[algorithm];
// Generate a random private key.
const privateKey = yield AesGcm.generateKey({ length });
// Set the `alg` property based on the specified algorithm.
privateKey.alg = algorithm;
return privateKey;
});
}
privateKeyToBytes({ privateKey }) {
return __awaiter(this, void 0, void 0, function* () {
// Convert the JWK to a byte array.
const privateKeyBytes = yield AesGcm.privateKeyToBytes({ privateKey });
return privateKeyBytes;
});
}
}
//# sourceMappingURL=aes-gcm.js.map
@@ -0,0 +1 @@
{"version":3,"file":"aes-gcm.js","sourceRoot":"","sources":["../../../../../src/prototyping/crypto/algorithms/aes-gcm.ts"],"names":[],"mappings":";;;;;;;;;AAUA,OAAO,EAAE,MAAM,EAAuB,eAAe,EAAE,MAAM,cAAc,CAAC;AAqD5E;;;;;;;;GAQG;AACH,MAAM,OAAO,eAAgB,SAAQ,eAAe;IAKrC,iBAAiB,CAAC,EAAE,eAAe,EAA2B;;YACzE,mCAAmC;YACnC,MAAM,UAAU,GAAG,MAAM,MAAM,CAAC,iBAAiB,CAAC,EAAE,eAAe,EAAE,CAAC,CAAC;YAEvE,kDAAkD;YAClD,UAAU,CAAC,GAAG,GAAG,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,SAAS,EAAE,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;YAEzF,OAAO,UAAU,CAAC;QACpB,CAAC;KAAA;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA8BG;IACU,OAAO,CAAC,MACS;;YAE5B,MAAM,SAAS,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;YAEzC,OAAO,SAAS,CAAC;QACnB,CAAC;KAAA;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA8BG;IACU,OAAO,CAAC,MACS;;YAE5B,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;YAE1C,OAAO,UAAU,CAAC;QACpB,CAAC;KAAA;IAED;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACU,WAAW,CAAC,EAAE,SAAS,EACX;;YAEvB,oCAAoC;YACpC,MAAM,MAAM,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,SAAS,CAAoB,CAAC;YAE1F,iCAAiC;YACjC,MAAM,UAAU,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;YAExD,2DAA2D;YAC3D,UAAU,CAAC,GAAG,GAAG,SAAS,CAAC;YAE3B,OAAO,UAAU,CAAC;QACpB,CAAC;KAAA;IAEY,iBAAiB,CAAC,EAAE,UAAU,EAA2B;;YACpE,mCAAmC;YACnC,MAAM,eAAe,GAAG,MAAM,MAAM,CAAC,iBAAiB,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC;YAEvE,OAAO,eAAe,CAAC;QACzB,CAAC;KAAA;CACF"}
@@ -0,0 +1,137 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { CryptoAlgorithm } from '@web5/crypto';
import { AesKw } from '../primitives/aes-kw.js';
/**
* The `AesKwAlgorithm` class provides a concrete implementation for cryptographic operations using
* the AES algorithm for key wrapping. This class implements both
* {@link KeyGenerator | `KeyGenerator`} and {@link KeyWrapper | `KeyWrapper`} interfaces, providing
* key generation, key wrapping, and key unwrapping features.
*
* This class is typically accessed through implementations that extend the
* {@link CryptoApi | `CryptoApi`} interface.
*/
export class AesKwAlgorithm extends CryptoAlgorithm {
bytesToPrivateKey({ privateKeyBytes }) {
return __awaiter(this, void 0, void 0, function* () {
// Convert the byte array to a JWK.
const privateKey = yield AesKw.bytesToPrivateKey({ privateKeyBytes });
// Set the `alg` property based on the key length.
privateKey.alg = { 16: 'A128KW', 24: 'A192KW', 32: 'A256KW' }[privateKeyBytes.length];
return privateKey;
});
}
/**
* Generates a symmetric key for AES for key wrapping in JSON Web Key (JWK) format.
*
* @remarks
* This method generates a symmetric AES key for use in key wrapping mode, based on the specified
* `algorithm` parameter which determines the key length. It uses cryptographically secure random
* number generation to ensure the uniqueness and security of the key. The key is returned in JWK
* format.
*
* The generated key includes the following components:
* - `kty`: Key Type, set to 'oct' for Octet Sequence.
* - `k`: The symmetric key component, base64url-encoded.
* - `kid`: Key ID, generated based on the JWK thumbprint.
* - `alg`: Algorithm, set to 'A128KW', 'A192KW', or 'A256KW' for AES Key Wrap with the
* specified key length.
*
* @example
* ```ts
* const aesKw = new AesKwAlgorithm();
* const privateKey = await aesKw.generateKey({ algorithm: 'A256KW' });
* ```
*
* @param params - The parameters for the key generation.
*
* @returns A Promise that resolves to the generated symmetric key in JWK format.
*/
generateKey({ algorithm }) {
return __awaiter(this, void 0, void 0, function* () {
// Map algorithm name to key length.
const length = { A128KW: 128, A192KW: 192, A256KW: 256 }[algorithm];
// Generate a random private key.
const privateKey = yield AesKw.generateKey({ length });
// Set the `alg` property based on the specified algorithm.
privateKey.alg = algorithm;
return privateKey;
});
}
privateKeyToBytes({ privateKey }) {
return __awaiter(this, void 0, void 0, function* () {
// Convert the JWK to a byte array.
const privateKeyBytes = yield AesKw.privateKeyToBytes({ privateKey });
return privateKeyBytes;
});
}
/**
* Decrypts a wrapped key using the AES Key Wrap algorithm.
*
* @remarks
* This method unwraps a previously wrapped cryptographic key using the AES Key Wrap algorithm.
* The wrapped key, provided as a byte array, is unwrapped using the decryption key specified in
* the parameters.
*
* This operation is useful for securely receiving keys transmitted over untrusted mediums. The
* method returns the unwrapped key as a JSON Web Key (JWK).
*
* @example
* ```ts
* const aesKw = new AesKwAlgorithm();
* const wrappedKeyBytes = new Uint8Array([...]); // Byte array of a wrapped AES-256 GCM key
* const decryptionKey = { ... }; // A Jwk object representing the AES unwrapping key
* const unwrappedKey = await aesKw.unwrapKey({
* wrappedKeyBytes,
* wrappedKeyAlgorithm: 'A256GCM',
* decryptionKey
* });
* ```
*
* @param params - The parameters for the key unwrapping operation.
*
* @returns A Promise that resolves to the unwrapped key in JWK format.
*/
unwrapKey(params) {
return __awaiter(this, void 0, void 0, function* () {
const unwrappedKey = yield AesKw.unwrapKey(params);
return unwrappedKey;
});
}
/**
* Encrypts a given key using the AES Key Wrap algorithm.
*
* @remarks
* This method wraps a given cryptographic key using the AES Key Wrap algorithm. The private key
* to be wrapped is provided in the form of a JSON Web Key (JWK).
*
* This operation is useful for securely transmitting keys over untrusted mediums. The method
* returns the wrapped key as a byte array.
*
* @example
* ```ts
* const aesKw = new AesKwAlgorithm();
* const unwrappedKey = { ... }; // A Jwk object representing the key to be wrapped
* const encryptionKey = { ... }; // A Jwk object representing the AES wrapping key
* const wrappedKeyBytes = await aesKw.wrapKey({ unwrappedKey, encryptionKey });
* ```
*
* @param params - The parameters for the key wrapping operation.
*
* @returns A Promise that resolves to the wrapped key as a Uint8Array.
*/
wrapKey(params) {
return __awaiter(this, void 0, void 0, function* () {
const wrappedKeyBytes = AesKw.wrapKey(params);
return wrappedKeyBytes;
});
}
}
//# sourceMappingURL=aes-kw.js.map
@@ -0,0 +1 @@
{"version":3,"file":"aes-kw.js","sourceRoot":"","sources":["../../../../../src/prototyping/crypto/algorithms/aes-kw.ts"],"names":[],"mappings":";;;;;;;;;AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAI/C,OAAO,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAC;AAiBhD;;;;;;;;GAQG;AACH,MAAM,OAAO,cAAe,SAAQ,eAAe;IAKpC,iBAAiB,CAAC,EAAE,eAAe,EACS;;YAEvD,mCAAmC;YACnC,MAAM,UAAU,GAAG,MAAM,KAAK,CAAC,iBAAiB,CAAC,EAAE,eAAe,EAAE,CAAC,CAAC;YAEtE,kDAAkD;YAClD,UAAU,CAAC,GAAG,GAAG,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;YAEtF,OAAO,UAAU,CAAC;QACpB,CAAC;KAAA;IAED;;;;;;;;;;;;;;;;;;;;;;;;;OAyBG;IACU,WAAW,CAAC,EAAE,SAAS,EACZ;;YAEtB,oCAAoC;YACpC,MAAM,MAAM,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,SAAS,CAAoB,CAAC;YAEvF,iCAAiC;YACjC,MAAM,UAAU,GAAG,MAAM,KAAK,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;YAEvD,2DAA2D;YAC3D,UAAU,CAAC,GAAG,GAAG,SAAS,CAAC;YAE3B,OAAO,UAAU,CAAC;QACpB,CAAC;KAAA;IAEY,iBAAiB,CAAC,EAAE,UAAU,EAClB;;YAEvB,mCAAmC;YACnC,MAAM,eAAe,GAAG,MAAM,KAAK,CAAC,iBAAiB,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC;YAEtE,OAAO,eAAe,CAAC;QACzB,CAAC;KAAA;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;OA0BG;IACU,SAAS,CAAC,MACN;;YAEf,MAAM,YAAY,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;YAEnD,OAAO,YAAY,CAAC;QACtB,CAAC;KAAA;IAED;;;;;;;;;;;;;;;;;;;;;OAqBG;IACU,OAAO,CAAC,MACN;;YAEb,MAAM,eAAe,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;YAE9C,OAAO,eAAe,CAAC;QACzB,CAAC;KAAA;CACF"}
@@ -0,0 +1,307 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { CryptoAlgorithm, isEcPrivateJwk, isEcPublicJwk, Secp256k1, Secp256r1 } from '@web5/crypto';
import { CryptoError, CryptoErrorCode } from '../crypto-error.js';
/**
* The `EcdsaAlgorithm` class provides a concrete implementation for cryptographic operations using
* the Elliptic Curve Digital Signature Algorithm (ECDSA). This class implements both
* {@link Signer | `Signer`} and { @link AsymmetricKeyGenerator | `AsymmetricKeyGenerator`}
* interfaces, providing private key generation, public key derivation, and creation/verification
* of signatures.
*
* This class is typically accessed through implementations that extend the
* {@link CryptoApi | `CryptoApi`} interface.
*/
export class EcdsaAlgorithm extends CryptoAlgorithm {
bytesToPrivateKey({ algorithm, privateKeyBytes }) {
return __awaiter(this, void 0, void 0, function* () {
switch (algorithm) {
case 'ES256K':
case 'secp256k1': {
const privateKey = yield Secp256k1.bytesToPrivateKey({ privateKeyBytes });
privateKey.alg = 'EdDSA';
return privateKey;
}
case 'ES256':
case 'secp256r1': {
const privateKey = yield Secp256r1.bytesToPrivateKey({ privateKeyBytes });
privateKey.alg = 'EdDSA';
return privateKey;
}
default: {
throw new CryptoError(CryptoErrorCode.AlgorithmNotSupported, `Algorithm not supported: ${algorithm}`);
}
}
});
}
bytesToPublicKey({ algorithm, publicKeyBytes }) {
return __awaiter(this, void 0, void 0, function* () {
switch (algorithm) {
case 'ES256K':
case 'secp256k1': {
const publicKey = yield Secp256k1.bytesToPublicKey({ publicKeyBytes });
publicKey.alg = 'EdDSA';
return publicKey;
}
case 'ES256':
case 'secp256r1': {
const publicKey = yield Secp256r1.bytesToPublicKey({ publicKeyBytes });
publicKey.alg = 'EdDSA';
return publicKey;
}
default: {
throw new CryptoError(CryptoErrorCode.AlgorithmNotSupported, `Algorithm not supported: ${algorithm}`);
}
}
});
}
/**
* Derives the public key in JWK format from a given private key.
*
* @remarks
* This method takes a private key in JWK format and derives its corresponding public key,
* also in JWK format. The process ensures that the derived public key correctly corresponds to
* the given private key.
*
* @example
* ```ts
* const ecdsa = new EcdsaAlgorithm();
* const privateKey = { ... }; // A Jwk object representing a private key
* const publicKey = await ecdsa.computePublicKey({ key: privateKey });
* ```
*
* @param params - The parameters for the public key derivation.
* @param params.key - The private key in JWK format from which to derive the public key.
*
* @returns A Promise that resolves to the derived public key in JWK format.
*/
computePublicKey({ key }) {
return __awaiter(this, void 0, void 0, function* () {
if (!isEcPrivateJwk(key))
throw new TypeError('Invalid key provided. Must be an elliptic curve (EC) private key.');
switch (key.crv) {
case 'secp256k1': {
const publicKey = yield Secp256k1.computePublicKey({ key });
publicKey.alg = 'ES256K';
return publicKey;
}
case 'P-256': {
const publicKey = yield Secp256r1.computePublicKey({ key });
publicKey.alg = 'ES256';
return publicKey;
}
default: {
throw new Error(`Unsupported curve: ${key.crv}`);
}
}
});
}
/**
* Generates a new private key with the specified algorithm in JSON Web Key (JWK) format.
*
* @example
* ```ts
* const ecdsa = new EcdsaAlgorithm();
* const privateKey = await ecdsa.generateKey({ algorithm: 'ES256K' });
* ```
*
* @param params - The parameters for key generation.
* @param params.algorithm - The algorithm to use for key generation.
*
* @returns A Promise that resolves to the generated private key in JWK format.
*/
generateKey({ algorithm }) {
return __awaiter(this, void 0, void 0, function* () {
switch (algorithm) {
case 'ES256K':
case 'secp256k1': {
const privateKey = yield Secp256k1.generateKey();
privateKey.alg = 'ES256K';
return privateKey;
}
case 'ES256':
case 'secp256r1': {
const privateKey = yield Secp256r1.generateKey();
privateKey.alg = 'ES256';
return privateKey;
}
}
});
}
/**
* Retrieves the public key properties from a given private key in JWK format.
*
* @remarks
* This method extracts the public key portion from an ECDSA private key in JWK format. It does
* so by removing the private key property 'd' and making a shallow copy, effectively yielding the
* public key.
*
* Note: This method offers a significant performance advantage, being about 200 times faster
* than `computePublicKey()`. However, it does not mathematically validate the private key, nor
* does it derive the public key from the private key. It simply extracts existing public key
* properties from the private key object. This makes it suitable for scenarios where speed is
* critical and the private key's integrity is already assured.
*
* @example
* ```ts
* const ecdsa = new EcdsaAlgorithm();
* const privateKey = { ... }; // A Jwk object representing a private key
* const publicKey = await ecdsa.getPublicKey({ key: privateKey });
* ```
*
* @param params - The parameters for retrieving the public key properties.
* @param params.key - The private key in JWK format.
*
* @returns A Promise that resolves to the public key in JWK format.
*/
getPublicKey({ key }) {
return __awaiter(this, void 0, void 0, function* () {
if (!isEcPrivateJwk(key))
throw new TypeError('Invalid key provided. Must be an elliptic curve (EC) private key.');
switch (key.crv) {
case 'secp256k1': {
const publicKey = yield Secp256k1.getPublicKey({ key });
publicKey.alg = 'ES256K';
return publicKey;
}
case 'P-256': {
const publicKey = yield Secp256r1.getPublicKey({ key });
publicKey.alg = 'ES256';
return publicKey;
}
default: {
throw new Error(`Unsupported curve: ${key.crv}`);
}
}
});
}
privateKeyToBytes({ privateKey }) {
return __awaiter(this, void 0, void 0, function* () {
switch (privateKey.crv) {
case 'secp256k1': {
return yield Secp256k1.privateKeyToBytes({ privateKey });
}
case 'P-256': {
return yield Secp256r1.privateKeyToBytes({ privateKey });
}
default: {
throw new CryptoError(CryptoErrorCode.AlgorithmNotSupported, `Curve not supported: ${privateKey.crv}`);
}
}
});
}
publicKeyToBytes({ publicKey }) {
return __awaiter(this, void 0, void 0, function* () {
switch (publicKey.crv) {
case 'secp256k1': {
return yield Secp256k1.publicKeyToBytes({ publicKey });
}
case 'P-256': {
return yield Secp256r1.publicKeyToBytes({ publicKey });
}
default: {
throw new CryptoError(CryptoErrorCode.AlgorithmNotSupported, `Curve not supported: ${publicKey.crv}`);
}
}
});
}
/**
* Generates an ECDSA signature of given data using a private key.
*
* @remarks
* This method uses the signature algorithm determined by the given `algorithm` to sign the
* provided data.
*
* The signature can later be verified by parties with access to the corresponding
* public key, ensuring that the data has not been tampered with and was indeed signed by the
* holder of the private key.
*
* @example
* ```ts
* const ecdsa = new EcdsaAlgorithm();
* const data = new TextEncoder().encode('Message');
* const privateKey = { ... }; // A Jwk object representing a private key
* const signature = await ecdsa.sign({
* key: privateKey,
* data
* });
* ```
*
* @param params - The parameters for the signing operation.
* @param params.key - The private key to use for signing, represented in JWK format.
* @param params.data - The data to sign.
*
* @returns A Promise resolving to the digital signature as a `Uint8Array`.
*/
sign({ key, data }) {
return __awaiter(this, void 0, void 0, function* () {
if (!isEcPrivateJwk(key))
throw new TypeError('Invalid key provided. Must be an elliptic curve (EC) private key.');
switch (key.crv) {
case 'secp256k1': {
return yield Secp256k1.sign({ key, data });
}
case 'P-256': {
return yield Secp256r1.sign({ key, data });
}
default: {
throw new Error(`Unsupported curve: ${key.crv}`);
}
}
});
}
/**
* Verifies an ECDSA signature associated with the provided data using the provided key.
*
* @remarks
* This method uses the signature algorithm determined by the `crv` property of the provided key
* to check the validity of a digital signature against the original data. It confirms whether the
* signature was created by the holder of the corresponding private key and that the data has not
* been tampered with.
*s
* @example
* ```ts
* const ecdsa = new EcdsaAlgorithm();
* const publicKey = { ... }; // Public key in JWK format corresponding to the private key that signed the data
* const signature = new Uint8Array([...]); // Signature to verify
* const data = new TextEncoder().encode('Message');
* const isValid = await ecdsa.verify({
* key: publicKey,
* signature,
* data
* });
* ```
*
* @param params - The parameters for the verification operation.
* @param params.key - The key to use for verification.
* @param params.signature - The signature to verify.
* @param params.data - The data to verify.
*
* @returns A Promise resolving to a boolean indicating whether the signature is valid.
*/
verify({ key, signature, data }) {
return __awaiter(this, void 0, void 0, function* () {
if (!isEcPublicJwk(key))
throw new TypeError('Invalid key provided. Must be an elliptic curve (EC) public key.');
switch (key.crv) {
case 'secp256k1': {
return yield Secp256k1.verify({ key, signature, data });
}
case 'P-256': {
return yield Secp256r1.verify({ key, signature, data });
}
default: {
throw new Error(`Unsupported curve: ${key.crv}`);
}
}
});
}
}
//# sourceMappingURL=ecdsa.js.map
@@ -0,0 +1 @@
{"version":3,"file":"ecdsa.js","sourceRoot":"","sources":["../../../../../src/prototyping/crypto/algorithms/ecdsa.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,264 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { CryptoAlgorithm, Ed25519, isOkpPrivateJwk, isOkpPublicJwk } from '@web5/crypto';
import { CryptoError, CryptoErrorCode } from '../crypto-error.js';
/**
* The `EdDsaAlgorithm` class provides a concrete implementation for cryptographic operations using
* the Edwards-curve Digital Signature Algorithm (EdDSA). This class implements both
* {@link Signer | `Signer`} and { @link AsymmetricKeyGenerator | `AsymmetricKeyGenerator`}
* interfaces, providing private key generation, public key derivation, and creation/verification
* of signatures.
*
* This class is typically accessed through implementations that extend the
* {@link CryptoApi | `CryptoApi`} interface.
*/
export class EdDsaAlgorithm extends CryptoAlgorithm {
bytesToPrivateKey({ algorithm, privateKeyBytes }) {
return __awaiter(this, void 0, void 0, function* () {
switch (algorithm) {
case 'Ed25519': {
const privateKey = yield Ed25519.bytesToPrivateKey({ privateKeyBytes });
privateKey.alg = 'EdDSA';
return privateKey;
}
default: {
throw new CryptoError(CryptoErrorCode.AlgorithmNotSupported, `Algorithm not supported: ${algorithm}`);
}
}
});
}
bytesToPublicKey({ algorithm, publicKeyBytes }) {
return __awaiter(this, void 0, void 0, function* () {
switch (algorithm) {
case 'Ed25519': {
const publicKey = yield Ed25519.bytesToPublicKey({ publicKeyBytes });
publicKey.alg = 'EdDSA';
return publicKey;
}
default: {
throw new CryptoError(CryptoErrorCode.AlgorithmNotSupported, `Algorithm not supported: ${algorithm}`);
}
}
});
}
/**
* Derives the public key in JWK format from a given private key.
*
* @remarks
* This method takes a private key in JWK format and derives its corresponding public key,
* also in JWK format. The process ensures that the derived public key correctly corresponds to
* the given private key.
*
* @example
* ```ts
* const eddsa = new EdDsaAlgorithm();
* const privateKey = { ... }; // A Jwk object representing a private key
* const publicKey = await eddsa.computePublicKey({ key: privateKey });
* ```
*
* @param params - The parameters for the public key derivation.
* @param params.key - The private key in JWK format from which to derive the public key.
*
* @returns A Promise that resolves to the derived public key in JWK format.
*/
computePublicKey({ key }) {
return __awaiter(this, void 0, void 0, function* () {
if (!isOkpPrivateJwk(key))
throw new TypeError('Invalid key provided. Must be an octet key pair (OKP) private key.');
switch (key.crv) {
case 'Ed25519': {
const publicKey = yield Ed25519.computePublicKey({ key });
publicKey.alg = 'EdDSA';
return publicKey;
}
default: {
throw new CryptoError(CryptoErrorCode.AlgorithmNotSupported, `Curve not supported: ${key.crv}`);
}
}
});
}
/**
* Generates a new private key with the specified algorithm in JSON Web Key (JWK) format.
*
* @example
* ```ts
* const eddsa = new EdDsaAlgorithm();
* const privateKey = await eddsa.generateKey({ algorithm: 'Ed25519' });
* ```
*
* @param params - The parameters for key generation.
* @param params.algorithm - The algorithm to use for key generation.
*
* @returns A Promise that resolves to the generated private key in JWK format.
*/
generateKey({ algorithm }) {
return __awaiter(this, void 0, void 0, function* () {
switch (algorithm) {
case 'Ed25519': {
const privateKey = yield Ed25519.generateKey();
privateKey.alg = 'EdDSA';
return privateKey;
}
}
});
}
/**
* Retrieves the public key properties from a given private key in JWK format.
*
* @remarks
* This method extracts the public key portion from an EdDSA private key in JWK format. It does
* so by removing the private key property 'd' and making a shallow copy, effectively yielding the
* public key.
*
* Note: This method offers a significant performance advantage, being about 100 times faster
* than `computePublicKey()`. However, it does not mathematically validate the private key, nor
* does it derive the public key from the private key. It simply extracts existing public key
* properties from the private key object. This makes it suitable for scenarios where speed is
* critical and the private key's integrity is already assured.
*
* @example
* ```ts
* const eddsa = new EdDsaAlgorithm();
* const privateKey = { ... }; // A Jwk object representing a private key
* const publicKey = await eddsa.getPublicKey({ key: privateKey });
* ```
*
* @param params - The parameters for retrieving the public key properties.
* @param params.key - The private key in JWK format.
*
* @returns A Promise that resolves to the public key in JWK format.
*/
getPublicKey({ key }) {
return __awaiter(this, void 0, void 0, function* () {
if (!isOkpPrivateJwk(key))
throw new TypeError('Invalid key provided. Must be an octet key pair (OKP) private key.');
switch (key.crv) {
case 'Ed25519': {
const publicKey = yield Ed25519.getPublicKey({ key });
publicKey.alg = 'EdDSA';
return publicKey;
}
default: {
throw new Error(`Unsupported curve: ${key.crv}`);
}
}
});
}
privateKeyToBytes({ privateKey }) {
return __awaiter(this, void 0, void 0, function* () {
switch (privateKey.crv) {
case 'Ed25519': {
return yield Ed25519.privateKeyToBytes({ privateKey });
}
default: {
throw new CryptoError(CryptoErrorCode.AlgorithmNotSupported, `Curve not supported: ${privateKey.crv}`);
}
}
});
}
publicKeyToBytes({ publicKey }) {
return __awaiter(this, void 0, void 0, function* () {
switch (publicKey.crv) {
case 'Ed25519': {
return yield Ed25519.publicKeyToBytes({ publicKey });
}
default: {
throw new CryptoError(CryptoErrorCode.AlgorithmNotSupported, `Curve not supported: ${publicKey.crv}`);
}
}
});
}
/**
* Generates an EdDSA signature of given data using a private key.
*
* @remarks
* This method uses the signature algorithm determined by the given `algorithm` to sign the
* provided data.
*
* The signature can later be verified by parties with access to the corresponding
* public key, ensuring that the data has not been tampered with and was indeed signed by the
* holder of the private key.
*
* @example
* ```ts
* const eddsa = new EdDsaAlgorithm();
* const data = new TextEncoder().encode('Message');
* const privateKey = { ... }; // A Jwk object representing a private key
* const signature = await eddsa.sign({
* key: privateKey,
* data
* });
* ```
*
* @param params - The parameters for the signing operation.
* @param params.key - The private key to use for signing, represented in JWK format.
* @param params.data - The data to sign.
*
* @returns A Promise resolving to the digital signature as a `Uint8Array`.
*/
sign({ key, data }) {
return __awaiter(this, void 0, void 0, function* () {
if (!isOkpPrivateJwk(key))
throw new TypeError('Invalid key provided. Must be an octet key pair (OKP) private key.');
switch (key.crv) {
case 'Ed25519': {
return yield Ed25519.sign({ key, data });
}
default: {
throw new CryptoError(CryptoErrorCode.AlgorithmNotSupported, `Curve not supported: ${key.crv}`);
}
}
});
}
/**
* Verifies an EdDSA signature associated with the provided data using the provided key.
*
* @remarks
* This method uses the signature algorithm determined by the `crv` property of the provided key
* to check the validity of a digital signature against the original data. It confirms whether the
* signature was created by the holder of the corresponding private key and that the data has not
* been tampered with.
*s
* @example
* ```ts
* const eddsa = new EdDsaAlgorithm();
* const publicKey = { ... }; // Public key in JWK format corresponding to the private key that signed the data
* const signature = new Uint8Array([...]); // Signature to verify
* const data = new TextEncoder().encode('Message');
* const isValid = await eddsa.verify({
* key: publicKey,
* signature,
* data
* });
* ```
*
* @param params - The parameters for the verification operation.
* @param params.key - The key to use for verification.
* @param params.signature - The signature to verify.
* @param params.data - The data to verify.
*
* @returns A Promise resolving to a boolean indicating whether the signature is valid.
*/
verify({ key, signature, data }) {
return __awaiter(this, void 0, void 0, function* () {
if (!isOkpPublicJwk(key))
throw new TypeError('Invalid key provided. Must be an octet key pair (OKP) public key.');
switch (key.crv) {
case 'Ed25519': {
return yield Ed25519.verify({ key, signature, data });
}
default: {
throw new CryptoError(CryptoErrorCode.AlgorithmNotSupported, `Curve not supported: ${key.crv}`);
}
}
});
}
}
//# sourceMappingURL=eddsa.js.map
@@ -0,0 +1 @@
{"version":3,"file":"eddsa.js","sourceRoot":"","sources":["../../../../../src/prototyping/crypto/algorithms/eddsa.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
import { CryptoAlgorithm } from '@web5/crypto';
import { Hkdf } from '../primitives/hkdf.js';
export class HkdfAlgorithm extends CryptoAlgorithm {
deriveKeyBytes(_a) {
var { algorithm } = _a, params = __rest(_a, ["algorithm"]);
return __awaiter(this, void 0, void 0, function* () {
// Map algorithm name to hash function.
const hash = {
'HKDF-256': 'SHA-256',
'HKDF-384': 'SHA-384',
'HKDF-512': 'SHA-512'
}[algorithm];
// Derive a cryptographic byte array using HKDF.
const derivedKeyBytes = yield Hkdf.deriveKeyBytes(Object.assign(Object.assign({}, params), { hash }));
return derivedKeyBytes;
});
}
}
//# sourceMappingURL=hkdf.js.map
@@ -0,0 +1 @@
{"version":3,"file":"hkdf.js","sourceRoot":"","sources":["../../../../../src/prototyping/crypto/algorithms/hkdf.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAI/C,OAAO,EAAE,IAAI,EAAc,MAAM,uBAAuB,CAAC;AAiBzD,MAAM,OAAO,aAAc,SAAQ,eAAe;IAGnC,cAAc,CAAC,EACyB;YADzB,EAAE,SAAS,OACc,EADT,MAAM,cAAtB,aAAwB,CAAF;;YAGhD,uCAAuC;YACvC,MAAM,IAAI,GAAG;gBACX,UAAU,EAAG,SAAkB;gBAC/B,UAAU,EAAG,SAAkB;gBAC/B,UAAU,EAAG,SAAkB;aAChC,CAAC,SAAS,CAAC,CAAC;YAEb,gDAAgD;YAChD,MAAM,eAAe,GAAG,MAAM,IAAI,CAAC,cAAc,iCAAM,MAAM,KAAE,IAAI,IAAG,CAAC;YAEvE,OAAO,eAAe,CAAC;;KACxB;CACF"}
@@ -0,0 +1,41 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
import { CryptoAlgorithm } from '@web5/crypto';
import { Pbkdf2 } from '../primitives/pbkdf2.js';
export class Pbkdf2Algorithm extends CryptoAlgorithm {
deriveKeyBytes(_a) {
var { algorithm } = _a, params = __rest(_a, ["algorithm"]);
return __awaiter(this, void 0, void 0, function* () {
// Extract the hash function component of the `algorithm` parameter.
const [, hashFunction] = algorithm.split(/[-+]/);
// Map from JOSE algorithm name to "SHA" hash function identifier.
const hash = {
'HS256': 'SHA-256',
'HS384': 'SHA-384',
'HS512': 'SHA-512'
}[hashFunction];
// Derive a cryptographic byte array using PBKDF2.
const derivedKeyBytes = yield Pbkdf2.deriveKeyBytes(Object.assign(Object.assign({}, params), { hash }));
return derivedKeyBytes;
});
}
}
//# sourceMappingURL=pbkdf2.js.map
@@ -0,0 +1 @@
{"version":3,"file":"pbkdf2.js","sourceRoot":"","sources":["../../../../../src/prototyping/crypto/algorithms/pbkdf2.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAM/C,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAgBjD,MAAM,OAAO,eAAgB,SAAQ,eAAe;IAGrC,cAAc,CAAC,EAC6B;YAD7B,EAAE,SAAS,OACkB,EADb,MAAM,cAAtB,aAAwB,CAAF;;YAGhD,oEAAoE;YACpE,MAAM,CAAC,EAAE,YAAY,CAAC,GAAG,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YAEjD,kEAAkE;YAClE,MAAM,IAAI,GAAG;gBACX,OAAO,EAAG,SAAkB;gBAC5B,OAAO,EAAG,SAAkB;gBAC5B,OAAO,EAAG,SAAkB;aAC7B,CAAC,YAAY,CAAE,CAAC;YAEjB,kDAAkD;YAClD,MAAM,eAAe,GAAG,MAAM,MAAM,CAAC,cAAc,iCAAM,MAAM,KAAE,IAAI,IAAG,CAAC;YAEzE,OAAO,eAAe,CAAC;;KACxB;CACF"}
@@ -0,0 +1,41 @@
/**
* A custom error class for Crypto-related errors.
*/
export class CryptoError extends Error {
/**
* Constructs an instance of CryptoError, a custom error class for handling Crypto-related errors.
*
* @param code - A {@link CryptoErrorCode} representing the specific type of error encountered.
* @param message - A human-readable description of the error.
*/
constructor(code, message) {
super(message);
this.code = code;
this.name = 'CryptoError';
// Ensures that instanceof works properly, the correct prototype chain when using inheritance,
// and that V8 stack traces (like Chrome, Edge, and Node.js) are more readable and relevant.
Object.setPrototypeOf(this, new.target.prototype);
// Captures the stack trace in V8 engines (like Chrome, Edge, and Node.js).
// In non-V8 environments, the stack trace will still be captured.
if (Error.captureStackTrace) {
Error.captureStackTrace(this, CryptoError);
}
}
}
/**
* An enumeration of possible Crypto error codes.
*/
export var CryptoErrorCode;
(function (CryptoErrorCode) {
/** The supplied algorithm identifier is not supported by the implementation. */
CryptoErrorCode["AlgorithmNotSupported"] = "algorithmNotSupported";
/** The encoding operation (either encoding or decoding) failed. */
CryptoErrorCode["EncodingError"] = "encodingError";
/** The JWE supplied does not conform to valid syntax. */
CryptoErrorCode["InvalidJwe"] = "invalidJwe";
/** The JWK supplied does not conform to valid syntax. */
CryptoErrorCode["InvalidJwk"] = "invalidJwk";
/** The requested operation is not supported by the implementation. */
CryptoErrorCode["OperationNotSupported"] = "operationNotSupported";
})(CryptoErrorCode || (CryptoErrorCode = {}));
//# sourceMappingURL=crypto-error.js.map
@@ -0,0 +1 @@
{"version":3,"file":"crypto-error.js","sourceRoot":"","sources":["../../../../src/prototyping/crypto/crypto-error.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,OAAO,WAAY,SAAQ,KAAK;IACpC;;;;;OAKG;IACH,YAAmB,IAAqB,EAAE,OAAe;QACvD,KAAK,CAAC,OAAO,CAAC,CAAC;QADE,SAAI,GAAJ,IAAI,CAAiB;QAEtC,IAAI,CAAC,IAAI,GAAG,aAAa,CAAC;QAE1B,8FAA8F;QAC9F,4FAA4F;QAC5F,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAElD,2EAA2E;QAC3E,kEAAkE;QAClE,IAAI,KAAK,CAAC,iBAAiB,EAAE;YAC3B,KAAK,CAAC,iBAAiB,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;SAC5C;IACH,CAAC;CACF;AAED;;GAEG;AACH,MAAM,CAAN,IAAY,eAeX;AAfD,WAAY,eAAe;IACzB,gFAAgF;IAChF,kEAA+C,CAAA;IAE/C,mEAAmE;IACnE,kDAA+B,CAAA;IAE/B,yDAAyD;IACzD,4CAAyB,CAAA;IAEzB,yDAAyD;IACzD,4CAAyB,CAAA;IAEzB,sEAAsE;IACtE,kEAA+C,CAAA;AACjD,CAAC,EAfW,eAAe,KAAf,eAAe,QAe1B"}
@@ -0,0 +1,236 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { Sha2Algorithm, computeJwkThumbprint } from '@web5/crypto';
import { EcdsaAlgorithm } from './algorithms/ecdsa.js';
import { EdDsaAlgorithm } from './algorithms/eddsa.js';
import { CryptoError, CryptoErrorCode } from './crypto-error.js';
/**
* `supportedAlgorithms` is an object mapping algorithm names to their respective implementations
* Each entry in this map specifies the algorithm name and its associated properties, including the
* implementation class and any relevant names or identifiers for the algorithm. This structure
* allows for easy retrieval and instantiation of algorithm implementations based on the algorithm
* name or key specification. It facilitates the support of multiple algorithms within the
* `LocalKeyManager` class.
*/
const supportedAlgorithms = {
'Ed25519': {
implementation: EdDsaAlgorithm,
names: ['Ed25519'],
operations: ['bytesToPrivateKey', 'bytesToPublicKey', 'generateKey', 'sign', 'verify'],
},
'secp256k1': {
implementation: EcdsaAlgorithm,
names: ['ES256K', 'secp256k1'],
operations: ['bytesToPrivateKey', 'bytesToPublicKey', 'generateKey', 'sign', 'verify'],
},
'secp256r1': {
implementation: EcdsaAlgorithm,
names: ['ES256', 'secp256r1'],
operations: ['bytesToPrivateKey', 'bytesToPublicKey', 'generateKey', 'sign', 'verify'],
},
'SHA-256': {
implementation: Sha2Algorithm,
names: ['SHA-256'],
operations: ['digest'],
}
};
export class Dsa {
constructor() {
/**
* A private map that stores instances of cryptographic algorithm implementations. Each key in
* this map is an `AlgorithmConstructor`, and its corresponding value is an instance of a class
* that implements a specific cryptographic algorithm. This map is used to cache and reuse
* instances for performance optimization, ensuring that each algorithm is instantiated only once.
*/
this._algorithmInstances = new Map();
}
bytesToPrivateKey({ algorithm: algorithmIdentifier, privateKeyBytes }) {
return __awaiter(this, void 0, void 0, function* () {
// Determine the algorithm name based on the given algorithm identifier.
const algorithm = this.getAlgorithmName({ algorithm: algorithmIdentifier });
// Get the key converter based on the algorithm name.
const keyConverter = this.getAlgorithm({ algorithm });
// Convert the byte array to a JWK.
const privateKey = yield keyConverter.bytesToPrivateKey({ algorithm: algorithmIdentifier, privateKeyBytes });
return privateKey;
});
}
bytesToPublicKey({ algorithm: algorithmIdentifier, publicKeyBytes }) {
return __awaiter(this, void 0, void 0, function* () {
// Determine the algorithm name based on the given algorithm identifier.
const algorithm = this.getAlgorithmName({ algorithm: algorithmIdentifier });
// Get the key converter based on the algorithm name.
const keyConverter = this.getAlgorithm({ algorithm });
// Convert the byte array to a JWK.
const publicKey = yield keyConverter.bytesToPublicKey({ algorithm: algorithmIdentifier, publicKeyBytes });
return publicKey;
});
}
/**
* Generates a hash digest of the provided data.
*
* @remarks
* A digest is the output of the hash function. It's a fixed-size string of bytes that uniquely
* represents the data input into the hash function. The digest is often used for data integrity
* checks, as any alteration in the input data results in a significantly different digest.
*
* It takes the algorithm identifier of the hash function and data to digest as input and returns
* the digest of the data.
*
* @example
* ```ts
* const Dsa = new AgentDsa();
* const data = new Uint8Array([...]);
* const digest = await Dsa.digest({ algorithm: 'SHA-256', data });
* ```
*
* @param params - The parameters for the digest operation.
* @param params.algorithm - The name of hash function to use.
* @param params.data - The data to digest.
*
* @returns A Promise which will be fulfilled with the hash digest.
*/
digest({ algorithm, data }) {
return __awaiter(this, void 0, void 0, function* () {
// Get the hash function implementation based on the specified `algorithm` parameter.
const hasher = this.getAlgorithm({ algorithm });
// Compute the hash.
const hash = yield hasher.digest({ algorithm, data });
return hash;
});
}
generateKey(params) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
// Determine the algorithm name based on the given algorithm identifier.
const algorithm = this.getAlgorithmName({ algorithm: params.algorithm });
// Get the key generator implementation based on the algorithm.
const keyGenerator = this.getAlgorithm({ algorithm });
// Generate the key.
const privateKey = yield keyGenerator.generateKey({ algorithm: params.algorithm });
// If the key ID is undefined, set it to the JWK thumbprint.
(_a = privateKey.kid) !== null && _a !== void 0 ? _a : (privateKey.kid = yield computeJwkThumbprint({ jwk: privateKey }));
return privateKey;
});
}
// ! TODO: Remove this once the `Dsa` interface is updated in @web5/crypto to remove KMS-specific methods.
getKeyUri(_params) {
return __awaiter(this, void 0, void 0, function* () {
throw new Error('Method not implemented.');
});
}
getPublicKey({ key }) {
return __awaiter(this, void 0, void 0, function* () {
// Determine the algorithm name based on the JWK's `alg` and `crv` properties.
const algorithm = this.getAlgorithmName({ key });
// Get the key generator based on the algorithm name.
const keyGenerator = this.getAlgorithm({ algorithm });
// Get the public key properties from the private JWK.
const publicKey = yield keyGenerator.getPublicKey({ key });
return publicKey;
});
}
privateKeyToBytes({ privateKey }) {
return __awaiter(this, void 0, void 0, function* () {
// Determine the algorithm name based on the JWK's `alg` property.
const algorithm = this.getAlgorithmName({ key: privateKey });
// Get the key converter based on the algorithm name.
const keyConverter = this.getAlgorithm({ algorithm });
// Convert the JWK to a byte array.
const privateKeyBytes = yield keyConverter.privateKeyToBytes({ privateKey });
return privateKeyBytes;
});
}
publicKeyToBytes({ publicKey }) {
return __awaiter(this, void 0, void 0, function* () {
// Determine the algorithm name based on the JWK's `alg` property.
const algorithm = this.getAlgorithmName({ key: publicKey });
// Get the key converter based on the algorithm name.
const keyConverter = this.getAlgorithm({ algorithm });
// Convert the JWK to a byte array.
const publicKeyBytes = yield keyConverter.publicKeyToBytes({ publicKey });
return publicKeyBytes;
});
}
sign({ key, data }) {
return __awaiter(this, void 0, void 0, function* () {
// Determine the algorithm name based on the JWK's `alg` and `crv` properties.
const algorithm = this.getAlgorithmName({ key });
// Get the signature algorithm based on the algorithm name.
const signer = this.getAlgorithm({ algorithm });
// Sign the data.
const signature = signer.sign({ data, key });
return signature;
});
}
verify({ key, signature, data }) {
return __awaiter(this, void 0, void 0, function* () {
// Determine the algorithm name based on the JWK's `alg` and `crv` properties.
const algorithm = this.getAlgorithmName({ key });
// Get the signature algorithm based on the algorithm name.
const signer = this.getAlgorithm({ algorithm });
// Verify the signature.
const isSignatureValid = signer.verify({ key, signature, data });
return isSignatureValid;
});
}
/**
* Retrieves an algorithm implementation instance based on the provided algorithm name.
*
* @remarks
* This method checks if the requested algorithm is supported and returns a cached instance
* if available. If an instance does not exist, it creates and caches a new one. This approach
* optimizes performance by reusing algorithm instances across cryptographic operations.
*
* @example
* ```ts
* const signer = this.getAlgorithm({ algorithm: 'Ed25519' });
* ```
*
* @param params - The parameters for retrieving the algorithm implementation.
* @param params.algorithm - The name of the algorithm to retrieve.
*
* @returns An instance of the requested algorithm implementation.
*
* @throws Error if the requested algorithm is not supported.
*/
getAlgorithm({ algorithm }) {
var _a;
// Check if algorithm is supported.
const AlgorithmImplementation = (_a = supportedAlgorithms[algorithm]) === null || _a === void 0 ? void 0 : _a['implementation'];
if (!AlgorithmImplementation) {
throw new CryptoError(CryptoErrorCode.AlgorithmNotSupported, `Algorithm not supported: ${algorithm}`);
}
// Check if instance already exists for the `AlgorithmImplementation`.
if (!this._algorithmInstances.has(AlgorithmImplementation)) {
// If not, create a new instance and store it in the cache
this._algorithmInstances.set(AlgorithmImplementation, new AlgorithmImplementation());
}
// Return the cached instance
return this._algorithmInstances.get(AlgorithmImplementation);
}
getAlgorithmName({ algorithm, key }) {
var _a;
const algProperty = (_a = key === null || key === void 0 ? void 0 : key.alg) !== null && _a !== void 0 ? _a : algorithm;
const crvProperty = key === null || key === void 0 ? void 0 : key.crv;
for (const algorithmIdentifier of Object.keys(supportedAlgorithms)) {
const algorithmNames = supportedAlgorithms[algorithmIdentifier].names;
if (algProperty && algorithmNames.includes(algProperty)) {
return algorithmIdentifier;
}
else if (crvProperty && algorithmNames.includes(crvProperty)) {
return algorithmIdentifier;
}
}
throw new CryptoError(CryptoErrorCode.AlgorithmNotSupported, `Algorithm not supported based on provided input: alg=${algProperty}, crv=${crvProperty}. ` +
'Please check the documentation for the list of supported algorithms.');
}
}
//# sourceMappingURL=dsa.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,130 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { LocalKeyManager } from '@web5/crypto';
import { isValidJweHeader } from './jwe.js';
import { FlattenedJwe } from './jwe-flattened.js';
import { AgentCryptoApi } from '../../../crypto-api.js';
import { CryptoError, CryptoErrorCode } from '../crypto-error.js';
/**
* The `CompactJwe` class facilitates encryption and decryption processes using the JSON Web
* Encryption (JWE) Compact Serialization format. This class adheres to the specifications
* outlined in {@link https://datatracker.ietf.org/doc/html/rfc7516 | RFC 7516}, enabling secure
* data encapsulation through various cryptographic algorithms.
*
* Compact Serialization is a space-efficient representation of JWE, suitable for contexts
* where verbose data structures are impractical, such as HTTP headers. It provides mechanisms to
* encrypt content and protect its integrity with authenticated encryption, ensuring
* confidentiality, authenticity, and non-repudiation.
*
* This class supports the following operations:
* - Decrypting data from a compact serialized JWE string.
* - Encrypting data and producing a compact serialized JWE string.
*
* Usage involves specifying the cryptographic details, such as keys and algorithms, and the class
* handles the complexities of the JWE processing, including parsing, validating, and applying the
* cryptographic operations defined in the JWE specification.
*
* @example
* ```ts
* // Example usage of encrypt method
* const plaintext = new TextEncoder().encode("Secret Message");
* const key = { kty: "oct", k: "your-secret-key" }; // Example symmetric key
* const protectedHeader = { alg: "dir", enc: "A256GCM" };
* const encryptedJweString = await CompactJwe.encrypt({
* plaintext,
* protectedHeader,
* key,
* });
* console.log(encryptedJweString); // Outputs the JWE string in Compact Serialization format
* ```
*
* @example
* ```ts
* // Example usage of decrypt method
* const jweString = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."; // A JWE in Compact Serialization
* const decryptionKey = { kty: "oct", k: "your-secret-key" }; // The key must match the one used for encryption
* const { plaintext, protectedHeader } = await CompactJwe.decrypt({
* jwe: jweString,
* key: decryptionKey,
* });
* console.log(new TextDecoder().decode(plaintext)); // Outputs the decrypted message
* ```
*/
export class CompactJwe {
/**
* Decrypts a JWE string in Compact Serialization format, extracting the plaintext and
* reconstructing the JWE Protected Header.
*
* This method parses the compact JWE, validates its structure, and applies the appropriate
* decryption algorithm as specified in the JWE Protected Header. It returns the decrypted
* plaintext along with the reconstructed protected header, ensuring the data's authenticity
* and integrity.
*
* @param params - The decryption parameters including the JWE string, cryptographic key, and
* optional instances of Key Manager and Crypto API.
* @returns A promise resolving to the decrypted content and the JWE Protected Header.
* @throws {@link CryptoError} if the JWE format is invalid or decryption fails.
*/
static decrypt({ jwe, key, keyManager = new LocalKeyManager(), crypto = new AgentCryptoApi(), options = {} }) {
return __awaiter(this, void 0, void 0, function* () {
if (typeof jwe !== 'string') {
throw new CryptoError(CryptoErrorCode.InvalidJwe, 'Invalid JWE format. JWE must be a string.');
}
// Split the JWE into its constituent parts.
const { 0: protectedHeader, 1: encryptedKey, 2: initializationVector, 3: ciphertext, 4: authenticationTag, length, } = jwe.split('.');
// Ensure that the JWE has the required number of parts.
if (length !== 5) {
throw new CryptoError(CryptoErrorCode.InvalidJwe, 'Invalid JWE format. JWE must have 5 parts.');
}
// Decrypt the JWE using the provided Key URI.
const flattenedJwe = yield FlattenedJwe.decrypt({
jwe: {
ciphertext,
encrypted_key: encryptedKey || undefined,
iv: initializationVector || undefined,
protected: protectedHeader,
tag: authenticationTag || undefined,
},
key,
keyManager,
crypto,
options
});
if (!isValidJweHeader(flattenedJwe.protectedHeader)) {
throw new CryptoError(CryptoErrorCode.InvalidJwe, 'Decrypt operation failed due to missing or malformed JWE Protected Header');
}
return { plaintext: flattenedJwe.plaintext, protectedHeader: flattenedJwe.protectedHeader };
});
}
/**
* Encrypts plaintext to a JWE string in Compact Serialization format, encapsulating the content
* with the specified cryptographic protections.
*
* It constructs the JWE by encrypting the plaintext, then serializing the output to the
* compact format, which includes concatenating various components like the protected header,
* encrypted key, initialization vector, ciphertext, and authentication tag.
*
* @param params - The encryption parameters, including plaintext, JWE Protected Header,
* cryptographic key, and optional Key Manager and Crypto API instances.
* @returns A promise that resolves to a string representing the JWE in Compact Serialization
* format.
* @throws {@link CryptoError} if encryption fails or the input parameters are invalid.
*/
static encrypt({ plaintext, protectedHeader, key, keyManager = new LocalKeyManager(), crypto = new AgentCryptoApi(), options = {} }) {
return __awaiter(this, void 0, void 0, function* () {
const jwe = yield FlattenedJwe.encrypt({ plaintext, protectedHeader, key, keyManager, crypto, options });
// Create the Compact Serialization, which is the string BASE64URL(UTF8(JWE Protected Header))
// || '.' || BASE64URL(JWE Encrypted Key) || '.' || BASE64URL(JWE Initialization Vector)
// || '.' || BASE64URL(JWE Ciphertext) || '.' || BASE64URL(JWE Authentication Tag).
return [jwe.protected, jwe.encrypted_key, jwe.iv, jwe.ciphertext, jwe.tag].join('.');
});
}
}
//# sourceMappingURL=jwe-compact.js.map
@@ -0,0 +1 @@
{"version":3,"file":"jwe-compact.js","sourceRoot":"","sources":["../../../../../src/prototyping/crypto/jose/jwe-compact.ts"],"names":[],"mappings":";;;;;;;;;AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAM/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAoElE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,MAAM,OAAO,UAAU;IACrB;;;;;;;;;;;;;OAaG;IACI,MAAM,CAAO,OAAO,CAGzB,EACA,GAAG,EACH,GAAG,EACH,UAAU,GAAG,IAAI,eAAe,EAAE,EAClC,MAAM,GAAG,IAAI,cAAc,EAAE,EAC7B,OAAO,GAAG,EAAE,EACkC;;YAE9C,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE;gBAC3B,MAAM,IAAI,WAAW,CAAC,eAAe,CAAC,UAAU,EAAE,2CAA2C,CAAC,CAAC;aAChG;YAED,4CAA4C;YAC5C,MAAM,EACJ,CAAC,EAAE,eAAe,EAClB,CAAC,EAAE,YAAY,EACf,CAAC,EAAE,oBAAoB,EACvB,CAAC,EAAE,UAAU,EACb,CAAC,EAAE,iBAAiB,EACpB,MAAM,GACP,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAEnB,wDAAwD;YACxD,IAAI,MAAM,KAAK,CAAC,EAAE;gBAChB,MAAM,IAAI,WAAW,CAAC,eAAe,CAAC,UAAU,EAAE,4CAA4C,CAAC,CAAC;aACjG;YAED,8CAA8C;YAC9C,MAAM,YAAY,GAAG,MAAM,YAAY,CAAC,OAAO,CAAC;gBAC9C,GAAG,EAAE;oBACH,UAAU;oBACV,aAAa,EAAG,YAAY,IAAI,SAAS;oBACzC,EAAE,EAAc,oBAAoB,IAAI,SAAS;oBACjD,SAAS,EAAO,eAAe;oBAC/B,GAAG,EAAa,iBAAiB,IAAI,SAAS;iBAC/C;gBACD,GAAG;gBACH,UAAU;gBACV,MAAM;gBACN,OAAO;aACR,CAAC,CAAC;YAEH,IAAI,CAAC,gBAAgB,CAAC,YAAY,CAAC,eAAe,CAAC,EAAE;gBACnD,MAAM,IAAI,WAAW,CAAC,eAAe,CAAC,UAAU,EAAE,2EAA2E,CAAC,CAAC;aAChI;YAED,OAAO,EAAE,SAAS,EAAE,YAAY,CAAC,SAAS,EAAE,eAAe,EAAE,YAAY,CAAC,eAAe,EAAE,CAAC;QAC9F,CAAC;KAAA;IAED;;;;;;;;;;;;;OAaG;IACI,MAAM,CAAO,OAAO,CAGzB,EACA,SAAS,EACT,eAAe,EACf,GAAG,EACH,UAAU,GAAG,IAAI,eAAe,EAAE,EAClC,MAAM,GAAG,IAAI,cAAc,EAAE,EAC7B,OAAO,GAAG,EAAE,EACkC;;YAE9C,MAAM,GAAG,GAAG,MAAM,YAAY,CAAC,OAAO,CAAC,EAAE,SAAS,EAAE,eAAe,EAAE,GAAG,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;YAEzG,8FAA8F;YAC9F,wFAAwF;YACxF,mFAAmF;YACnF,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,GAAG,CAAC,aAAa,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,UAAU,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACvF,CAAC;KAAA;CACF"}
@@ -0,0 +1,294 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { Convert } from '@web5/common';
import { LocalKeyManager, utils as cryptoUtils } from '@web5/crypto';
import { isCipher } from '../utils.js';
import { AgentCryptoApi } from '../../../crypto-api.js';
import { JweKeyManagement, isValidJweHeader } from './jwe.js';
import { hasDuplicateProperties } from '../../common/object.js';
import { CryptoError, CryptoErrorCode } from '../crypto-error.js';
/**
* A helper utility function used internally to decode a JWE header parameter from a Base64 URL
* encoded string to a Uint8Array. It's designed to process individual JWE header parameter values,
* ensuring they are correctly formatted and decoded.
*
* @param param - The name of the JWE header parameter being decoded; used for error messaging.
* @param value - The Base64 URL encoded string value of the header parameter to decode.
* @returns The decoded parameter as a Uint8Array, or undefined if the input value is undefined.
* @throws {@link CryptoError} if the value is not a properly encoded Base64 URL string or if it's
* not a string.
*/
function decodeHeaderParam(param, value) {
// If the parameter value is not present, return undefined.
if (value === undefined)
return undefined;
try {
if (typeof value !== 'string')
throw new Error();
return Convert.base64Url(value).toUint8Array();
}
catch (_a) {
throw new CryptoError(CryptoErrorCode.InvalidJwe, `Failed to decode the JWE Header parameter '${param}' from Base64 URL format to ` +
'Uint8Array. Ensure the value is properly encoded in Base64 URL format without padding.');
}
}
/**
* The `FlattenedJwe` class handles the encryption and decryption of JSON Web Encryption (JWE)
* objects in the flattened serialization format. This format is a compact, URL-safe means of
* representing encrypted content, typically used when dealing with a single recipient or when
* bandwidth efficiency is important.
*
* This class provides methods to encrypt plaintext to a flattened JWE and decrypt a flattened JWE
* back to plaintext, utilizing a variety of supported cryptographic algorithms as specified in the
* JWE header parameters.
*
* @example
* ```ts
* // Example usage of encrypt method
* const plaintext = new TextEncoder().encode("Secret Message");
* const key = { kty: "oct", k: "your-secret-key" }; // Example symmetric key
* const protectedHeader = { alg: "dir", enc: "A256GCM" };
* const encryptedJwe = await FlattenedJwe.encrypt({
* plaintext,
* protectedHeader,
* key,
* });
* ```
*
* @example
* // Decryption example
* const { plaintext, protectedHeader } = await FlattenedJwe.decrypt({
* jwe: yourFlattenedJweObject,
* key: yourDecryptionKey,
* crypto: new YourCryptoApi(),
* });
*/
export class FlattenedJwe {
constructor(params) {
/** Base64URL encoded ciphertext. */
this.ciphertext = '';
Object.assign(this, params);
}
static decrypt({ jwe, key, keyManager = new LocalKeyManager(), crypto = new AgentCryptoApi(), options = {} }) {
var _a, _b;
return __awaiter(this, void 0, void 0, function* () {
// Verify that the provided Crypto API supports the decrypt operation before proceeding.
if (!isCipher(crypto)) {
throw new CryptoError(CryptoErrorCode.OperationNotSupported, 'Crypto API does not support the "encrypt" operation.');
}
// Verify that the provided Key Manager supports the decrypt operation before proceeding.
if (!isCipher(keyManager)) {
throw new CryptoError(CryptoErrorCode.OperationNotSupported, 'Key Manager does not support the "decrypt" operation.');
}
// Verify that at least one of the JOSE header objects is present.
if (!jwe.protected && !jwe.header && !jwe.unprotected) {
throw new CryptoError(CryptoErrorCode.InvalidJwe, 'JWE is missing the required JOSE header parameters. ' +
'Please provide at least one of the following: "protected", "header", or "unprotected"');
}
// Verify that the JWE Ciphertext is present.
if (typeof jwe.ciphertext !== 'string') {
throw new CryptoError(CryptoErrorCode.InvalidJwe, 'JWE Ciphertext is missing or not a string.');
}
// Parse the JWE Protected Header, if present.
let parsedProtectedHeader;
if (jwe.protected) {
try {
parsedProtectedHeader = Convert.base64Url(jwe.protected).toObject();
}
catch (_c) {
throw new Error('JWE Protected Header is invalid');
}
}
// Per {@link https://www.rfc-editor.org/rfc/rfc7516#section-5.2 | RFC7516 Section 5.2}
// the resulting JOSE Header MUST NOT contain duplicate Header Parameter names. In other words,
// the same Header Parameter name MUST NOT occur in the `header`, `protected`, and
// `unprotected` JSON object values that together comprise the JOSE Header.
if (hasDuplicateProperties(parsedProtectedHeader, jwe.header, jwe.unprotected)) {
throw new Error('Duplicate properties detected. Please ensure that each parameter is defined only once ' +
'across the JWE "header", "protected", and "unprotected" objects.');
}
// The JOSE Header is the union of the members of the JWE Protected Header (`protected`), the
// JWE Shared Unprotected Header (`unprotected`), and the corresponding JWE Per-Recipient
// Unprotected Header (`header`).
const joseHeader = Object.assign(Object.assign(Object.assign({}, parsedProtectedHeader), jwe.header), jwe.unprotected);
if (!isValidJweHeader(joseHeader)) {
throw new Error('JWE Header is missing required "alg" (Algorithm) and/or "enc" (Encryption) Header Parameters');
}
if (Array.isArray(options.allowedAlgValues)
&& !options.allowedAlgValues.includes(joseHeader.alg)) {
throw new Error(`"alg" (Algorithm) Header Parameter value not allowed: ${joseHeader.alg}`);
}
if (Array.isArray(options.allowedEncValues)
&& !options.allowedEncValues.includes(joseHeader.enc)) {
throw new Error(`"enc" (Encryption Algorithm) Header Parameter value not allowed: ${joseHeader.enc}`);
}
let cek;
try {
const encryptedKey = jwe.encrypted_key
? Convert.base64Url(jwe.encrypted_key).toUint8Array()
: undefined;
cek = yield JweKeyManagement.decrypt({ key, encryptedKey, joseHeader, keyManager, crypto });
}
catch (error) {
// If the error is a CryptoError with code "InvalidJwe" or "AlgorithmNotSupported", re-throw.
if (error instanceof CryptoError
&& (error.code === CryptoErrorCode.InvalidJwe || error.code === CryptoErrorCode.AlgorithmNotSupported)) {
throw error;
}
// Otherwise, generate a random CEK and proceed to the next step.
// As noted in
// {@link https://datatracker.ietf.org/doc/html/rfc7516#section-11.5 | RFC 7516 Section 11.5},
// to mitigate the attacks described in
// {@link https://datatracker.ietf.org/doc/html/rfc3218 | RFC 3218}, the recipient MUST NOT
// distinguish between format, padding, and length errors of encrypted keys. It is strongly
// recommended, in the event of receiving an improperly formatted key, that the recipient
// substitute a randomly generated CEK and proceed to the next step, to mitigate timing
// attacks.
cek = typeof key === 'string'
? yield keyManager.generateKey({ algorithm: joseHeader.enc })
: yield crypto.generateKey({ algorithm: joseHeader.enc });
}
// If present, decode the JWE Initialization Vector (IV) and Authentication Tag.
const iv = decodeHeaderParam('iv', jwe.iv);
const tag = decodeHeaderParam('tag', jwe.tag);
// Decode the JWE Ciphertext to a byte array, and if present, append the Authentication Tag.
const ciphertext = tag !== undefined
? new Uint8Array([
...Convert.base64Url(jwe.ciphertext).toUint8Array(),
...(tag !== null && tag !== void 0 ? tag : [])
])
: Convert.base64Url(jwe.ciphertext).toUint8Array();
// If the JWE Additional Authenticated Data (AAD) is present, the Additional Authenticated Data
// input to the Content Encryption Algorithm is
// ASCII(Encoded Protected Header || '.' || BASE64URL(JWE AAD)). If the JWE AAD is absent, the
// Additional Authenticated Data is ASCII(BASE64URL(UTF8(JWE Protected Header))).
const additionalData = jwe.aad !== undefined
? new Uint8Array([
...Convert.string((_a = jwe.protected) !== null && _a !== void 0 ? _a : '').toUint8Array(),
...Convert.string('.').toUint8Array(),
...Convert.string(jwe.aad).toUint8Array()
])
: Convert.string((_b = jwe.protected) !== null && _b !== void 0 ? _b : '').toUint8Array();
// Decrypt the JWE using the Content Encryption Key (CEK) with:
// - Key Manager: If the CEK is a Key Identifier.
// - Crypto API: If the CEK is a JWK.
const plaintext = typeof cek === 'string'
? yield keyManager.decrypt({ keyUri: cek, data: ciphertext, iv, additionalData })
: yield crypto.decrypt({ key: cek, data: ciphertext, iv, additionalData });
return {
plaintext,
protectedHeader: parsedProtectedHeader,
additionalAuthenticatedData: decodeHeaderParam('aad', jwe.aad),
sharedUnprotectedHeader: jwe.unprotected,
unprotectedHeader: jwe.header
};
});
}
static encrypt({ key, plaintext, additionalAuthenticatedData, protectedHeader, sharedUnprotectedHeader, unprotectedHeader, keyManager = new LocalKeyManager(), crypto = new AgentCryptoApi(), }) {
return __awaiter(this, void 0, void 0, function* () {
// Verify that the provided Crypto API supports the decrypt operation before proceeding.
if (!isCipher(crypto)) {
throw new CryptoError(CryptoErrorCode.OperationNotSupported, 'Crypto API does not support the "encrypt" operation.');
}
// Verify that the provided Key Manager supports the decrypt operation before proceeding.
if (!isCipher(keyManager)) {
throw new CryptoError(CryptoErrorCode.OperationNotSupported, 'Key Manager does not support the "decrypt" operation.');
}
// Verify that at least one of the JOSE header objects is present.
if (!protectedHeader && !sharedUnprotectedHeader && !unprotectedHeader) {
throw new CryptoError(CryptoErrorCode.InvalidJwe, 'JWE is missing the required JOSE header parameters. ' +
'Please provide at least one of the following: "protectedHeader", "sharedUnprotectedHeader", or "unprotectedHeader"');
}
// Verify that the Plaintext is present.
if (!(plaintext instanceof Uint8Array)) {
throw new CryptoError(CryptoErrorCode.InvalidJwe, 'Plaintext is missing or not a byte array.');
}
// Per {@link https://www.rfc-editor.org/rfc/rfc7516#section-5.2 | RFC7516 Section 5.2}
// the resulting JOSE Header MUST NOT contain duplicate Header Parameter names. In other words,
// the same Header Parameter name MUST NOT occur in the `header`, `protected`, and
// `unprotected` JSON object values that together comprise the JOSE Header.
if (hasDuplicateProperties(protectedHeader, sharedUnprotectedHeader, unprotectedHeader)) {
throw new Error('Duplicate properties detected. Please ensure that each parameter is defined only once ' +
'across the JWE "protectedHeader", "sharedUnprotectedHeader", and "unprotectedHeader" objects.');
}
// The JOSE Header is the union of the members of the JWE Protected Header (`protectedHeader`),
// the JWE Shared Unprotected Header (`sharedUnprotectedHeader`), and the corresponding JWE
// Per-Recipient Unprotected Header (`unprotectedHeader`).
const joseHeader = Object.assign(Object.assign(Object.assign({}, protectedHeader), sharedUnprotectedHeader), unprotectedHeader);
if (!isValidJweHeader(joseHeader)) {
throw new Error('JWE Header is missing required "alg" (Algorithm) and/or "enc" (Encryption) Header Parameters');
}
const { cek, encryptedKey } = yield JweKeyManagement.encrypt({ key, joseHeader, keyManager, crypto });
// If required for the Content Encryption Algorithm, generate a random JWE Initialization
// Vector (IV) of the correct size; otherwise, let the JWE Initialization Vector be the empty
// octet sequence.
let iv;
switch (joseHeader.enc) {
case 'A128GCM':
case 'A192GCM':
case 'A256GCM':
iv = cryptoUtils.randomBytes(12);
break;
default:
iv = new Uint8Array(0);
}
// Compute the Encoded Protected Header value BASE64URL(UTF8(JWE Protected Header)). If the JWE
// Protected Header is not present, let this value be the empty string.
const encodedProtectedHeader = protectedHeader
? Convert.object(protectedHeader).toBase64Url()
: '';
// If the JWE Additional Authenticated Data (AAD) is present, the Additional Authenticated Data
// input to the Content Encryption Algorithm is
// ASCII(Encoded Protected Header || '.' || BASE64URL(JWE AAD)). If the JWE AAD is absent, the
// Additional Authenticated Data is ASCII(BASE64URL(UTF8(JWE Protected Header))).
let additionalData;
let encodedAad;
if (additionalAuthenticatedData) {
encodedAad = Convert.uint8Array(additionalAuthenticatedData).toBase64Url();
additionalData = Convert.string(encodedProtectedHeader + '.' + encodedAad).toUint8Array();
}
else {
additionalData = Convert.string(encodedProtectedHeader).toUint8Array();
}
// Encrypt the plaintext using the CEK, the JWE Initialization Vector, and the Additional
// Authenticated Data value using the specified content encryption algorithm to create the JWE
// Ciphertext value and the JWE Authentication Tag.
const ciphertextWithTag = typeof cek === 'string'
? yield keyManager.encrypt({ keyUri: cek, data: plaintext, iv, additionalData })
: yield crypto.encrypt({ key: cek, data: plaintext, iv, additionalData });
const ciphertext = ciphertextWithTag.slice(0, -16);
const authenticationTag = ciphertextWithTag.slice(-16);
// Create the Flattened JWE JSON Serialization output, which is based upon the General syntax,
// but flattens it, optimizing it for the single-recipient case. It flattens it by removing the
// "recipients" member and instead placing those members defined for use in the "recipients"
// array (the "header" and "encrypted_key" members) in the top-level JSON object (at the same
// level as the "ciphertext" member).
const jwe = new FlattenedJwe({
ciphertext: Convert.uint8Array(ciphertext).toBase64Url(),
});
if (encryptedKey)
jwe.encrypted_key = Convert.uint8Array(encryptedKey).toBase64Url();
if (protectedHeader)
jwe.protected = encodedProtectedHeader;
if (sharedUnprotectedHeader)
jwe.unprotected = sharedUnprotectedHeader;
if (unprotectedHeader)
jwe.header = unprotectedHeader;
if (iv)
jwe.iv = Convert.uint8Array(iv).toBase64Url();
if (encodedAad)
jwe.aad = encodedAad;
if (authenticationTag)
jwe.tag = Convert.uint8Array(authenticationTag).toBase64Url();
return jwe;
});
}
}
//# sourceMappingURL=jwe-flattened.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,308 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { Convert } from '@web5/common';
import { CryptoError, CryptoErrorCode } from '../crypto-error.js';
/**
* Checks if the provided object is a valid JWE (JSON Web Encryption) header.
*
* This function evaluates whether the given object adheres to the structure expected for
* a JWE header, specifically looking for the presence and proper format of the "alg" (algorithm)
* and "enc" (encryption algorithm) properties, which are essential for defining the JWE's
* cryptographic operations.
*
* @example
* ```ts
* const header = {
* alg: 'dir',
* enc: 'A256GCM'
* };
*
* if (isValidJweHeader(header)) {
* console.log('The object is a valid JWE header.');
* } else {
* console.log('The object is not a valid JWE header.');
* }
* ```
*
* @param obj - The object to be validated as a JWE header.
* @returns Returns `true` if the object is a valid JWE header, otherwise `false`.
*/
export function isValidJweHeader(obj) {
return typeof obj === 'object' && obj !== null
&& 'alg' in obj && obj.alg !== undefined
&& 'enc' in obj && obj.enc !== undefined;
}
/**
* The `JweKeyManagement` class implements the key management aspects of JSON Web Encryption (JWE)
* as specified in {@link https://datatracker.ietf.org/doc/html/rfc7516 | RFC 7516}.
*
* It supports algorithms for encrypting and decrypting keys, thereby enabling the secure
* transmission of information where the payload is encrypted, and the encryption key is also
* encrypted or agreed upon using key agreement techniques.
*
* The choice of algorithm is determined by the "alg" parameter in the JWE
* header, and the class is designed to handle the intricacies associated with each algorithm,
* ensuring the secure handling of the encryption keys.
*
* Supported algorithms include:
* - `"dir"`: Direct Encryption Mode
* - `"PBES2-HS256+A128KW"`, `"PBES2-HS384+A192KW"`, `"PBES2-HS512+A256KW"`: Password-Based
* Encryption Mode with Key Wrapping (PBES2) using HMAC-SHA and AES Key Wrap algorithms for key
* wrapping and encryption.
*
* @example
* // To encrypt a key:
* const keyEncryptionKey = Convert.string(passphrase).toUint8Array()
* const { cek, encryptedKey: encryptedCek } = await JweKeyManagement.encrypt({
* key: keyEncryptionKey,
* joseHeader: {
* alg: 'PBES2-HS512+A256KW',
* enc: 'A256GCM',
* p2c : 210_000,
p2s : Convert.uint8Array(saltInput).toBase64Url()
* },
* crypto: new AgentCryptoApi(),
* });
*
* // To decrypt a key:
* const cek = await JweKeyManagement.decrypt({
* key: keyEncryptionKey,
* encryptedKey: encryptedCek,
* joseHeader: {
* alg: 'PBES2-HS512+A256KW',
* enc: 'A256GCM',
* p2c : 210_000,
p2s : Convert.uint8Array(saltInput).toBase64Url()
* },
* crypto: new AgentCryptoApi(),
* });
*/
export class JweKeyManagement {
/**
* Decrypts the encrypted key (JWE Encrypted Key) using the specified key encryption algorithm
* defined in the JWE Header's "alg" parameter.
*
* This method supports multiple key management algorithms, including Direct Encryption (dir) and
* PBES2 schemes with key wrapping.
*
* The method takes a key, which can be a Key Identifier, JWK, or raw byte array, and the
* encrypted key along with the JWE header. It returns the decrypted Content Encryption Key (CEK)
* which can then be used to decrypt the JWE ciphertext.
*
* @example
* ```ts
* // Decrypting the CEK with the PBES2-HS512+A256KW algorithm
* const cek = await JweKeyManagement.decrypt({
* key: Convert.string(passphrase).toUint8Array(),
* encryptedKey: encryptedCek,
* joseHeader: {
* alg: 'PBES2-HS512+A256KW',
* enc: 'A256GCM',
* p2c: 210_000,
* p2s: Convert.uint8Array(saltInput).toBase64Url(),
* },
* crypto: new AgentCryptoApi()
* });
* ```
*
* @param params - The decryption parameters.
* @throws Throws an error if the key management algorithm is not supported or if required
* parameters are missing or invalid.
*/
static decrypt({ key, encryptedKey, joseHeader, crypto }) {
return __awaiter(this, void 0, void 0, function* () {
// Determine the Key Management Mode employed by the algorithm specified by the "alg"
// (algorithm) Header Parameter.
switch (joseHeader.alg) {
case 'dir': {
// In Direct Encryption mode, a JWE "Encrypted Key" is not provided. Instead, the
// provided key management `key` is directly used as the Content Encryption Key (CEK) to
// decrypt the JWE payload.
// Verify that the JWE Encrypted Key value is empty.
if (encryptedKey !== undefined) {
throw new CryptoError(CryptoErrorCode.InvalidJwe, 'JWE "encrypted_key" is not allowed when using "dir" (Direct Encryption Mode).');
}
// Verify the key management `key` is a Key Identifier or JWK.
if (key instanceof Uint8Array) {
throw new CryptoError(CryptoErrorCode.InvalidJwe, 'Key management "key" must be a Key URI or JWK when using "dir" (Direct Encryption Mode).');
}
// return the key management `key` as the CEK.
return key;
}
case 'PBES2-HS256+A128KW':
case 'PBES2-HS384+A192KW':
case 'PBES2-HS512+A256KW': {
// In Key Encryption mode (PBES2) with key wrapping (A128KW, A192KW, A256KW), the given
// passphrase, salt (p2s), and iteration count (p2c) are used with the PBKDF2 key derivation
// function to derive the Key Encryption Key (KEK). The KEK is then used to decrypt the JWE
// Encrypted Key to obtain the Content Encryption Key (CEK).
if (typeof joseHeader.p2c !== 'number') {
throw new CryptoError(CryptoErrorCode.InvalidJwe, 'JOSE Header "p2c" (PBES2 Count) is missing or not a number.');
}
if (typeof joseHeader.p2s !== 'string') {
throw new CryptoError(CryptoErrorCode.InvalidJwe, 'JOSE Header "p2s" (PBES2 salt) is missing or not a string.');
}
// Throw an error if the key management `key` is not a byte array. For PBES2, the key is
// expected to be a low-entropy passphrase as a byte array.
if (!(key instanceof Uint8Array)) {
throw new CryptoError(CryptoErrorCode.InvalidJwe, 'Key management "key" must be a Uint8Array when using "PBES2" (Key Encryption Mode).');
}
// Verify that the JWE Encrypted Key value is present.
if (encryptedKey === undefined) {
throw new CryptoError(CryptoErrorCode.InvalidJwe, 'JWE "encrypted_key" is required when using "PBES2" (Key Encryption Mode).');
}
// Per {@link https://www.rfc-editor.org/rfc/rfc7518.html#section-4.8.1.1 | RFC 7518, Section 4.8.1.1},
// the salt value used with PBES2 should be of the format (UTF8(Alg) || 0x00 || Salt Input),
// where Alg is the "alg" (algorithm) Header Parameter value. This reduces the potential for
// a precomputed dictionary attack (also known as a rainbow table attack).
let salt;
try {
salt = new Uint8Array([
...Convert.string(joseHeader.alg).toUint8Array(),
0x00,
...Convert.base64Url(joseHeader.p2s).toUint8Array()
]);
}
catch (_a) {
throw new CryptoError(CryptoErrorCode.EncodingError, 'Failed to decode the JOSE Header "p2s" (PBES2 salt) value.');
}
// Derive the Key Encryption Key (KEK) from the given passphrase, salt, and iteration count.
const kek = yield crypto.deriveKey({
algorithm: joseHeader.alg,
baseKeyBytes: key,
iterations: joseHeader.p2c,
salt
});
if (!(kek.alg && ['A128KW', 'A192KW', 'A256KW'].includes(kek.alg))) {
throw new CryptoError(CryptoErrorCode.AlgorithmNotSupported, `Unsupported Key Encryption Algorithm (alg) value: ${kek.alg}`);
}
// Decrypt the Content Encryption Key (CEK) with the derived KEK.
return yield crypto.unwrapKey({
decryptionKey: kek,
wrappedKeyBytes: encryptedKey,
wrappedKeyAlgorithm: joseHeader.enc
});
}
default: {
throw new CryptoError(CryptoErrorCode.AlgorithmNotSupported, `Unsupported "alg" (Algorithm) Header Parameter value: ${joseHeader.alg}`);
}
}
});
}
/**
* Encrypts a Content Encryption Key (CEK) using the key management algorithm specified in the
* JWE Header's "alg" parameter.
*
* This method supports various key management algorithms, including Direct Encryption (dir) and
* PBES2 with key wrapping.
*
* It generates a random CEK for the specified encryption algorithm in the JWE header, which
* can then be used to encrypt the actual payload. For algorithms that require an encrypted key,
* it returns the CEK along with the encrypted key.
*
* @example
* ```ts
* // Encrypting the CEK with the PBES2-HS512+A256KW algorithm
* const { cek, encryptedKey } = await JweKeyManagement.encrypt({
* key: Convert.string(passphrase).toUint8Array(),
* joseHeader: {
* alg: 'PBES2-HS512+A256KW',
* enc: 'A256GCM',
* p2c: 210_000,
* p2s: Convert.uint8Array(saltInput).toBase64Url(),
* },
* crypto: crypto: new AgentCryptoApi()
* });
* ```
*
* @param params - The encryption parameters.
* @returns The encrypted key result containing the CEK and optionally the encrypted CEK
* (JWE Encrypted Key).
* @throws Throws an error if the key management algorithm is not supported or if required
* parameters are missing or invalid.
*/
static encrypt({ key, joseHeader, crypto }) {
return __awaiter(this, void 0, void 0, function* () {
let cek;
let encryptedKey;
// Determine the Key Management Mode employed by the algorithm specified by the "alg"
// (algorithm) Header Parameter.
switch (joseHeader.alg) {
case 'dir': {
// In Direct Encryption mode (dir), a JWE "Encrypted Key" is not provided. Instead, the
// provided key management `key` is directly used as the Content Encryption Key (CEK) to
// decrypt the JWE payload.
// Verify that the JWE Encrypted Key value is empty.
if (encryptedKey !== undefined) {
throw new CryptoError(CryptoErrorCode.InvalidJwe, 'JWE "encrypted_key" is not allowed when using "dir" (Direct Encryption Mode).');
}
// Verify the key management `key` is a Key Identifier or JWK.
if (key instanceof Uint8Array) {
throw new CryptoError(CryptoErrorCode.InvalidJwe, 'Key management "key" must be a Key URI or JWK when using "dir" (Direct Encryption Mode).');
}
// Set the CEK to the key management `key`.
cek = key;
break;
}
case 'PBES2-HS256+A128KW':
case 'PBES2-HS384+A192KW':
case 'PBES2-HS512+A256KW': {
// In Key Encryption mode (PBES2) with key wrapping (A128KW, A192KW, A256KW), a randomly
// generated Content Encryption Key (CEK) is encrypted with a Key Encryption Key (KEK)
// derived from the given passphrase, salt (p2s), and iteration count (p2c) using the
// PBKDF2 key derivation function.
if (typeof joseHeader.p2c !== 'number') {
throw new CryptoError(CryptoErrorCode.InvalidJwe, 'JOSE Header "p2c" (PBES2 Count) is missing or not a number.');
}
if (typeof joseHeader.p2s !== 'string') {
throw new CryptoError(CryptoErrorCode.InvalidJwe, 'JOSE Header "p2s" (PBES2 salt) is missing or not a string.');
}
// Throw an error if the key management `key` is not a byte array.
if (!(key instanceof Uint8Array)) {
throw new CryptoError(CryptoErrorCode.InvalidJwe, 'Key management "key" must be a Uint8Array when using "PBES2" (Key Encryption Mode).');
}
// Generate a random Content Encryption Key (CEK) using the algorithm specified by the "enc"
// (encryption) Header Parameter.
cek = yield crypto.generateKey({ algorithm: joseHeader.enc });
// Per {@link https://www.rfc-editor.org/rfc/rfc7518.html#section-4.8.1.1 | RFC 7518, Section 4.8.1.1},
// the salt value used with PBES2 should be of the format (UTF8(Alg) || 0x00 || Salt Input),
// where Alg is the "alg" (algorithm) Header Parameter value. This reduces the potential for
// a precomputed dictionary attack (also known as a rainbow table attack).
let salt;
try {
salt = new Uint8Array([
...Convert.string(joseHeader.alg).toUint8Array(),
0x00,
...Convert.base64Url(joseHeader.p2s).toUint8Array()
]);
}
catch (_a) {
throw new CryptoError(CryptoErrorCode.EncodingError, 'Failed to decode the JOSE Header "p2s" (PBES2 salt) value.');
}
// Derive a Key Encryption Key (KEK) from the given passphrase, salt, and iteration count.
const kek = yield crypto.deriveKey({
algorithm: joseHeader.alg,
baseKeyBytes: key,
iterations: joseHeader.p2c,
salt
});
// Encrypt the randomly generated CEK with the derived Key Encryption Key (KEK).
encryptedKey = yield crypto.wrapKey({ encryptionKey: kek, unwrappedKey: cek });
break;
}
default: {
throw new CryptoError(CryptoErrorCode.AlgorithmNotSupported, `Unsupported "alg" (Algorithm) Header Parameter value: ${joseHeader.alg}`);
}
}
return { cek, encryptedKey };
});
}
}
//# sourceMappingURL=jwe.js.map
@@ -0,0 +1 @@
{"version":3,"file":"jwe.js","sourceRoot":"","sources":["../../../../../src/prototyping/crypto/jose/jwe.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,352 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
import { Convert } from '@web5/common';
import { getWebcryptoSubtle } from '@noble/ciphers/webcrypto/utils';
import { computeJwkThumbprint, isOctPrivateJwk } from '@web5/crypto';
/**
* Const defining the AES-GCM initialization vector (IV) length in bits.
*
* @remarks
* NIST Special Publication 800-38D, Section 5.2.1.1 states that the IV length:
* > For IVs, it is recommended that implementations restrict support to the length of 96 bits, to
* > promote interoperability, efficiency, and simplicity of design.
*
* This implementation does not support IV lengths that are different from the value defined by
* this constant.
*
* @see {@link https://doi.org/10.6028/NIST.SP.800-38D | NIST SP 800-38D}
*/
const AES_GCM_IV_LENGTH = 96;
/**
* Constant defining the AES key length values in bits.
*
* @remarks
* NIST publication FIPS 197 states:
* > The AES algorithm is capable of using cryptographic keys of 128, 192, and 256 bits to encrypt
* > and decrypt data in blocks of 128 bits.
*
* This implementation does not support key lengths that are different from the three values
* defined by this constant.
*
* @see {@link https://doi.org/10.6028/NIST.FIPS.197-upd1 | NIST FIPS 197}
*/
const AES_KEY_LENGTHS = [128, 192, 256];
/**
* Constant defining the AES-GCM tag length values in bits.
*
* @remarks
* NIST Special Publication 800-38D, Section 5.2.1.2 states that the tag length:
* > may be any one of the following five values: 128, 120, 112, 104, or 96
*
* Although the NIST specification allows for tag lengths of 32 or 64 bits in certain applications,
* the use of shorter tag lengths can be problematic for GCM due to targeted forgery attacks. As a
* precaution, this implementation does not support tag lengths that are different from the five
* values defined by this constant. See Appendix C of the NIST SP 800-38D specification for
* additional guidance and details.
*
* @see {@link https://doi.org/10.6028/NIST.SP.800-38D | NIST SP 800-38D}
*/
export const AES_GCM_TAG_LENGTHS = [96, 104, 112, 120, 128];
/**
* The `AesGcm` class provides a comprehensive set of utilities for cryptographic operations
* using the Advanced Encryption Standard (AES) in Galois/Counter Mode (GCM). This class includes
* methods for key generation, encryption, decryption, and conversions between raw byte arrays
* and JSON Web Key (JWK) formats. It is designed to support AES-GCM, a symmetric key algorithm
* that is widely used for its efficiency, security, and provision of authenticated encryption.
*
* AES-GCM is particularly favored for scenarios that require both confidentiality and integrity
* of data. It integrates the counter mode of encryption with the Galois mode of authentication,
* offering high performance and parallel processing capabilities.
*
* Key Features:
* - Key Generation: Generate AES symmetric keys in JWK format.
* - Key Conversion: Transform keys between raw byte arrays and JWK formats.
* - Encryption: Encrypt data using AES-GCM with the provided symmetric key.
* - Decryption: Decrypt data encrypted with AES-GCM using the corresponding symmetric key.
*
* The methods in this class are asynchronous, returning Promises to accommodate various
* JavaScript environments.
*
* @example
* ```ts
* // Key Generation
* const length = 256; // Length of the key in bits (e.g., 128, 192, 256)
* const privateKey = await AesGcm.generateKey({ length });
*
* // Encryption
* const data = new TextEncoder().encode('Messsage');
* const iv = new Uint8Array(12); // 12-byte initialization vector
* const encryptedData = await AesGcm.encrypt({
* data,
* iv,
* key: privateKey
* });
*
* // Decryption
* const decryptedData = await AesGcm.decrypt({
* data: encryptedData,
* iv,
* key: privateKey
* });
*
* // Key Conversion
* const privateKeyBytes = await AesGcm.privateKeyToBytes({ privateKey });
* ```
*/
export class AesGcm {
/**
* Converts a raw private key in bytes to its corresponding JSON Web Key (JWK) format.
*
* @remarks
* This method accepts a symmetric key represented as a byte array (Uint8Array) and
* converts it into a JWK object for use with AES-GCM (Advanced Encryption Standard -
* Galois/Counter Mode). The conversion process involves encoding the key into
* base64url format and setting the appropriate JWK parameters.
*
* The resulting JWK object includes the following properties:
* - `kty`: Key Type, set to 'oct' for Octet Sequence (representing a symmetric key).
* - `k`: The symmetric key, base64url-encoded.
* - `kid`: Key ID, generated based on the JWK thumbprint.
*
* @example
* ```ts
* const privateKeyBytes = new Uint8Array([...]); // Replace with actual symmetric key bytes
* const privateKey = await AesGcm.bytesToPrivateKey({ privateKeyBytes });
* ```
*
* @param params - The parameters for the symmetric key conversion.
* @param params.privateKeyBytes - The raw symmetric key as a Uint8Array.
*
* @returns A Promise that resolves to the symmetric key in JWK format.
*/
static bytesToPrivateKey({ privateKeyBytes }) {
return __awaiter(this, void 0, void 0, function* () {
// Construct the private key in JWK format.
const privateKey = {
k: Convert.uint8Array(privateKeyBytes).toBase64Url(),
kty: 'oct'
};
// Compute the JWK thumbprint and set as the key ID.
privateKey.kid = yield computeJwkThumbprint({ jwk: privateKey });
// Add algorithm identifier based on key length.
const lengthInBits = privateKeyBytes.length * 8;
privateKey.alg = { 128: 'A128GCM', 192: 'A192GCM', 256: 'A256GCM' }[lengthInBits];
return privateKey;
});
}
/**
* Decrypts the provided data using AES-GCM.
*
* @remarks
* This method performs AES-GCM decryption on the given encrypted data using the specified key.
* It requires an initialization vector (IV), the encrypted data along with the decryption key,
* and optionally, additional authenticated data (AAD). The method returns the decrypted data as a
* Uint8Array. The optional `tagLength` parameter specifies the size in bits of the authentication
* tag used when encrypting the data. If not specified, the default tag length of 128 bits is
* used.
*
* @example
* ```ts
* const encryptedData = new Uint8Array([...]); // Encrypted data
* const iv = new Uint8Array([...]); // Initialization vector used during encryption
* const additionalData = new Uint8Array([...]); // Optional additional authenticated data
* const key = { ... }; // A Jwk object representing the AES key
* const decryptedData = await AesGcm.decrypt({
* data: encryptedData,
* iv,
* additionalData,
* key,
* tagLength: 128 // Optional tag length in bits
* });
* ```
*
* @param params - The parameters for the decryption operation.
* @param params.key - The key to use for decryption, represented in JWK format.
* @param params.data - The encrypted data to decrypt, represented as a Uint8Array.
* @param params.iv - The initialization vector, represented as a Uint8Array.
* @param params.additionalData - Optional additional authenticated data. Optional.
* @param params.tagLength - The length of the authentication tag in bits. Optional.
*
* @returns A Promise that resolves to the decrypted data as a Uint8Array.
*/
static decrypt({ key, data, iv, additionalData, tagLength }) {
return __awaiter(this, void 0, void 0, function* () {
// Validate the initialization vector length.
if (iv.byteLength !== AES_GCM_IV_LENGTH / 8) {
throw new TypeError(`The initialization vector must be ${AES_GCM_IV_LENGTH} bits in length`);
}
// Validate the tag length.
if (tagLength && !AES_GCM_TAG_LENGTHS.includes(tagLength)) {
throw new RangeError(`The tag length is invalid: Must be ${AES_GCM_TAG_LENGTHS.join(', ')} bits`);
}
// Get the Web Crypto API interface.
const webCrypto = getWebcryptoSubtle();
// Import the JWK into the Web Crypto API to use for the decrypt operation.
const webCryptoKey = yield webCrypto.importKey('jwk', key, { name: 'AES-GCM' }, true, ['decrypt']);
// Browser implementations of the Web Crypto API throw an error if additionalData is undefined.
const algorithm = (additionalData === undefined)
? { name: 'AES-GCM', iv, tagLength }
: { name: 'AES-GCM', additionalData, iv, tagLength };
// Decrypt the data.
const plaintextBuffer = yield webCrypto.decrypt(algorithm, webCryptoKey, data);
// Convert from ArrayBuffer to Uint8Array.
const plaintext = new Uint8Array(plaintextBuffer);
return plaintext;
});
}
/**
* Encrypts the provided data using AES-GCM.
*
* @remarks
* This method performs AES-GCM encryption on the given data using the specified key.
* It requires an initialization vector (IV), the encrypted data along with the decryption key,
* and optionally, additional authenticated data (AAD). The method returns the encrypted data as a
* Uint8Array. The optional `tagLength` parameter specifies the size in bits of the authentication
* tag generated in the encryption operation and used for authentication in the corresponding
* decryption. If not specified, the default tag length of 128 bits is used.
*
* @example
* ```ts
* const data = new TextEncoder().encode('Messsage');
* const iv = new Uint8Array([...]); // Initialization vector
* const additionalData = new Uint8Array([...]); // Optional additional authenticated data
* const key = { ... }; // A Jwk object representing an AES key
* const encryptedData = await AesGcm.encrypt({
* data,
* iv,
* additionalData,
* key,
* tagLength: 128 // Optional tag length in bits
* });
* ```
*
* @param params - The parameters for the encryption operation.
* @param params.key - The key to use for encryption, represented in JWK format.
* @param params.data - The data to encrypt, represented as a Uint8Array.
* @param params.iv - The initialization vector, represented as a Uint8Array.
* @param params.additionalData - Optional additional authenticated data. Optional.
* @param params.tagLength - The length of the authentication tag in bits. Optional.
*
* @returns A Promise that resolves to the encrypted data as a Uint8Array.
*/
static encrypt({ data, iv, key, additionalData, tagLength }) {
return __awaiter(this, void 0, void 0, function* () {
// Validate the initialization vector length.
if (iv.byteLength !== AES_GCM_IV_LENGTH / 8) {
throw new TypeError(`The initialization vector must be ${AES_GCM_IV_LENGTH} bits in length`);
}
// Validate the tag length.
if (tagLength && !AES_GCM_TAG_LENGTHS.includes(tagLength)) {
throw new RangeError(`The tag length is invalid: Must be ${AES_GCM_TAG_LENGTHS.join(', ')} bits`);
}
// Get the Web Crypto API interface.
const webCrypto = getWebcryptoSubtle();
// Import the JWK into the Web Crypto API to use for the encrypt operation.
const webCryptoKey = yield webCrypto.importKey('jwk', key, { name: 'AES-GCM' }, true, ['encrypt']);
// Browser implementations of the Web Crypto API throw an error if additionalData is undefined.
const algorithm = (additionalData === undefined)
? { name: 'AES-GCM', iv, tagLength }
: { name: 'AES-GCM', additionalData, iv, tagLength };
// Encrypt the data.
const ciphertextBuffer = yield webCrypto.encrypt(algorithm, webCryptoKey, data);
// Convert from ArrayBuffer to Uint8Array.
const ciphertext = new Uint8Array(ciphertextBuffer);
return ciphertext;
});
}
/**
* Generates a symmetric key for AES in Galois/Counter Mode (GCM) in JSON Web Key (JWK) format.
*
* @remarks
* This method creates a new symmetric key of a specified length suitable for use with
* AES-GCM encryption. It leverages cryptographically secure random number generation
* to ensure the uniqueness and security of the key. The generated key adheres to the JWK
* format, facilitating compatibility with common cryptographic standards and ease of use
* in various cryptographic applications.
*
* The generated key includes these components:
* - `kty`: Key Type, set to 'oct' for Octet Sequence, indicating a symmetric key.
* - `k`: The symmetric key component, base64url-encoded.
* - `kid`: Key ID, generated based on the JWK thumbprint, providing a unique identifier.
*
* @example
* ```ts
* const length = 256; // Length of the key in bits (e.g., 128, 192, 256)
* const privateKey = await AesGcm.generateKey({ length });
* ```
*
* @param params - The parameters for the key generation.
* @param params.length - The length of the key in bits. Common lengths are 128, 192, and 256 bits.
*
* @returns A Promise that resolves to the generated symmetric key in JWK format.
*/
static generateKey({ length }) {
return __awaiter(this, void 0, void 0, function* () {
// Validate the key length.
if (!AES_KEY_LENGTHS.includes(length)) {
throw new RangeError(`The key length is invalid: Must be ${AES_KEY_LENGTHS.join(', ')} bits`);
}
// Get the Web Crypto API interface.
const webCrypto = getWebcryptoSubtle();
// Generate a random private key.
// See https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues#usage_notes for
// an explanation for why Web Crypto generateKey() is used instead of getRandomValues().
const webCryptoKey = yield webCrypto.generateKey({ name: 'AES-GCM', length }, true, ['encrypt']);
// Export the private key in JWK format.
const _a = yield webCrypto.exportKey('jwk', webCryptoKey), { ext, key_ops } = _a, privateKey = __rest(_a, ["ext", "key_ops"]);
// Compute the JWK thumbprint and set as the key ID.
privateKey.kid = yield computeJwkThumbprint({ jwk: privateKey });
return privateKey;
});
}
/**
* Converts a private key from JSON Web Key (JWK) format to a raw byte array (Uint8Array).
*
* @remarks
* This method takes a symmetric key in JWK format and extracts its raw byte representation.
* It focuses on the 'k' parameter of the JWK, which represents the symmetric key component
* in base64url encoding. The method decodes this value into a byte array, providing
* the symmetric key in its raw binary form.
*
* @example
* ```ts
* const privateKey = { ... }; // A symmetric key in JWK format
* const privateKeyBytes = await AesGcm.privateKeyToBytes({ privateKey });
* ```
*
* @param params - The parameters for the symmetric key conversion.
* @param params.privateKey - The symmetric key in JWK format.
*
* @returns A Promise that resolves to the symmetric key as a Uint8Array.
*/
static privateKeyToBytes({ privateKey }) {
return __awaiter(this, void 0, void 0, function* () {
// Verify the provided JWK represents a valid oct private key.
if (!isOctPrivateJwk(privateKey)) {
throw new Error(`AesGcm: The provided key is not a valid oct private key.`);
}
// Decode the provided private key to bytes.
const privateKeyBytes = Convert.base64Url(privateKey.k).toUint8Array();
return privateKeyBytes;
});
}
}
//# sourceMappingURL=aes-gcm.js.map
@@ -0,0 +1 @@
{"version":3,"file":"aes-gcm.js","sourceRoot":"","sources":["../../../../../src/prototyping/crypto/primitives/aes-gcm.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,247 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
// ! TODO : Make sure I remove `@noble/ciphers` from the Agent package.json once this is moved to the `@web5/crypto` package.
import { getWebcryptoSubtle } from '@noble/ciphers/webcrypto/utils';
import { Convert } from '@web5/common';
import { computeJwkThumbprint, isOctPrivateJwk } from '@web5/crypto';
import { CryptoError, CryptoErrorCode } from '../crypto-error.js';
/**
* Constant defining the AES key length values in bits.
*
* @remarks
* NIST publication FIPS 197 states:
* > The AES algorithm is capable of using cryptographic keys of 128, 192, and 256 bits to encrypt
* > and decrypt data in blocks of 128 bits.
*
* This implementation does not support key lengths that are different from the three values
* defined by this constant.
*
* @see {@link https://doi.org/10.6028/NIST.FIPS.197-upd1 | NIST FIPS 197}
*/
const AES_KEY_LENGTHS = [128, 192, 256];
export class AesKw {
/**
* Converts a raw private key in bytes to its corresponding JSON Web Key (JWK) format.
*
* @remarks
* This method takes a symmetric key represented as a byte array (Uint8Array) and
* converts it into a JWK object for use with AES (Advanced Encryption Standard)
* for key wrapping. The conversion process involves encoding the key into
* base64url format and setting the appropriate JWK parameters.
*
* The resulting JWK object includes the following properties:
* - `kty`: Key Type, set to 'oct' for Octet Sequence (representing a symmetric key).
* - `k`: The symmetric key, base64url-encoded.
* - `kid`: Key ID, generated based on the JWK thumbprint.
*
* @example
* ```ts
* const privateKeyBytes = new Uint8Array([...]); // Replace with actual symmetric key bytes
* const privateKey = await AesKw.bytesToPrivateKey({ privateKeyBytes });
* ```
*
* @param params - The parameters for the symmetric key conversion.
* @param params.privateKeyBytes - The raw symmetric key as a Uint8Array.
*
* @returns A Promise that resolves to the symmetric key in JWK format.
*/
static bytesToPrivateKey({ privateKeyBytes }) {
return __awaiter(this, void 0, void 0, function* () {
// Construct the private key in JWK format.
const privateKey = {
k: Convert.uint8Array(privateKeyBytes).toBase64Url(),
kty: 'oct'
};
// Compute the JWK thumbprint and set as the key ID.
privateKey.kid = yield computeJwkThumbprint({ jwk: privateKey });
// Add algorithm identifier based on key length.
const lengthInBits = privateKeyBytes.length * 8;
privateKey.alg = { 128: 'A128KW', 192: 'A192KW', 256: 'A256KW' }[lengthInBits];
return privateKey;
});
}
/**
* Generates a symmetric key for AES for key wrapping in JSON Web Key (JWK) format.
*
* @remarks
* This method creates a new symmetric key of a specified length suitable for use with
* AES key wrapping. It uses cryptographically secure random number generation to
* ensure the uniqueness and security of the key. The generated key adheres to the JWK
* format, making it compatible with common cryptographic standards and easy to use in
* various cryptographic processes.
*
* The generated key includes the following components:
* - `kty`: Key Type, set to 'oct' for Octet Sequence.
* - `k`: The symmetric key component, base64url-encoded.
* - `kid`: Key ID, generated based on the JWK thumbprint.
* - `alg`: Algorithm, set to 'A128KW', 'A192KW', or 'A256KW' for AES Key Wrap with the
* specified key length.
*
* @example
* ```ts
* const length = 256; // Length of the key in bits (e.g., 128, 192, 256)
* const privateKey = await AesKw.generateKey({ length });
* ```
*
* @param params - The parameters for the key generation.
* @param params.length - The length of the key in bits. Common lengths are 128, 192, and 256 bits.
*
* @returns A Promise that resolves to the generated symmetric key in JWK format.
*/
static generateKey({ length }) {
return __awaiter(this, void 0, void 0, function* () {
// Validate the key length.
if (!AES_KEY_LENGTHS.includes(length)) {
throw new RangeError(`The key length is invalid: Must be ${AES_KEY_LENGTHS.join(', ')} bits`);
}
// Get the Web Crypto API interface.
const webCrypto = getWebcryptoSubtle();
// Generate a random private key.
// See https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues#usage_notes for
// an explanation for why Web Crypto generateKey() is used instead of getRandomValues().
const webCryptoKey = yield webCrypto.generateKey({ name: 'AES-KW', length }, true, ['wrapKey', 'unwrapKey']);
// Export the private key in JWK format.
const _a = yield webCrypto.exportKey('jwk', webCryptoKey), { ext, key_ops } = _a, privateKey = __rest(_a, ["ext", "key_ops"]);
// Compute the JWK thumbprint and set as the key ID.
privateKey.kid = yield computeJwkThumbprint({ jwk: privateKey });
return privateKey;
});
}
/**
* Converts a private key from JSON Web Key (JWK) format to a raw byte array (Uint8Array).
*
* @remarks
* This method takes a symmetric key in JWK format and extracts its raw byte representation.
* It decodes the 'k' parameter of the JWK value, which represents the symmetric key in base64url
* encoding, into a byte array.
*
* @example
* ```ts
* const privateKey = { ... }; // A symmetric key in JWK format
* const privateKeyBytes = await AesKw.privateKeyToBytes({ privateKey });
* ```
*
* @param params - The parameters for the symmetric key conversion.
* @param params.privateKey - The symmetric key in JWK format.
*
* @returns A Promise that resolves to the symmetric key as a Uint8Array.
*/
static privateKeyToBytes({ privateKey }) {
return __awaiter(this, void 0, void 0, function* () {
// Verify the provided JWK represents a valid oct private key.
if (!isOctPrivateJwk(privateKey)) {
throw new Error(`AesKw: The provided key is not a valid oct private key.`);
}
// Decode the provided private key to bytes.
const privateKeyBytes = Convert.base64Url(privateKey.k).toUint8Array();
return privateKeyBytes;
});
}
static unwrapKey({ wrappedKeyBytes, wrappedKeyAlgorithm, decryptionKey }) {
return __awaiter(this, void 0, void 0, function* () {
if (!('alg' in decryptionKey && decryptionKey.alg)) {
throw new CryptoError(CryptoErrorCode.InvalidJwk, `The decryption key is missing the 'alg' property.`);
}
if (!['A128KW', 'A192KW', 'A256KW'].includes(decryptionKey.alg)) {
throw new CryptoError(CryptoErrorCode.AlgorithmNotSupported, `The 'decryptionKey' algorithm is not supported: ${decryptionKey.alg}`);
}
// Get the Web Crypto API interface.
const webCrypto = getWebcryptoSubtle();
// Import the decryption key for use with the Web Crypto API.
const decryptionCryptoKey = yield webCrypto.importKey('jwk', // key format
decryptionKey, // key data
{ name: 'AES-KW' }, // algorithm identifier
true, // key is extractable
['unwrapKey'] // key usages
);
// Map the private key's JOSE algorithm name to the Web Crypto API algorithm identifier.
const webCryptoAlgorithm = {
A128KW: 'AES-KW', A192KW: 'AES-KW', A256KW: 'AES-KW',
A128GCM: 'AES-GCM', A192GCM: 'AES-GCM', A256GCM: 'AES-GCM',
}[wrappedKeyAlgorithm];
if (!webCryptoAlgorithm) {
throw new CryptoError(CryptoErrorCode.AlgorithmNotSupported, `The 'wrappedKeyAlgorithm' is not supported: ${wrappedKeyAlgorithm}`);
}
// Unwrap the key using the Web Crypto API.
const unwrappedCryptoKey = yield webCrypto.unwrapKey('raw', // output format
wrappedKeyBytes.buffer, // key to unwrap
decryptionCryptoKey, // unwrapping key
'AES-KW', // algorithm identifier
{ name: webCryptoAlgorithm }, // unwrapped key algorithm identifier
true, // key is extractable
['unwrapKey'] // key usages
);
// Export the unwrapped key in JWK format.
const _a = yield webCrypto.exportKey('jwk', unwrappedCryptoKey), { ext, key_ops } = _a, unwrappedJsonWebKey = __rest(_a, ["ext", "key_ops"]);
const unwrappedKey = unwrappedJsonWebKey;
// Compute the JWK thumbprint and set as the key ID.
unwrappedKey.kid = yield computeJwkThumbprint({ jwk: unwrappedKey });
return unwrappedKey;
});
}
static wrapKey({ unwrappedKey, encryptionKey }) {
return __awaiter(this, void 0, void 0, function* () {
if (!('alg' in encryptionKey && encryptionKey.alg)) {
throw new CryptoError(CryptoErrorCode.InvalidJwk, `The encryption key is missing the 'alg' property.`);
}
if (!['A128KW', 'A192KW', 'A256KW'].includes(encryptionKey.alg)) {
throw new CryptoError(CryptoErrorCode.AlgorithmNotSupported, `The 'encryptionKey' algorithm is not supported: ${encryptionKey.alg}`);
}
if (!('alg' in unwrappedKey && unwrappedKey.alg)) {
throw new CryptoError(CryptoErrorCode.InvalidJwk, `The private key to wrap is missing the 'alg' property.`);
}
// Get the Web Crypto API interface.
const webCrypto = getWebcryptoSubtle();
// Import the encryption key for use with the Web Crypto API.
const encryptionCryptoKey = yield webCrypto.importKey('jwk', // key format
encryptionKey, // key data
{ name: 'AES-KW' }, // algorithm identifier
true, // key is extractable
['wrapKey'] // key usages
);
// Map the private key's JOSE algorithm name to the Web Crypto API algorithm identifier.
const webCryptoAlgorithm = {
A128KW: 'AES-KW', A192KW: 'AES-KW', A256KW: 'AES-KW',
A128GCM: 'AES-GCM', A192GCM: 'AES-GCM', A256GCM: 'AES-GCM',
}[unwrappedKey.alg];
if (!webCryptoAlgorithm) {
throw new CryptoError(CryptoErrorCode.AlgorithmNotSupported, `The 'unwrappedKey' algorithm is not supported: ${unwrappedKey.alg}`);
}
// Import the private key to wrap for use with the Web Crypto API.
const unwrappedCryptoKey = yield webCrypto.importKey('jwk', // key format
unwrappedKey, // key data
{ name: webCryptoAlgorithm }, // algorithm identifier
true, // key is extractable
['unwrapKey'] // key usages
);
// Wrap the key using the Web Crypto API.
const wrappedKeyBuffer = yield webCrypto.wrapKey('raw', // output format
unwrappedCryptoKey, // key to wrap
encryptionCryptoKey, // wrapping key
'AES-KW' // algorithm identifier
);
// Convert from ArrayBuffer to Uint8Array.
const wrappedKeyBytes = new Uint8Array(wrappedKeyBuffer);
return wrappedKeyBytes;
});
}
}
//# sourceMappingURL=aes-kw.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,80 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
// ! TODO : Make sure I remove `@noble/ciphers` from the Agent package.json once this is moved to the `@web5/crypto` package.
import { getWebcryptoSubtle } from '@noble/ciphers/webcrypto/utils';
import { Convert } from '@web5/common';
/**
* The `Hkdf` class provides an interface for HMAC-based Extract-and-Expand Key Derivation Function (HKDF)
* as defined in RFC 5869.
*
* Note: The `baseKeyBytes` that will be the input key material for HKDF should be a high-entropy secret
* value, such as a cryptographic key. It should be kept confidential and not be derived from a
* low-entropy value, such as a password.
*
* @example
* ```ts
* const info = new Uint8Array([...]);
* const derivedKeyBytes = await Hkdf.deriveKeyBytes({
* baseKeyBytes: new Uint8Array([...]), // Input keying material
* hash: 'SHA-256', // The hash function to use ('SHA-256', 'SHA-384', 'SHA-512')
* salt: new Uint8Array([...]), // The salt value
* info: new Uint8Array([...]), // Optional application-specific information
* length: 256 // The length of the derived key in bits
* });
* ```
*/
export class Hkdf {
/**
* Derives a key using the HMAC-based Extract-and-Expand Key Derivation Function (HKDF).
*
* This method generates a derived key using a hash function from input keying material given as
* `baseKeyBytes`. The length of the derived key can be specified. Optionally, it can also use a salt
* and info for the derivation process.
*
* HKDF is useful in various cryptographic applications and protocols, especially when
* there's a need to derive multiple keys from a single source of key material.
*
* Note: The `baseKeyBytes` that will be the input key material for HKDF should be a high-entropy
* secret value, such as a cryptographic key. It should be kept confidential and not be derived
* from a low-entropy value, such as a password.
*
* @example
* ```ts
* const info = new Uint8Array([...]);
* const derivedKeyBytes = await Hkdf.deriveKeyBytes({
* baseKeyBytes: new Uint8Array([...]), // Input keying material
* hash: 'SHA-256', // The hash function to use ('SHA-256', 'SHA-384', 'SHA-512')
* salt: new Uint8Array([...]), // The salt value
* info: new Uint8Array([...]), // Optional application-specific information
* length: 256 // The length of the derived key in bits
* });
* ```
*
* @param params - The parameters for key derivation.
* @returns A Promise that resolves to the derived key as a byte array.
*/
static deriveKeyBytes({ baseKeyBytes, length, hash, salt, info = new Uint8Array() }) {
return __awaiter(this, void 0, void 0, function* () {
// Get the Web Crypto API interface.
const webCrypto = getWebcryptoSubtle();
// Import the baseKeyBytes into the Web Crypto API to use for the key derivation operation.
const webCryptoKey = yield webCrypto.importKey('raw', baseKeyBytes, { name: 'HKDF' }, false, ['deriveBits']);
// Convert the salt and info to Uint8Array if they are provided as strings.
salt = typeof salt === 'string' ? Convert.string(salt).toUint8Array() : salt;
info = typeof info === 'string' ? Convert.string(info).toUint8Array() : info;
// Derive the bytes using the Web Crypto API.
const derivedKeyBuffer = yield crypto.subtle.deriveBits({ name: 'HKDF', hash, salt, info }, webCryptoKey, length);
// Convert from ArrayBuffer to Uint8Array.
const derivedKeyBytes = new Uint8Array(derivedKeyBuffer);
return derivedKeyBytes;
});
}
}
//# sourceMappingURL=hkdf.js.map
@@ -0,0 +1 @@
{"version":3,"file":"hkdf.js","sourceRoot":"","sources":["../../../../../src/prototyping/crypto/primitives/hkdf.ts"],"names":[],"mappings":";;;;;;;;;AAAA,6HAA6H;AAC7H,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AAEpE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AA0CvC;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,OAAO,IAAI;IACf;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA4BG;IACI,MAAM,CAAO,cAAc,CAAC,EAAE,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,GAAG,IAAI,UAAU,EAAE,EAC3D;;YAEjC,oCAAoC;YACpC,MAAM,SAAS,GAAG,kBAAkB,EAAkB,CAAC;YAEvD,2FAA2F;YAC3F,MAAM,YAAY,GAAG,MAAM,SAAS,CAAC,SAAS,CAAC,KAAK,EAAE,YAAY,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC;YAE7G,2EAA2E;YAC3E,IAAI,GAAG,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;YAC7E,IAAI,GAAG,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;YAE7E,6CAA6C;YAC7C,MAAM,gBAAgB,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,UAAU,CACrD,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,EAClC,YAAY,EACZ,MAAM,CACP,CAAC;YAEF,0CAA0C;YAC1C,MAAM,eAAe,GAAG,IAAI,UAAU,CAAC,gBAAgB,CAAC,CAAC;YAEzD,OAAO,eAAe,CAAC;QACzB,CAAC;KAAA;CACF"}
@@ -0,0 +1,85 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
// ! TODO : Make sure I remove `@noble/ciphers` from the Agent package.json once this is moved to the `@web5/crypto` package.
import { getWebcryptoSubtle } from '@noble/ciphers/webcrypto/utils';
/**
* The `Pbkdf2` class provides a secure way to derive cryptographic keys from a password
* using the PBKDF2 (Password-Based Key Derivation Function 2) algorithm.
*
* The PBKDF2 algorithm is widely used for generating keys from passwords, as it applies
* a pseudorandom function to the input password along with a salt value and iterates the
* process multiple times to increase the key's resistance to brute-force attacks.
*
* Notes:
* - The `baseKeyBytes` that will be the input key material for PBKDF2 is expected to be a low-entropy
* value, such as a password or passphrase. It should be kept confidential.
* - In 2023, {@link https://web.archive.org/web/20230123232056/https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#pbkdf2 | OWASP recommended}
* a minimum of 600,000 iterations for PBKDF2-HMAC-SHA256 and 210,000 for PBKDF2-HMAC-SHA512.
*
* @example
* ```ts
* // Key Derivation
* const derivedKeyBytes = await Pbkdf2.deriveKeyBytes({
* baseKeyBytes: new TextEncoder().encode('password'), // The password as a Uint8Array
* hash: 'SHA-256', // The hash function to use ('SHA-256', 'SHA-384', 'SHA-512')
* salt: new Uint8Array([...]), // The salt value
* iterations: 600_000, // The number of iterations
* length: 256 // The length of the derived key in bits
* });
* ```
*
* @remarks
* This class relies on the availability of the Web Crypto API.
*/
export class Pbkdf2 {
/**
* Derives a cryptographic key from a password using the PBKDF2 algorithm.
*
* @remarks
* This method applies the PBKDF2 algorithm to the provided password along with
* a salt value and iterates the process a specified number of times. It uses
* a cryptographic hash function to enhance security and produce a key of the
* desired length. The method is capable of utilizing either the Web Crypto API
* or the Node.js Crypto module, depending on the environment's support.
*
* @example
* ```ts
* const derivedKeyBytes = await Pbkdf2.deriveKeyBytes({
* baseKeyBytes: new TextEncoder().encode('password'), // The password as a Uint8Array
* hash: 'SHA-256', // The hash function to use ('SHA-256', 'SHA-384', 'SHA-512')
* salt: new Uint8Array([...]), // The salt value
* iterations: 600_000, // The number of iterations
* length: 256 // The length of the derived key in bits
* });
* ```
*
* @param params - The parameters for key derivation.
* @returns A Promise that resolves to the derived key as a byte array.
*/
static deriveKeyBytes({ baseKeyBytes, hash, salt, iterations, length }) {
return __awaiter(this, void 0, void 0, function* () {
// Get the Web Crypto API interface.
const webCrypto = getWebcryptoSubtle();
// Import the password as a raw key for use with the Web Crypto API.
const webCryptoKey = yield webCrypto.importKey('raw', // key format is raw bytes
baseKeyBytes, // key data to import
{ name: 'PBKDF2' }, // algorithm identifier
false, // key is not extractable
['deriveBits'] // key usages
);
// Derive the bytes using the Web Crypto API.
const derivedKeyBuffer = yield webCrypto.deriveBits({ name: 'PBKDF2', hash, salt, iterations }, webCryptoKey, length);
// Convert from ArrayBuffer to Uint8Array.
const derivedKeyBytes = new Uint8Array(derivedKeyBuffer);
return derivedKeyBytes;
});
}
}
//# sourceMappingURL=pbkdf2.js.map
@@ -0,0 +1 @@
{"version":3,"file":"pbkdf2.js","sourceRoot":"","sources":["../../../../../src/prototyping/crypto/primitives/pbkdf2.ts"],"names":[],"mappings":";;;;;;;;;AAAA,6HAA6H;AAC7H,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AAiCpE;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,OAAO,MAAM;IACjB;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACI,MAAM,CAAO,cAAc,CAAC,EAAE,YAAY,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAC5C;;YAEnC,oCAAoC;YACpC,MAAM,SAAS,GAAG,kBAAkB,EAAkB,CAAC;YAEvD,oEAAoE;YACpE,MAAM,YAAY,GAAG,MAAM,SAAS,CAAC,SAAS,CAC5C,KAAK,EAAe,0BAA0B;YAC9C,YAAY,EAAQ,qBAAqB;YACzC,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,uBAAuB;YAC3C,KAAK,EAAe,yBAAyB;YAC7C,CAAC,YAAY,CAAC,CAAM,aAAa;aAClC,CAAC;YAEF,6CAA6C;YAC7C,MAAM,gBAAgB,GAAG,MAAM,SAAS,CAAC,UAAU,CACjD,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,EAC1C,YAAY,EACZ,MAAM,CACP,CAAC;YAEF,0CAA0C;YAC1C,MAAM,eAAe,GAAG,IAAI,UAAU,CAAC,gBAAgB,CAAC,CAAC;YAEzD,OAAO,eAAe,CAAC;QACzB,CAAC;KAAA;CACF"}
@@ -0,0 +1,2 @@
export {};
//# sourceMappingURL=cipher.js.map
@@ -0,0 +1 @@
{"version":3,"file":"cipher.js","sourceRoot":"","sources":["../../../../../src/prototyping/crypto/types/cipher.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
export {};
//# sourceMappingURL=crypto-api.js.map
@@ -0,0 +1 @@
{"version":3,"file":"crypto-api.js","sourceRoot":"","sources":["../../../../../src/prototyping/crypto/types/crypto-api.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
export {};
//# sourceMappingURL=key-converter.js.map
@@ -0,0 +1 @@
{"version":3,"file":"key-converter.js","sourceRoot":"","sources":["../../../../../src/prototyping/crypto/types/key-converter.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
export {};
//# sourceMappingURL=key-deriver.js.map
@@ -0,0 +1 @@
{"version":3,"file":"key-deriver.js","sourceRoot":"","sources":["../../../../../src/prototyping/crypto/types/key-deriver.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
export {};
//# sourceMappingURL=key-io.js.map
@@ -0,0 +1 @@
{"version":3,"file":"key-io.js","sourceRoot":"","sources":["../../../../../src/prototyping/crypto/types/key-io.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
export {};
//# sourceMappingURL=key-manager.js.map
@@ -0,0 +1 @@
{"version":3,"file":"key-manager.js","sourceRoot":"","sources":["../../../../../src/prototyping/crypto/types/key-manager.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
export {};
//# sourceMappingURL=key-wrapper.js.map
@@ -0,0 +1 @@
{"version":3,"file":"key-wrapper.js","sourceRoot":"","sources":["../../../../../src/prototyping/crypto/types/key-wrapper.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
export {};
//# sourceMappingURL=params-direct.js.map
@@ -0,0 +1 @@
{"version":3,"file":"params-direct.js","sourceRoot":"","sources":["../../../../../src/prototyping/crypto/types/params-direct.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
export {};
//# sourceMappingURL=params-kms.js.map
@@ -0,0 +1 @@
{"version":3,"file":"params-kms.js","sourceRoot":"","sources":["../../../../../src/prototyping/crypto/types/params-kms.ts"],"names":[],"mappings":""}
@@ -0,0 +1,19 @@
export function isCipher(obj) {
return (obj !== null && typeof obj === 'object'
&& 'encrypt' in obj && typeof obj.encrypt === 'function'
&& 'decrypt' in obj && typeof obj.decrypt === 'function');
}
export function isKeyExporter(obj) {
return (obj !== null && typeof obj === 'object'
&& 'exportKey' in obj && typeof obj.exportKey === 'function');
}
export function isKeyImporter(obj) {
return (obj !== null && typeof obj === 'object'
&& 'importKey' in obj && typeof obj.importKey === 'function');
}
export function isKeyWrapper(obj) {
return (obj !== null && typeof obj === 'object'
&& 'wrapKey' in obj && typeof obj.wrapKey === 'function'
&& 'unwrapKey' in obj && typeof obj.unwrapKey === 'function');
}
//# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../../src/prototyping/crypto/utils.ts"],"names":[],"mappings":"AAIA,MAAM,UAAU,QAAQ,CACtB,GAAY;IAEZ,OAAO,CACL,GAAG,KAAK,IAAI,IAAI,OAAO,GAAG,KAAK,QAAQ;WACpC,SAAS,IAAI,GAAG,IAAI,OAAO,GAAG,CAAC,OAAO,KAAK,UAAU;WACrD,SAAS,IAAI,GAAG,IAAI,OAAO,GAAG,CAAC,OAAO,KAAK,UAAU,CACzD,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,aAAa,CAC3B,GAAY;IAEZ,OAAO,CACL,GAAG,KAAK,IAAI,IAAI,OAAO,GAAG,KAAK,QAAQ;WACpC,WAAW,IAAI,GAAG,IAAI,OAAO,GAAG,CAAC,SAAS,KAAK,UAAU,CAC7D,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,aAAa,CAC3B,GAAY;IAEZ,OAAO,CACL,GAAG,KAAK,IAAI,IAAI,OAAO,GAAG,KAAK,QAAQ;WACpC,WAAW,IAAI,GAAG,IAAI,OAAO,GAAG,CAAC,SAAS,KAAK,UAAU,CAC7D,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,YAAY,CAC1B,GAAY;IAEZ,OAAO,CACL,GAAG,KAAK,IAAI,IAAI,OAAO,GAAG,KAAK,QAAQ;WACpC,SAAS,IAAI,GAAG,IAAI,OAAO,GAAG,CAAC,OAAO,KAAK,UAAU;WACrD,WAAW,IAAI,GAAG,IAAI,OAAO,GAAG,CAAC,SAAS,KAAK,UAAU,CAC7D,CAAC;AACJ,CAAC"}
@@ -0,0 +1,77 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import ms from 'ms';
import { TtlCache } from '@web5/common';
export class DidResolverCacheMemory {
constructor({ ttl = '15m' } = {}) {
this.cache = new TtlCache({ ttl: ms(ttl) });
}
/**
* Retrieves a DID resolution result from the cache.
*
* If the cached item has exceeded its TTL, it's scheduled for deletion and undefined is returned.
*
* @param didUri - The DID string used as the key for retrieving the cached result.
* @returns The cached DID resolution result or undefined if not found or expired.
*/
get(didUri) {
return __awaiter(this, void 0, void 0, function* () {
if (!didUri) {
throw new Error('Key cannot be null or undefined');
}
return this.cache.get(didUri);
});
}
/**
* Stores a DID resolution result in the cache with a TTL.
*
* @param didUri - The DID string used as the key for storing the result.
* @param resolutionResult - The DID resolution result to be cached.
* @returns A promise that resolves when the operation is complete.
*/
set(didUri, resolutionResult) {
return __awaiter(this, void 0, void 0, function* () {
this.cache.set(didUri, resolutionResult);
});
}
/**
* Deletes a DID resolution result from the cache.
*
* @param didUri - The DID string used as the key for deletion.
* @returns A promise that resolves when the operation is complete.
*/
delete(didUri) {
return __awaiter(this, void 0, void 0, function* () {
this.cache.delete(didUri);
});
}
/**
* Clears all entries from the cache.
*
* @returns A promise that resolves when the operation is complete.
*/
clear() {
return __awaiter(this, void 0, void 0, function* () {
this.cache.clear();
});
}
/**
* This method is a no-op but exists to be consistent with other DID Resolver Cache
* implementations.
*
* @returns A promise that resolves immediately.
*/
close() {
return __awaiter(this, void 0, void 0, function* () {
// No-op since there is no underlying store to close.
});
}
}
//# sourceMappingURL=resolver-cache-memory.js.map
@@ -0,0 +1 @@
{"version":3,"file":"resolver-cache-memory.js","sourceRoot":"","sources":["../../../../src/prototyping/dids/resolver-cache-memory.ts"],"names":[],"mappings":";;;;;;;;;AAEA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAiBxC,MAAM,OAAO,sBAAsB;IAGjC,YAAY,EAAE,GAAG,GAAG,KAAK,KAAmC,EAAE;QAC5D,IAAI,CAAC,KAAK,GAAG,IAAI,QAAQ,CAAC,EAAE,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC9C,CAAC;IAED;;;;;;;OAOG;IACU,GAAG,CAAC,MAAc;;YAC7B,IAAI,CAAC,MAAM,EAAE;gBACX,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;aACpD;YAED,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAChC,CAAC;KAAA;IAED;;;;;;OAMG;IACU,GAAG,CAAC,MAAc,EAAE,gBAAqC;;YACpE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;QAC3C,CAAC;KAAA;IAED;;;;;OAKG;IACU,MAAM,CAAC,MAAc;;YAChC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAC5B,CAAC;KAAA;IAED;;;;OAIG;IACU,KAAK;;YAChB,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACrB,CAAC;KAAA;IAED;;;;;OAKG;IACU,KAAK;;YAChB,qDAAqD;QACvD,CAAC;KAAA;CACF"}
@@ -0,0 +1,9 @@
export function isPortableDid(obj) {
// Validate that the given value is an object that has the necessary properties of PortableDid.
return !(!obj || typeof obj !== 'object' || obj === null)
&& 'uri' in obj
&& 'document' in obj
&& 'metadata' in obj
&& (!('keyManager' in obj) || obj.keyManager === undefined);
}
//# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../../src/prototyping/dids/utils.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,aAAa,CAAC,GAAY;IACxC,+FAA+F;IAC/F,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,CAAC;WACpD,KAAK,IAAI,GAAG;WACZ,UAAU,IAAI,GAAG;WACjB,UAAU,IAAI,GAAG;WACjB,CAAC,CAAC,CAAC,YAAY,IAAI,GAAG,CAAC,IAAI,GAAG,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC;AAChE,CAAC"}
+123
View File
@@ -0,0 +1,123 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { utils as cryptoUtils } from '@web5/crypto';
import { createJsonRpcRequest } from './prototyping/clients/json-rpc.js';
import { HttpDwnRpcClient } from './prototyping/clients/http-dwn-rpc-client.js';
import { WebSocketDwnRpcClient } from './prototyping/clients/web-socket-clients.js';
export var DidRpcMethod;
(function (DidRpcMethod) {
DidRpcMethod["Create"] = "did.create";
DidRpcMethod["Resolve"] = "did.resolve";
})(DidRpcMethod || (DidRpcMethod = {}));
/**
* Client used to communicate with Dwn Servers
*/
export class Web5RpcClient {
constructor(clients = []) {
this.transportClients = new Map();
// include http and socket clients as default.
// can be overwritten for 'http:', 'https:', 'ws: or ':wss' if instantiated with other clients.
clients = [new HttpWeb5RpcClient(), new WebSocketWeb5RpcClient(), ...clients];
for (let client of clients) {
for (let transportScheme of client.transportProtocols) {
this.transportClients.set(transportScheme, client);
}
}
}
get transportProtocols() {
return Array.from(this.transportClients.keys());
}
sendDidRequest(request) {
return __awaiter(this, void 0, void 0, function* () {
// URL() will throw if provided `url` is invalid.
const url = new URL(request.url);
const transportClient = this.transportClients.get(url.protocol);
if (!transportClient) {
const error = new Error(`no ${url.protocol} transport client available`);
error.name = 'NO_TRANSPORT_CLIENT';
throw error;
}
return transportClient.sendDidRequest(request);
});
}
sendDwnRequest(request) {
// will throw if url is invalid
const url = new URL(request.dwnUrl);
const transportClient = this.transportClients.get(url.protocol);
if (!transportClient) {
const error = new Error(`no ${url.protocol} transport client available`);
error.name = 'NO_TRANSPORT_CLIENT';
throw error;
}
return transportClient.sendDwnRequest(request);
}
getServerInfo(dwnUrl) {
return __awaiter(this, void 0, void 0, function* () {
// will throw if url is invalid
const url = new URL(dwnUrl);
const transportClient = this.transportClients.get(url.protocol);
if (!transportClient) {
const error = new Error(`no ${url.protocol} transport client available`);
error.name = 'NO_TRANSPORT_CLIENT';
throw error;
}
return transportClient.getServerInfo(dwnUrl);
});
}
}
export class HttpWeb5RpcClient extends HttpDwnRpcClient {
sendDidRequest(request) {
return __awaiter(this, void 0, void 0, function* () {
const requestId = cryptoUtils.randomUuid();
const jsonRpcRequest = createJsonRpcRequest(requestId, request.method, {
data: request.data
});
const httpRequest = new Request(request.url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(jsonRpcRequest),
});
let jsonRpcResponse;
try {
const response = yield fetch(httpRequest);
if (response.ok) {
jsonRpcResponse = yield response.json();
// If the response is an error, throw an error.
if (jsonRpcResponse.error) {
const { code, message } = jsonRpcResponse.error;
throw new Error(`JSON RPC (${code}) - ${message}`);
}
}
else {
throw new Error(`HTTP (${response.status}) - ${response.statusText}`);
}
}
catch (error) {
throw new Error(`Error encountered while processing response from ${request.url}: ${error.message}`);
}
return jsonRpcResponse.result;
});
}
}
export class WebSocketWeb5RpcClient extends WebSocketDwnRpcClient {
sendDidRequest(_request) {
return __awaiter(this, void 0, void 0, function* () {
throw new Error(`not implemented for transports [${this.transportProtocols.join(', ')}]`);
});
}
getServerInfo(_dwnUrl) {
return __awaiter(this, void 0, void 0, function* () {
throw new Error(`not implemented for transports [${this.transportProtocols.join(', ')}]`);
});
}
}
//# sourceMappingURL=rpc-client.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"rpc-client.js","sourceRoot":"","sources":["../../src/rpc-client.ts"],"names":[],"mappings":"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"}
+228
View File
@@ -0,0 +1,228 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import ms from 'ms';
import { Convert, NodeStream, TtlCache } from '@web5/common';
import { TENANT_SEPARATOR } from './utils-internal.js';
import { getDataStoreTenant } from './utils-internal.js';
import { DwnInterface } from './types/dwn.js';
export class DwnDataStore {
constructor() {
this.name = 'DwnDataStore';
/**
* Cache of Store Objects referenced by DWN record ID to Store Objects.
*
* Up to 100 entries are retained for 15 minutes.
*/
this._cache = new TtlCache({ ttl: ms('15 minutes'), max: 100 });
/**
* Index for mappings from Store Identifier to DWN record ID.
*
* Up to 1,000 entries are retained for 2 hours.
*/
this._index = new TtlCache({ ttl: ms('2 hours'), max: 1000 });
/**
* Properties to use when writing and querying records with the DWN store.
*/
this._recordProperties = {
dataFormat: 'application/json',
schema: 'https://identity.foundation/schemas/web5/private-jwk'
};
}
delete({ id, agent, tenant }) {
return __awaiter(this, void 0, void 0, function* () {
// Determine the tenant identifier (DID) for the delete operation.
const tenantDid = yield getDataStoreTenant({ agent, tenant, didUri: id });
// Look up the DWN record ID of the object in the store with the given `id`.
let matchingRecordId = yield this.lookupRecordId({ id, tenantDid, agent });
// Return false if the given ID was not found in the store.
if (!matchingRecordId)
return false;
// If a record for the given ID was found, attempt to delete it.
const { reply: { status } } = yield agent.dwn.processRequest({
author: tenantDid,
target: tenantDid,
messageType: DwnInterface.RecordsDelete,
messageParams: { recordId: matchingRecordId }
});
// If the record was successfully deleted, update the index/cache and return true;
if (status.code === 202) {
this._index.delete(`${tenantDid}${TENANT_SEPARATOR}${id}`);
this._cache.delete(matchingRecordId);
return true;
}
// If the Delete operation failed, throw an error.
throw new Error(`${this.name}: Failed to delete '${id}' from store: (${status.code}) ${status.detail}`);
});
}
get({ id, agent, tenant, useCache = false }) {
return __awaiter(this, void 0, void 0, function* () {
// Determine the tenant identifier (DID) for the list operation.
const tenantDid = yield getDataStoreTenant({ agent, tenant, didUri: id });
// Look up the DWN record ID of the object in the store with the given `id`.
let matchingRecordId = yield this.lookupRecordId({ id, tenantDid, agent });
// Return undefined if no matches were found.
if (!matchingRecordId)
return undefined;
// Retrieve and return the stored object.
return yield this.getRecord({ recordId: matchingRecordId, tenantDid, agent, useCache });
});
}
list({ agent, tenant }) {
return __awaiter(this, void 0, void 0, function* () {
// Determine the tenant identifier (DID) for the list operation.
const tenantDid = yield getDataStoreTenant({ tenant, agent });
// Query the DWN for all stored record objects.
const storedRecords = yield this.getAllRecords({ agent, tenantDid });
return storedRecords;
});
}
set({ id, data, tenant, agent, preventDuplicates = true, useCache = false }) {
return __awaiter(this, void 0, void 0, function* () {
// Determine the tenant identifier (DID) for the set operation.
const tenantDid = yield getDataStoreTenant({ agent, tenant, didUri: id });
// If enabled, check if a record with the given `id` is already present in the store.
if (preventDuplicates) {
// Look up the DWN record ID of the object in the store with the given `id`.
const matchingRecordId = yield this.lookupRecordId({ id, tenantDid, agent });
if (matchingRecordId) {
throw new Error(`${this.name}: Import failed due to duplicate entry for: ${id}`);
}
}
// Convert the store object to a byte array, which will be the data payload of the DWN record.
const dataBytes = Convert.object(data).toUint8Array();
// Store the record in the DWN.
const { message, reply: { status } } = yield agent.dwn.processRequest({
author: tenantDid,
target: tenantDid,
messageType: DwnInterface.RecordsWrite,
messageParams: Object.assign({}, this._recordProperties),
dataStream: new Blob([dataBytes], { type: 'application/json' })
});
// If the write fails, throw an error.
if (!(message && status.code === 202)) {
throw new Error(`${this.name}: Failed to write data to store for: ${id}`);
}
// Add the ID of the newly created record to the index.
this._index.set(`${tenantDid}${TENANT_SEPARATOR}${id}`, message.recordId);
// If caching is enabled, add the store object to the cache.
if (useCache) {
this._cache.set(message.recordId, data);
}
});
}
getAllRecords(_params) {
return __awaiter(this, void 0, void 0, function* () {
throw new Error('Not implemented: Classes extending DwnDataStore must implement getAllRecords()');
});
}
getRecord({ recordId, tenantDid, agent, useCache }) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
// If caching is enabled, check the cache for the record ID.
if (useCache) {
const record = this._cache.get(recordId);
// If the record ID was present in the cache, return the associated store object.
if (record)
return record;
// Otherwise, continue to read from the store.
}
// Read the record from the store.
const { reply: readReply } = yield agent.dwn.processRequest({
author: tenantDid,
target: tenantDid,
messageType: DwnInterface.RecordsRead,
messageParams: { filter: { recordId } }
});
if (!((_a = readReply.record) === null || _a === void 0 ? void 0 : _a.data)) {
throw new Error(`${this.name}: Failed to read data from DWN for: ${recordId}`);
}
// If the record was found, convert back to store object format.
const storeObject = yield NodeStream.consumeToJson({ readable: readReply.record.data });
// If caching is enabled, add the store object to the cache.
if (useCache) {
this._cache.set(recordId, storeObject);
}
return storeObject;
});
}
lookupRecordId({ id, tenantDid, agent }) {
return __awaiter(this, void 0, void 0, function* () {
// Check the index for a matching ID and extend the index TTL.
let recordId = this._index.get(`${tenantDid}${TENANT_SEPARATOR}${id}`, { updateAgeOnGet: true });
// If no matching record ID was found in the index...
if (!recordId) {
// Query the DWN for all stored objects, which rebuilds the index.
yield this.getAllRecords({ agent, tenantDid });
// Check the index again for a matching ID.
recordId = this._index.get(`${tenantDid}${TENANT_SEPARATOR}${id}`);
}
return recordId;
});
}
}
export class InMemoryDataStore {
constructor() {
this.name = 'InMemoryDataStore';
/**
* A private field that contains the Map used as the in-memory data store.
*/
this.store = new Map();
}
delete({ id, agent, tenant }) {
return __awaiter(this, void 0, void 0, function* () {
// Determine the tenant identifier (DID) for the delete operation.
const tenantDid = yield getDataStoreTenant({ agent, tenant, didUri: id });
if (this.store.has(`${tenantDid}${TENANT_SEPARATOR}${id}`)) {
// Record with given identifier exists so proceed with delete.
this.store.delete(`${tenantDid}${TENANT_SEPARATOR}${id}`);
return true;
}
// Record with given identifier not present so delete operation not possible.
return false;
});
}
get({ id, agent, tenant }) {
return __awaiter(this, void 0, void 0, function* () {
// Determine the tenant identifier (DID) for the get operation.
const tenantDid = yield getDataStoreTenant({ agent, tenant, didUri: id });
return this.store.get(`${tenantDid}${TENANT_SEPARATOR}${id}`);
});
}
list({ agent, tenant }) {
return __awaiter(this, void 0, void 0, function* () {
// Determine the tenant identifier (DID) for the list operation.
const tenantDid = yield getDataStoreTenant({ tenant, agent });
const result = [];
for (const [key, storedRecord] of this.store.entries()) {
if (key.startsWith(`${tenantDid}${TENANT_SEPARATOR}`)) {
result.push(storedRecord);
}
}
return result;
});
}
set({ id, data, tenant, agent, preventDuplicates }) {
return __awaiter(this, void 0, void 0, function* () {
// Determine the tenant identifier (DID) for the set operation.
const tenantDid = yield getDataStoreTenant({ agent, tenant, didUri: id });
// If enabled, check if a record with the given `id` is already present in the store.
if (preventDuplicates) {
const duplicateFound = this.store.has(`${tenantDid}${TENANT_SEPARATOR}${id}`);
if (duplicateFound) {
throw new Error(`${this.name}: Import failed due to duplicate entry for: ${id}`);
}
}
// Make a deep copy so that the object stored does not share the same references as the input.
const clonedData = structuredClone(data);
this.store.set(`${tenantDid}${TENANT_SEPARATOR}${id}`, clonedData);
});
}
}
//# sourceMappingURL=store-data.js.map
File diff suppressed because one or more lines are too long
+132
View File
@@ -0,0 +1,132 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { Convert } from '@web5/common';
import { TENANT_SEPARATOR } from './utils-internal.js';
import { DwnInterface } from './types/dwn.js';
import { isPortableDid } from './prototyping/dids/utils.js';
import { DwnDataStore, InMemoryDataStore } from './store-data.js';
export class DwnDidStore extends DwnDataStore {
constructor() {
super(...arguments);
this.name = 'DwnDidStore';
/**
* Properties to use when writing and querying DID records with the DWN store.
*/
this._recordProperties = {
dataFormat: 'application/json',
schema: 'https://identity.foundation/schemas/web5/portable-did'
};
}
delete(params) {
const _super = Object.create(null, {
delete: { get: () => super.delete }
});
return __awaiter(this, void 0, void 0, function* () {
return yield _super.delete.call(this, params);
});
}
get(params) {
const _super = Object.create(null, {
get: { get: () => super.get }
});
return __awaiter(this, void 0, void 0, function* () {
return yield _super.get.call(this, params);
});
}
list(params) {
const _super = Object.create(null, {
list: { get: () => super.list }
});
return __awaiter(this, void 0, void 0, function* () {
return yield _super.list.call(this, params);
});
}
set(params) {
const _super = Object.create(null, {
set: { get: () => super.set }
});
return __awaiter(this, void 0, void 0, function* () {
return yield _super.set.call(this, params);
});
}
getAllRecords({ agent, tenantDid }) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
// Clear the index since it will be rebuilt from the query results.
this._index.clear();
// Query the DWN for all stored PortableDid objects.
const { reply: queryReply } = yield agent.dwn.processRequest({
author: tenantDid,
target: tenantDid,
messageType: DwnInterface.RecordsQuery,
messageParams: { filter: Object.assign({}, this._recordProperties) }
});
// Loop through all of the stored DID records and accumulate the DID objects.
let storedDids = [];
for (const record of (_a = queryReply.entries) !== null && _a !== void 0 ? _a : []) {
// All DID records are expected to be small enough such that the data is returned with the
// query results. If a record is returned without `encodedData` this is unexpected so throw
// an error.
if (!record.encodedData) {
throw new Error(`${this.name}: Expected 'encodedData' to be present in the DWN query result entry`);
}
const storedDid = Convert.base64Url(record.encodedData).toObject();
if (isPortableDid(storedDid)) {
// Update the index with the matching record ID.
const indexKey = `${tenantDid}${TENANT_SEPARATOR}${storedDid.uri}`;
this._index.set(indexKey, record.recordId);
// Add the stored DID to the cache.
this._cache.set(record.recordId, storedDid);
storedDids.push(storedDid);
}
}
return storedDids;
});
}
}
export class InMemoryDidStore extends InMemoryDataStore {
constructor() {
super(...arguments);
this.name = 'InMemoryDidStore';
}
delete(params) {
const _super = Object.create(null, {
delete: { get: () => super.delete }
});
return __awaiter(this, void 0, void 0, function* () {
return yield _super.delete.call(this, params);
});
}
get(params) {
const _super = Object.create(null, {
get: { get: () => super.get }
});
return __awaiter(this, void 0, void 0, function* () {
return yield _super.get.call(this, params);
});
}
list(params) {
const _super = Object.create(null, {
list: { get: () => super.list }
});
return __awaiter(this, void 0, void 0, function* () {
return yield _super.list.call(this, params);
});
}
set(params) {
const _super = Object.create(null, {
set: { get: () => super.set }
});
return __awaiter(this, void 0, void 0, function* () {
return yield _super.set.call(this, params);
});
}
}
//# sourceMappingURL=store-did.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"store-did.js","sourceRoot":"","sources":["../../src/store-did.ts"],"names":[],"mappings":"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"}
+136
View File
@@ -0,0 +1,136 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { Convert } from '@web5/common';
import { TENANT_SEPARATOR } from './utils-internal.js';
import { DwnInterface } from './types/dwn.js';
import { DwnDataStore, InMemoryDataStore } from './store-data.js';
export function isIdentityMetadata(obj) {
// Validate that the given value is an object that has the necessary properties of IdentityMetadata.
return !(!obj || typeof obj !== 'object' || obj === null)
&& 'name' in obj;
}
export class DwnIdentityStore extends DwnDataStore {
constructor() {
super(...arguments);
this.name = 'DwnIdentityStore';
/**
* Properties to use when writing and querying Identity records with the DWN store.
*/
this._recordProperties = {
dataFormat: 'application/json',
schema: 'https://identity.foundation/schemas/web5/identity-metadata'
};
}
delete(params) {
const _super = Object.create(null, {
delete: { get: () => super.delete }
});
return __awaiter(this, void 0, void 0, function* () {
return yield _super.delete.call(this, params);
});
}
get(params) {
const _super = Object.create(null, {
get: { get: () => super.get }
});
return __awaiter(this, void 0, void 0, function* () {
return yield _super.get.call(this, params);
});
}
set(params) {
const _super = Object.create(null, {
set: { get: () => super.set }
});
return __awaiter(this, void 0, void 0, function* () {
return yield _super.set.call(this, params);
});
}
list(params) {
const _super = Object.create(null, {
list: { get: () => super.list }
});
return __awaiter(this, void 0, void 0, function* () {
return yield _super.list.call(this, params);
});
}
getAllRecords({ agent, tenantDid }) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
// Clear the index since it will be rebuilt from the query results.
this._index.clear();
// Query the DWN for all stored IdentityMetadata objects.
const { reply: queryReply } = yield agent.dwn.processRequest({
author: tenantDid,
target: tenantDid,
messageType: DwnInterface.RecordsQuery,
messageParams: { filter: Object.assign({}, this._recordProperties) }
});
// Loop through all of the stored IdentityMetadata records and accumulate the objects.
let storedIdentities = [];
for (const record of (_a = queryReply.entries) !== null && _a !== void 0 ? _a : []) {
// All IdentityMetadata records are expected to be small enough such that the data is returned
// with the query results. If a record is returned without `encodedData` this is unexpected so
// throw an error.
if (!record.encodedData) {
throw new Error(`${this.name}: Expected 'encodedData' to be present in the DWN query result entry`);
}
const storedIdentity = Convert.base64Url(record.encodedData).toObject();
if (isIdentityMetadata(storedIdentity)) {
// Update the index with the matching record ID.
const indexKey = `${tenantDid}${TENANT_SEPARATOR}${storedIdentity.uri}`;
this._index.set(indexKey, record.recordId);
// Add the stored Identity to the cache.
this._cache.set(record.recordId, storedIdentity);
storedIdentities.push(storedIdentity);
}
}
return storedIdentities;
});
}
}
export class InMemoryIdentityStore extends InMemoryDataStore {
constructor() {
super(...arguments);
this.name = 'InMemoryIdentityStore';
}
delete(params) {
const _super = Object.create(null, {
delete: { get: () => super.delete }
});
return __awaiter(this, void 0, void 0, function* () {
return yield _super.delete.call(this, params);
});
}
get(params) {
const _super = Object.create(null, {
get: { get: () => super.get }
});
return __awaiter(this, void 0, void 0, function* () {
return yield _super.get.call(this, params);
});
}
list(params) {
const _super = Object.create(null, {
list: { get: () => super.list }
});
return __awaiter(this, void 0, void 0, function* () {
return yield _super.list.call(this, params);
});
}
set(params) {
const _super = Object.create(null, {
set: { get: () => super.set }
});
return __awaiter(this, void 0, void 0, function* () {
return yield _super.set.call(this, params);
});
}
}
//# sourceMappingURL=store-identity.js.map
@@ -0,0 +1 @@
{"version":3,"file":"store-identity.js","sourceRoot":"","sources":["../../src/store-identity.ts"],"names":[],"mappings":"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"}
+132
View File
@@ -0,0 +1,132 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { KEY_URI_PREFIX_JWK, isPrivateJwk } from '@web5/crypto';
import { Convert } from '@web5/common';
import { TENANT_SEPARATOR } from './utils-internal.js';
import { DwnInterface } from './types/dwn.js';
import { DwnDataStore, InMemoryDataStore } from './store-data.js';
export class DwnKeyStore extends DwnDataStore {
constructor() {
super(...arguments);
this.name = 'DwnKeyStore';
/**
* Properties to use when writing and querying Private Key records with the DWN store.
*/
this._recordProperties = {
dataFormat: 'application/json',
schema: 'https://identity.foundation/schemas/web5/private-jwk'
};
}
delete(params) {
const _super = Object.create(null, {
delete: { get: () => super.delete }
});
return __awaiter(this, void 0, void 0, function* () {
return yield _super.delete.call(this, params);
});
}
get(params) {
const _super = Object.create(null, {
get: { get: () => super.get }
});
return __awaiter(this, void 0, void 0, function* () {
return yield _super.get.call(this, params);
});
}
set(params) {
const _super = Object.create(null, {
set: { get: () => super.set }
});
return __awaiter(this, void 0, void 0, function* () {
yield _super.set.call(this, params);
});
}
list(params) {
const _super = Object.create(null, {
list: { get: () => super.list }
});
return __awaiter(this, void 0, void 0, function* () {
return yield _super.list.call(this, params);
});
}
getAllRecords({ agent, tenantDid }) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
// Clear the index since it will be rebuilt from the query results.
this._index.clear();
// Query the DWN for all stored Jwk objects.
const { reply: queryReply } = yield agent.dwn.processRequest({
author: tenantDid,
target: tenantDid,
messageType: DwnInterface.RecordsQuery,
messageParams: { filter: Object.assign({}, this._recordProperties) }
});
// Loop through all of the stored Jwk records and accumulate the objects.
let storedKeys = [];
for (const record of (_a = queryReply.entries) !== null && _a !== void 0 ? _a : []) {
// All Jwk records are expected to be small enough such that the data is returned
// with the query results. If a record is returned without `encodedData` this is unexpected so
// throw an error.
if (!record.encodedData) {
throw new Error(`${this.name}: Expected 'encodedData' to be present in the DWN query result entry`);
}
const storedKey = Convert.base64Url(record.encodedData).toObject();
if (isPrivateJwk(storedKey)) {
// Update the index with the matching record ID.
const indexKey = `${tenantDid}${TENANT_SEPARATOR}${KEY_URI_PREFIX_JWK}${storedKey.kid}`;
this._index.set(indexKey, record.recordId);
// Add the stored key to the cache.
this._cache.set(record.recordId, storedKey);
storedKeys.push(storedKey);
}
}
return storedKeys;
});
}
}
export class InMemoryKeyStore extends InMemoryDataStore {
constructor() {
super(...arguments);
this.name = 'InMemoryKeyStore';
}
delete(params) {
const _super = Object.create(null, {
delete: { get: () => super.delete }
});
return __awaiter(this, void 0, void 0, function* () {
return yield _super.delete.call(this, params);
});
}
get(params) {
const _super = Object.create(null, {
get: { get: () => super.get }
});
return __awaiter(this, void 0, void 0, function* () {
return yield _super.get.call(this, params);
});
}
list(params) {
const _super = Object.create(null, {
list: { get: () => super.list }
});
return __awaiter(this, void 0, void 0, function* () {
return yield _super.list.call(this, params);
});
}
set(params) {
const _super = Object.create(null, {
set: { get: () => super.set }
});
return __awaiter(this, void 0, void 0, function* () {
return yield _super.set.call(this, params);
});
}
}
//# sourceMappingURL=store-key.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"store-key.js","sourceRoot":"","sources":["../../src/store-key.ts"],"names":[],"mappings":"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"}
+43
View File
@@ -0,0 +1,43 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
export class AgentSyncApi {
constructor({ agent, syncEngine }) {
this._syncEngine = syncEngine;
this._agent = agent;
}
/**
* Retrieves the `Web5PlatformAgent` execution context.
*
* @returns The `Web5PlatformAgent` instance that represents the current execution context.
* @throws Will throw an error if the `agent` instance property is undefined.
*/
get agent() {
if (this._agent === undefined) {
throw new Error('AgentSyncApi: Unable to determine agent execution context.');
}
return this._agent;
}
set agent(agent) {
this._agent = agent;
this._syncEngine.agent = agent;
}
registerIdentity(params) {
return __awaiter(this, void 0, void 0, function* () {
yield this._syncEngine.registerIdentity(params);
});
}
startSync(params) {
return this._syncEngine.startSync(params);
}
stopSync() {
this._syncEngine.stopSync();
}
}
//# sourceMappingURL=sync-api.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"sync-api.js","sourceRoot":"","sources":["../../src/sync-api.ts"],"names":[],"mappings":";;;;;;;;;AAQA,MAAM,OAAO,YAAY;IAWvB,YAAY,EAAE,KAAK,EAAE,UAAU,EAAiB;QAC9C,IAAI,CAAC,WAAW,GAAG,UAAU,CAAC;QAC9B,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;IACtB,CAAC;IAED;;;;;OAKG;IACH,IAAI,KAAK;QACP,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS,EAAE;YAC7B,MAAM,IAAI,KAAK,CAAC,4DAA4D,CAAC,CAAC;SAC/E;QAED,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;IAED,IAAI,KAAK,CAAC,KAAwB;QAChC,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;QACpB,IAAI,CAAC,WAAW,CAAC,KAAK,GAAG,KAAK,CAAC;IACjC,CAAC;IAEY,gBAAgB,CAAC,MAAwB;;YACpD,MAAM,IAAI,CAAC,WAAW,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC;QAClD,CAAC;KAAA;IAEM,SAAS,CAAC,MAA6B;QAC5C,OAAO,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAC5C,CAAC;IAEM,QAAQ;QACb,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE,CAAC;IAC9B,CAAC;CACF"}

Some files were not shown because too many files have changed in this diff Show More