anon-identity
Version:
Decentralized identity framework with DIDs, Verifiable Credentials, and privacy-preserving selective disclosure
136 lines • 5.83 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.ServiceProviderV2 = void 0;
const service_provider_1 = require("./service-provider");
const vc2_1 = require("../types/vc2");
const credential_status_1 = require("../status/credential-status");
const verification_errors_1 = require("./verification-errors");
/**
* Enhanced Service Provider with W3C VC 2.0 support
*/
class ServiceProviderV2 extends service_provider_1.ServiceProvider {
constructor(name, trustedIssuers = [], options = {}) {
super(name, trustedIssuers, options);
this.statusCache = new Map();
this.checkCredentialStatus = options.checkCredentialStatus ?? true;
this.statusChecker = options.statusChecker || new credential_status_1.CompositeStatusChecker();
this.statusCacheTTL = (options.statusCacheTTL || 300) * 1000; // Convert to milliseconds
}
/**
* Verify a presentation that may contain VC 2.0 credentials
*/
async verifyPresentationV2(presentation) {
// First, perform standard verification
const baseResult = await super.verifyPresentation(presentation);
// If base verification failed, return immediately
if (!baseResult.valid) {
return baseResult;
}
// Now check credential status for V2 credentials
if (this.checkCredentialStatus && presentation.verifiableCredential) {
const additionalErrors = [];
for (const credential of presentation.verifiableCredential) {
if (typeof credential === 'string')
continue;
// Check if this is a V2 credential with status
if ((0, vc2_1.isVerifiableCredentialV2)(credential) && credential.credentialStatus) {
const statusResult = await this.checkCredentialStatusWithCache(credential.id || 'unknown', credential.credentialStatus);
if (statusResult.revoked) {
additionalErrors.push(verification_errors_1.VerificationError.revokedCredential(credential.id || 'unknown', typeof credential.issuer === 'string'
? credential.issuer
: credential.issuer.id));
}
if (statusResult.suspended) {
additionalErrors.push(new verification_errors_1.VerificationError(verification_errors_1.VerificationErrorCode.CREDENTIAL_SUSPENDED, `Credential ${credential.id} is suspended: ${statusResult.reason || 'No reason provided'}`, { credentialId: credential.id, reason: statusResult.reason }));
}
}
}
// If we found status issues, update the result
if (additionalErrors.length > 0) {
return {
...baseResult,
valid: false,
errors: [...(baseResult.errors || []), ...additionalErrors]
};
}
}
return baseResult;
}
/**
* Check credential status with caching
*/
async checkCredentialStatusWithCache(credentialId, statusInfo) {
const statusArray = Array.isArray(statusInfo) ? statusInfo : [statusInfo];
// Check each status (a credential might have multiple status entries)
for (const status of statusArray) {
const cacheKey = `${credentialId}:${status.id}`;
// Check cache first
const cached = this.statusCache.get(cacheKey);
if (cached && cached.expires > Date.now()) {
return cached.result;
}
// Perform status check
try {
const result = await this.statusChecker.checkStatus(credentialId, status);
// Cache the result
this.statusCache.set(cacheKey, {
result,
expires: Date.now() + this.statusCacheTTL
});
// If revoked or suspended, return immediately
if (result.revoked || result.suspended) {
return result;
}
}
catch (error) {
console.warn(`Failed to check credential status: ${error}`);
// On error, assume credential is valid (fail open)
return {
revoked: false,
checkedAt: new Date().toISOString()
};
}
}
// If all status checks passed, return not revoked
return {
revoked: false,
checkedAt: new Date().toISOString()
};
}
/**
* Load a revocation list into the status checker
*/
async loadRevocationList(listId, list) {
const checker = this.statusChecker['checkers'].get('RevocationList2020');
if (checker instanceof credential_status_1.RevocationList2020StatusChecker) {
checker.addRevocationList(listId, list);
}
}
/**
* Load a status list credential into the status checker
*/
async loadStatusListCredential(credential) {
const checker = this.statusChecker['checkers'].get('StatusList2021');
if (checker instanceof credential_status_1.StatusList2021StatusChecker) {
await checker.loadStatusListCredential(credential);
}
}
/**
* Clear the status cache
*/
clearStatusCache() {
this.statusCache.clear();
}
/**
* Get cache statistics
*/
getStatusCacheStats() {
return {
size: this.statusCache.size,
hits: 0, // Would need to track this
misses: 0 // Would need to track this
};
}
}
exports.ServiceProviderV2 = ServiceProviderV2;
//# sourceMappingURL=service-provider-v2.js.map