@credo-ts/core
Version:
<p align="center"> <br /> <img alt="Credo Logo" src="https://github.com/openwallet-foundation/credo-ts/blob/c7886cb8377ceb8ee4efe8d264211e561a75072d/images/credo-logo.png" height="250px" /> </p> <h1 align="center"><b>Credo - Core</b></h1
117 lines (113 loc) • 8.07 kB
JavaScript
import { CredoError } from "../error/CredoError.mjs";
import "../agent/index.mjs";
import { CredentialMultiInstanceState, CredentialMultiInstanceUseMode, CredentialMultiInstanceUseUpdateMode } from "./credentialUseTypes.mjs";
import { W3cJsonLdVerifiableCredential } from "../modules/vc/data-integrity/models/W3cJsonLdVerifiableCredential.mjs";
import { W3cV2JwtVerifiableCredential } from "../modules/vc/jwt-vc/W3cV2JwtVerifiableCredential.mjs";
import { W3cV2SdJwtVerifiableCredential } from "../modules/vc/sd-jwt-vc/W3cV2SdJwtVerifiableCredential.mjs";
import { W3cJwtVerifiableCredential } from "../modules/vc/jwt-vc/W3cJwtVerifiableCredential.mjs";
import { W3cCredentialRecord } from "../modules/vc/repository/W3cCredentialRecord.mjs";
import { W3cCredentialRepository } from "../modules/vc/repository/W3cCredentialRepository.mjs";
import { W3cV2CredentialRecord } from "../modules/vc/repository/W3cV2CredentialRecord.mjs";
import { W3cV2CredentialRepository } from "../modules/vc/repository/W3cV2CredentialRepository.mjs";
import "../modules/vc/repository/index.mjs";
import "../modules/vc/index.mjs";
import { Mdoc } from "../modules/mdoc/Mdoc.mjs";
import { MdocRecord } from "../modules/mdoc/repository/MdocRecord.mjs";
import { MdocRepository } from "../modules/mdoc/repository/MdocRepository.mjs";
import "../modules/mdoc/repository/index.mjs";
import { decodeSdJwtVc } from "../modules/sd-jwt-vc/decodeSdJwtVc.mjs";
import { SdJwtVcRecord } from "../modules/sd-jwt-vc/repository/SdJwtVcRecord.mjs";
import { SdJwtVcRepository } from "../modules/sd-jwt-vc/repository/SdJwtVcRepository.mjs";
import "../modules/sd-jwt-vc/repository/index.mjs";
//#region src/utils/credentialUse.ts
/**
* Checks whether an instance can be used from the provided record based on
* the required credential use mode.
*/
function canUseInstanceFromCredentialRecord({ credentialRecord, useMode }) {
if (useMode === CredentialMultiInstanceUseMode.First || useMode === CredentialMultiInstanceUseMode.NewOrFirst || useMode === CredentialMultiInstanceUseMode.NewIfReceivedInBatch && [CredentialMultiInstanceState.SingleInstanceUnused, CredentialMultiInstanceState.SingleInstanceUsed].includes(credentialRecord.multiInstanceState)) return true;
return credentialRecord.multiInstanceState === CredentialMultiInstanceState.MultiInstanceFirstUnused || credentialRecord.multiInstanceState === CredentialMultiInstanceState.SingleInstanceUnused;
}
/**
* Extract an instance with the correct kms key id from the credential instances
* on the record. Note that if an instance is extracted (that is not reused) it
* will remove the instance from the record, and the record should be updated in
* storage after usage.
*
* Note that the last credential instance is never removed from the record. So if the
* method indicates the last instance has been used, you should remove the credential
* from storage if you don't want it to be used anymore in the future.
*/
async function useInstanceFromCredentialRecord({ credentialRecord, useMode, agentContext, updateMode }) {
let extractResult = extractInstanceAndUpdateRecord({
credentialRecord,
useMode
});
if ((!extractResult.isReused || extractResult.isLastNewInstance) && updateMode === CredentialMultiInstanceUseUpdateMode.Update) await updateCredentialRecord(agentContext, credentialRecord);
if ((!extractResult.isReused || extractResult.isLastNewInstance) && updateMode === CredentialMultiInstanceUseUpdateMode.RefetchAndUpdateWithLock) await repositoryForRecord(agentContext, credentialRecord).updateByIdWithLock(agentContext, credentialRecord.id, async (freshCredentialRecord) => {
extractResult = extractInstanceAndUpdateRecord({
credentialRecord: freshCredentialRecord,
useMode
});
return freshCredentialRecord;
});
let transformedCredentialInstance;
if (credentialRecord instanceof MdocRecord) {
const { issuerSignedBase64Url, kmsKeyId } = extractResult.credentialInstance;
transformedCredentialInstance = Mdoc.fromBase64Url(issuerSignedBase64Url);
transformedCredentialInstance.deviceKeyId = kmsKeyId ?? transformedCredentialInstance.deviceKey.legacyKeyId;
} else if (credentialRecord instanceof SdJwtVcRecord) {
const { compactSdJwtVc, kmsKeyId } = extractResult.credentialInstance;
transformedCredentialInstance = {
...decodeSdJwtVc(compactSdJwtVc, credentialRecord.typeMetadata),
kmsKeyId
};
} else if (credentialRecord instanceof W3cCredentialRecord) {
const { credential } = extractResult.credentialInstance;
transformedCredentialInstance = typeof credential === "string" ? W3cJwtVerifiableCredential.fromSerializedJwt(credential) : W3cJsonLdVerifiableCredential.fromJson(credential);
} else if (credentialRecord instanceof W3cV2CredentialRecord) {
const { credential } = extractResult.credentialInstance;
transformedCredentialInstance = credential.includes("~") ? W3cV2SdJwtVerifiableCredential.fromCompact(credential) : W3cV2JwtVerifiableCredential.fromCompact(credential);
} else throw new CredoError("Unsupported record type");
return {
credentialInstance: transformedCredentialInstance,
isReused: extractResult.isReused,
isLastNewInstance: extractResult.isLastNewInstance
};
}
function extractInstanceAndUpdateRecord({ credentialRecord, useMode }) {
if (credentialRecord.credentialInstances.length === 1 || useMode === CredentialMultiInstanceUseMode.First) {
const isFirstUnused = credentialRecord.multiInstanceState === CredentialMultiInstanceState.MultiInstanceFirstUnused || credentialRecord.multiInstanceState === CredentialMultiInstanceState.SingleInstanceUnused;
const isMultiInstance = credentialRecord.multiInstanceState === CredentialMultiInstanceState.MultiInstanceFirstUnused || credentialRecord.multiInstanceState === CredentialMultiInstanceState.MultiInstanceFirstUsed;
const allowsReuse = useMode === CredentialMultiInstanceUseMode.New ? false : useMode === CredentialMultiInstanceUseMode.NewIfReceivedInBatch ? !isMultiInstance : true;
if (isFirstUnused) credentialRecord.multiInstanceState = credentialRecord.multiInstanceState === CredentialMultiInstanceState.SingleInstanceUnused ? CredentialMultiInstanceState.SingleInstanceUsed : CredentialMultiInstanceState.MultiInstanceFirstUsed;
else if (!allowsReuse) throw new CredoError(`Unable to extract new credential instance from ${credentialRecord.type} with id '${credentialRecord.id}', since it only contains a single credential instance but using a new instance is required due to use mode '${useMode}'.`);
return {
isReused: !isFirstUnused,
credentialInstance: credentialRecord.credentialInstances[0],
isLastNewInstance: isFirstUnused
};
}
const _credentialInstance = credentialRecord.credentialInstances.pop();
if (!_credentialInstance) throw new CredoError(`Unable to extract credential instance from ${credentialRecord.type} with id '${credentialRecord.id}', since the credential record does not contain any credential instances.`);
return {
credentialInstance: _credentialInstance,
isReused: false,
isLastNewInstance: false
};
}
function repositoryForRecord(agentContext, record) {
if (record instanceof W3cCredentialRecord) return agentContext.resolve(W3cCredentialRepository);
if (record instanceof W3cV2CredentialRecord) return agentContext.resolve(W3cV2CredentialRepository);
if (record instanceof MdocRecord) return agentContext.resolve(MdocRepository);
return agentContext.resolve(SdJwtVcRepository);
}
function updateCredentialRecord(agentContext, record) {
if (record instanceof W3cCredentialRecord) return agentContext.resolve(W3cCredentialRepository).update(agentContext, record);
if (record instanceof W3cV2CredentialRecord) return agentContext.resolve(W3cV2CredentialRepository).update(agentContext, record);
if (record instanceof MdocRecord) return agentContext.resolve(MdocRepository).update(agentContext, record);
return agentContext.resolve(SdJwtVcRepository).update(agentContext, record);
}
//#endregion
export { canUseInstanceFromCredentialRecord, useInstanceFromCredentialRecord };
//# sourceMappingURL=credentialUse.mjs.map