UNPKG

anon-identity

Version:

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

401 lines 14.9 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.FileStorageProvider = void 0; const fs_1 = require("fs"); const path = __importStar(require("path")); const uuid_1 = require("uuid"); const crypto = __importStar(require("crypto")); class FileStorageProvider { constructor(dataPath, encryption = true, passphrase) { this.data = { dids: {}, credentials: {}, keyPairs: {}, revocationLists: {}, schemas: {}, phoneNumbers: {}, phoneNumbersByUser: {}, emailAddresses: {}, emailAddressesByUser: {}, addresses: {}, addressesByUser: {} }; this.dataPath = dataPath; this.encryption = encryption; if (encryption && passphrase) { // Derive encryption key from passphrase this.encryptionKey = crypto.scryptSync(passphrase, 'salt', 32); } } async ensureDirectory() { const dir = path.dirname(this.dataPath); try { await fs_1.promises.access(dir); } catch { await fs_1.promises.mkdir(dir, { recursive: true }); } } encrypt(data) { if (!this.encryption || !this.encryptionKey) return data; const iv = crypto.randomBytes(16); const cipher = crypto.createCipheriv('aes-256-gcm', this.encryptionKey, iv); let encrypted = cipher.update(data, 'utf8', 'hex'); encrypted += cipher.final('hex'); const authTag = cipher.getAuthTag(); return JSON.stringify({ encrypted, authTag: authTag.toString('hex'), iv: iv.toString('hex') }); } decrypt(encryptedData) { if (!this.encryption || !this.encryptionKey) return encryptedData; try { const { encrypted, authTag, iv } = JSON.parse(encryptedData); const decipher = crypto.createDecipheriv('aes-256-gcm', this.encryptionKey, Buffer.from(iv, 'hex')); decipher.setAuthTag(Buffer.from(authTag, 'hex')); let decrypted = decipher.update(encrypted, 'hex', 'utf8'); decrypted += decipher.final('utf8'); return decrypted; } catch (error) { throw new Error('Failed to decrypt data. Invalid passphrase or corrupted data.'); } } async load() { try { const rawData = await fs_1.promises.readFile(this.dataPath, 'utf8'); const decryptedData = this.decrypt(rawData); this.data = JSON.parse(decryptedData); } catch (error) { // File doesn't exist or is corrupted, start with empty data this.data = { dids: {}, credentials: {}, keyPairs: {}, revocationLists: {}, schemas: {}, phoneNumbers: {}, phoneNumbersByUser: {}, emailAddresses: {}, emailAddressesByUser: {}, addresses: {}, addressesByUser: {} }; } } async save() { await this.ensureDirectory(); const jsonData = JSON.stringify(this.data, null, 2); const dataToSave = this.encrypt(jsonData); await fs_1.promises.writeFile(this.dataPath, dataToSave, 'utf8'); } // DID Operations async storeDID(did, document) { await this.load(); this.data.dids[did] = document; await this.save(); } async resolveDID(did) { await this.load(); return this.data.dids[did] || null; } async listDIDs(owner) { await this.load(); const dids = Object.keys(this.data.dids); if (!owner) return dids; return dids.filter(did => { const doc = this.data.dids[did]; if (!doc || !doc.verificationMethod) return false; return doc.verificationMethod.some(vm => vm.controller === owner); }); } // Credential Operations async storeCredential(credential) { await this.load(); this.data.credentials[credential.id] = credential; await this.save(); } async getCredential(id) { await this.load(); return this.data.credentials[id] || null; } async listCredentials(holder) { await this.load(); return Object.values(this.data.credentials).filter(cred => cred.credentialSubject.id === holder); } async deleteCredential(id) { await this.load(); delete this.data.credentials[id]; await this.save(); } // Revocation Operations async publishRevocation(issuerDID, revocationList) { await this.load(); this.data.revocationLists[issuerDID] = revocationList; await this.save(); } async checkRevocation(issuerDID, credentialId) { await this.load(); const revocationList = this.data.revocationLists[issuerDID]; if (!revocationList) return false; return revocationList.revokedCredentialIds.includes(credentialId); } async getRevocationList(issuerDID) { await this.load(); return this.data.revocationLists[issuerDID] || null; } // Key Management async storeKeyPair(identifier, encryptedKeyPair) { await this.load(); this.data.keyPairs[identifier] = encryptedKeyPair; await this.save(); } async retrieveKeyPair(identifier) { await this.load(); return this.data.keyPairs[identifier] || null; } async deleteKeyPair(identifier) { await this.load(); delete this.data.keyPairs[identifier]; await this.save(); } // Schema Operations async registerSchema(schema) { await this.load(); const schemaId = schema.id || `schema:${(0, uuid_1.v4)()}`; const schemaWithId = { ...schema, id: schemaId }; this.data.schemas[schemaId] = schemaWithId; await this.save(); return schemaId; } async getSchema(schemaId) { await this.load(); return this.data.schemas[schemaId] || null; } async listSchemas(issuerDID) { await this.load(); const schemas = Object.values(this.data.schemas); if (!issuerDID) return schemas; return schemas.filter(schema => schema.issuerDID === issuerDID); } // Phone Number Operations async storePhoneNumber(userDID, phoneNumber) { await this.load(); const phoneId = phoneNumber.id || `phone:${(0, uuid_1.v4)()}`; const phoneWithId = { ...phoneNumber, id: phoneId }; this.data.phoneNumbers[phoneId] = phoneWithId; // Update user index if (!this.data.phoneNumbersByUser[userDID]) { this.data.phoneNumbersByUser[userDID] = []; } if (!this.data.phoneNumbersByUser[userDID].includes(phoneId)) { this.data.phoneNumbersByUser[userDID].push(phoneId); } await this.save(); return phoneId; } async getPhoneNumber(userDID, phoneId) { await this.load(); const userPhones = this.data.phoneNumbersByUser[userDID] || []; if (!userPhones.includes(phoneId)) { return null; } return this.data.phoneNumbers[phoneId] || null; } async listPhoneNumbers(userDID) { await this.load(); const phoneIds = this.data.phoneNumbersByUser[userDID] || []; return phoneIds .map(id => this.data.phoneNumbers[id]) .filter(phone => phone !== undefined); } async updatePhoneNumber(userDID, phoneId, phoneNumber) { await this.load(); const userPhones = this.data.phoneNumbersByUser[userDID] || []; if (!userPhones.includes(phoneId)) { throw new Error('Phone number not found'); } const existingPhone = this.data.phoneNumbers[phoneId]; if (existingPhone) { this.data.phoneNumbers[phoneId] = { ...existingPhone, ...phoneNumber, id: phoneId }; await this.save(); } } async deletePhoneNumber(userDID, phoneId) { await this.load(); const userPhones = this.data.phoneNumbersByUser[userDID] || []; this.data.phoneNumbersByUser[userDID] = userPhones.filter(id => id !== phoneId); if (this.data.phoneNumbersByUser[userDID].length === 0) { delete this.data.phoneNumbersByUser[userDID]; } delete this.data.phoneNumbers[phoneId]; await this.save(); } // Email Address Operations async storeEmailAddress(userDID, emailAddress) { await this.load(); const emailId = emailAddress.id || `email:${(0, uuid_1.v4)()}`; const emailWithId = { ...emailAddress, id: emailId }; this.data.emailAddresses[emailId] = emailWithId; // Update user index if (!this.data.emailAddressesByUser[userDID]) { this.data.emailAddressesByUser[userDID] = []; } if (!this.data.emailAddressesByUser[userDID].includes(emailId)) { this.data.emailAddressesByUser[userDID].push(emailId); } await this.save(); return emailId; } async getEmailAddress(userDID, emailId) { await this.load(); const userEmails = this.data.emailAddressesByUser[userDID] || []; if (!userEmails.includes(emailId)) { return null; } return this.data.emailAddresses[emailId] || null; } async listEmailAddresses(userDID) { await this.load(); const emailIds = this.data.emailAddressesByUser[userDID] || []; return emailIds .map(id => this.data.emailAddresses[id]) .filter(email => email !== undefined); } async updateEmailAddress(userDID, emailId, emailAddress) { await this.load(); const userEmails = this.data.emailAddressesByUser[userDID] || []; if (!userEmails.includes(emailId)) { throw new Error('Email address not found'); } const existingEmail = this.data.emailAddresses[emailId]; if (existingEmail) { this.data.emailAddresses[emailId] = { ...existingEmail, ...emailAddress, id: emailId }; await this.save(); } } async deleteEmailAddress(userDID, emailId) { await this.load(); const userEmails = this.data.emailAddressesByUser[userDID] || []; this.data.emailAddressesByUser[userDID] = userEmails.filter(id => id !== emailId); if (this.data.emailAddressesByUser[userDID].length === 0) { delete this.data.emailAddressesByUser[userDID]; } delete this.data.emailAddresses[emailId]; await this.save(); } // Address Operations async storeAddress(userDID, address) { await this.load(); const addressId = address.id || `address:${(0, uuid_1.v4)()}`; const addressWithId = { ...address, id: addressId }; this.data.addresses[addressId] = addressWithId; // Update user index if (!this.data.addressesByUser[userDID]) { this.data.addressesByUser[userDID] = []; } if (!this.data.addressesByUser[userDID].includes(addressId)) { this.data.addressesByUser[userDID].push(addressId); } await this.save(); return addressId; } async getAddress(userDID, addressId) { await this.load(); const userAddresses = this.data.addressesByUser[userDID] || []; if (!userAddresses.includes(addressId)) { return null; } return this.data.addresses[addressId] || null; } async listAddresses(userDID) { await this.load(); const addressIds = this.data.addressesByUser[userDID] || []; return addressIds .map(id => this.data.addresses[id]) .filter(address => address !== undefined); } async updateAddress(userDID, addressId, address) { await this.load(); const userAddresses = this.data.addressesByUser[userDID] || []; if (!userAddresses.includes(addressId)) { throw new Error('Address not found'); } const existingAddress = this.data.addresses[addressId]; if (existingAddress) { this.data.addresses[addressId] = { ...existingAddress, ...address, id: addressId }; await this.save(); } } async deleteAddress(userDID, addressId) { await this.load(); const userAddresses = this.data.addressesByUser[userDID] || []; this.data.addressesByUser[userDID] = userAddresses.filter(id => id !== addressId); if (this.data.addressesByUser[userDID].length === 0) { delete this.data.addressesByUser[userDID]; } delete this.data.addresses[addressId]; await this.save(); } // General operations async clear() { this.data = { dids: {}, credentials: {}, keyPairs: {}, revocationLists: {}, schemas: {}, phoneNumbers: {}, phoneNumbersByUser: {}, emailAddresses: {}, emailAddressesByUser: {}, addresses: {}, addressesByUser: {} }; await this.save(); } } exports.FileStorageProvider = FileStorageProvider; //# sourceMappingURL=file-storage-provider.js.map