UNPKG

anon-identity

Version:

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

250 lines 9.24 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.defaultJsonLdProcessor = exports.JsonLdProcessor = void 0; const jsonld = __importStar(require("jsonld")); const context_loader_1 = require("./context-loader"); /** * JSON-LD Processor for Verifiable Credentials */ class JsonLdProcessor { constructor(options = {}) { this.contextLoader = options.contextLoader || context_loader_1.defaultContextLoader; this.documentLoader = this.contextLoader.createDocumentLoader(); this.safeMode = options.safeMode ?? true; this.validateContexts = options.validateContexts ?? true; } /** * Expand a JSON-LD document */ async expand(document) { try { const expanded = await jsonld.expand(document, { documentLoader: this.documentLoader }); return expanded; } catch (error) { throw new Error(`JSON-LD expansion failed: ${error}`); } } /** * Compact a JSON-LD document */ async compact(document, context) { try { const compacted = await jsonld.compact(document, context, { documentLoader: this.documentLoader }); return compacted; } catch (error) { throw new Error(`JSON-LD compaction failed: ${error}`); } } /** * Canonicalize a JSON-LD document for signing */ async canonicalize(document) { try { const canonicalized = await jsonld.canonize(document, { algorithm: 'URDNA2015', format: 'application/n-quads', documentLoader: this.documentLoader }); return canonicalized; } catch (error) { throw new Error(`JSON-LD canonicalization failed: ${error}`); } } /** * Frame a JSON-LD document */ async frame(document, frame) { try { const framed = await jsonld.frame(document, frame, { documentLoader: this.documentLoader }); return framed; } catch (error) { throw new Error(`JSON-LD framing failed: ${error}`); } } /** * Validate a credential's JSON-LD structure */ async validateCredential(credential) { const errors = []; try { // 1. Check that @context is present if (!credential['@context']) { errors.push('Missing @context property'); return { valid: false, errors }; } // 2. Expand the document to check for errors const expanded = await this.expand(credential); // 3. Check that required properties expanded correctly if (expanded.length === 0) { errors.push('Document expanded to empty array'); } // 4. Validate specific credential properties const expandedCred = expanded[0]; // Check for required credential properties const requiredProps = [ 'https://www.w3.org/2018/credentials#credentialSubject', 'https://www.w3.org/2018/credentials#issuer' ]; for (const prop of requiredProps) { if (!expandedCred[prop]) { errors.push(`Missing required property: ${prop}`); } } // 5. If proof exists, validate it expanded correctly if (credential.proof && !expandedCred['https://w3id.org/security#proof']) { errors.push('Proof property did not expand correctly'); } return { valid: errors.length === 0, errors: errors.length > 0 ? errors : undefined }; } catch (error) { errors.push(`JSON-LD processing error: ${error}`); return { valid: false, errors }; } } /** * Validate a presentation's JSON-LD structure */ async validatePresentation(presentation) { const errors = []; try { // 1. Check that @context is present if (!presentation['@context']) { errors.push('Missing @context property'); return { valid: false, errors }; } // 2. Expand the document const expanded = await this.expand(presentation); if (expanded.length === 0) { errors.push('Document expanded to empty array'); } // 3. Validate credentials if present if (presentation.verifiableCredential) { for (let i = 0; i < presentation.verifiableCredential.length; i++) { const cred = presentation.verifiableCredential[i]; if (typeof cred !== 'string') { const result = await this.validateCredential(cred); if (!result.valid) { errors.push(`Credential ${i}: ${result.errors?.join(', ')}`); } } } } return { valid: errors.length === 0, errors: errors.length > 0 ? errors : undefined }; } catch (error) { errors.push(`JSON-LD processing error: ${error}`); return { valid: false, errors }; } } /** * Normalize a document for comparison */ async normalize(document) { // First expand, then compact with a standard context const expanded = await this.expand(document); const context = document['@context'] || 'https://www.w3.org/ns/credentials/v2'; return await this.compact(expanded, context); } /** * Extract claims from an expanded credential */ async extractClaims(credential) { const claims = new Map(); try { const expanded = await this.expand(credential); if (expanded.length === 0) return claims; const expandedCred = expanded[0]; const subject = expandedCred['https://www.w3.org/2018/credentials#credentialSubject']; if (Array.isArray(subject)) { // Multiple subjects subject.forEach((subj, index) => { this.extractClaimsFromSubject(subj, claims, `subject${index}`); }); } else if (subject) { // Single subject this.extractClaimsFromSubject(subject, claims); } return claims; } catch (error) { throw new Error(`Failed to extract claims: ${error}`); } } /** * Extract claims from a subject object */ extractClaimsFromSubject(subject, claims, prefix = '') { for (const [key, value] of Object.entries(subject)) { if (key === '@id' || key === '@type') continue; const claimKey = prefix ? `${prefix}.${key}` : key; if (Array.isArray(value) && value.length > 0 && value[0] && typeof value[0] === 'object' && '@value' in value[0]) { // Literal value claims.set(claimKey, value[0]['@value']); } else if (value && typeof value === 'object' && '@value' in value) { // Single literal value claims.set(claimKey, value['@value']); } else { // Complex value or reference claims.set(claimKey, value); } } } } exports.JsonLdProcessor = JsonLdProcessor; // Default instance exports.defaultJsonLdProcessor = new JsonLdProcessor(); //# sourceMappingURL=jsonld-processor.js.map