UNPKG

anon-identity

Version:

Decentralized identity framework with DIDs, Verifiable Credentials, and privacy-preserving selective disclosure

136 lines 5.83 kB
"use strict"; 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