UNPKG

@synet/identity

Version:

Simple and secure identity management library for Verifiable Identity

469 lines (463 loc) 16 kB
"use strict"; /** * @synet/identity - Identity Unit * * Creates and manages decentralized identities by composing multiple units: * - DID unit for decentralized identifier management * - Signer unit for cryptographic signing operations * - Key unit for public key operations * - Credential unit for verifiable credential operations * * The Identity follows Unit Architecture with props-based construction * and teaching/learning contracts for capability sharing. * * * @author Synet Team */ Object.defineProperty(exports, "__esModule", { value: true }); exports.Identity = void 0; const keys_1 = require("@synet/keys"); const did_1 = require("@synet/did"); const credential_1 = require("@synet/credential"); const result_1 = require("./result"); const unit_1 = require("@synet/unit"); const VERSION = "1.0.1"; /** * Identity Unit - Unit Architecture implementation * Composes DID, Signer, Key, and Credential units */ class Identity extends unit_1.Unit { // MUST be protected (enables evolution) constructor(props) { super(props); } /** * Create identity from existing data or config */ static create(config) { try { if (!config.privateKeyHex || !config.publicKeyHex || !config.did || !config.alias) { return result_1.Result.fail("Required fields: alias, publicKeyHex, privateKeyHex, did"); } // 1. Prepare cryptographic material const privateKeyPEM = (0, keys_1.hexPrivateKeyToPem)(config.privateKeyHex); const publicKeyPEM = (0, keys_1.hexToPem)(config.publicKeyHex, "ed25519"); if (!privateKeyPEM || !publicKeyPEM) { throw new Error("Failed to convert keys to PEM format"); } // 2. Create signer const signer = keys_1.Signer.create({ privateKeyPEM, publicKeyPEM, keyType: "ed25519", metadata: { name: `${config.alias || "unknown"}-signer`, }, }); if (!signer) { return result_1.Result.fail("Failed to create signer from key material"); } // 3. Create key from signer const key = signer.createKey(); if (!key) { return result_1.Result.fail("Failed to create key from signer"); } // 4. Create DID unit from public key const didUnit = did_1.DID.create({ publicKeyHex: config.publicKeyHex, keyType: "Ed25519", metadata: { alias: config.alias || "unknown", }, }); if (!didUnit) { return result_1.Result.fail("Failed to reconstruct DID"); } // 5. Create credential unit and learn from key. Key already knows how to sign from signer. const credentialUnit = credential_1.Credential.create(); credentialUnit.learn([key.teach()]); const props = { dna: (0, unit_1.createUnitSchema)({ id: "identity", version: "1.0.0" }), alias: config.alias || "unknown", did: config.did || "did:key:unknown", kid: config.kid || config.publicKeyHex, publicKeyHex: config.publicKeyHex, privateKeyHex: config.privateKeyHex, provider: config.provider || "did:key", credential: config.credential || {}, metadata: config.metadata || {}, createdAt: config.createdAt || new Date(), didUnit, signerUnit: signer, keyUnit: key, credentialUnit, }; return result_1.Result.success(new Identity(props)); } catch (error) { return result_1.Result.fail(error instanceof Error ? error.message : "Unknown error occurred", error instanceof Error ? error : undefined); } } /** * Generate a new identity with fresh cryptographic material */ static async generate(alias) { try { // 1. Generate cryptographic material in hex format const keyPair = (0, keys_1.generateKeyPair)("ed25519", { format: "hex" }); if (!keyPair) { throw new Error("Failed to generate key pair"); } // 2. Convert hex keys to PEM for signer creation const publicKeyPEM = (0, keys_1.hexToPem)(keyPair.publicKey, "ed25519"); const privateKeyPEM = (0, keys_1.hexPrivateKeyToPem)(keyPair.privateKey); if (!publicKeyPEM || !privateKeyPEM) { throw new Error("Failed to convert keys to PEM format"); } // 3. Create signer from the PEM keys const signer = keys_1.Signer.create({ privateKeyPEM, publicKeyPEM, keyType: "ed25519", secure: true, metadata: { name: `${alias}-signer`, }, }); if (!signer) { throw new Error("Failed to create signer from key pair"); } const key = signer.createKey(); if (!key) { throw new Error("Failed to create key from signer"); } // 4. Get public key in hex format (should match our generated key) const publicKeyHex = signer.getPublicKeyHex(); if (!publicKeyHex) { throw new Error("Failed to get public key hex"); } // 5. Use the hex private key we generated const privateKeyHex = keyPair.privateKey; // 6. Create DID from public key (reuse the PEM we already have) const didUnit = did_1.DID.create({ publicKeyHex, keyType: "Ed25519", metadata: { alias } }); if (!didUnit) { throw new Error("Failed to create DID from public key"); } // 7. Generate DID from publicKey const didString = didUnit.generateKey(); if (!didString) { throw new Error("Failed to generate DID string"); } // 8. Create credential unit and learn from key const credentialUnit = credential_1.Credential.create(); credentialUnit.learn([key.teach()]); // 9. Create self-signed verifiable credential const subject = { holder: { id: didString, name: alias, }, issuedBy: { id: didString, name: alias, }, }; const credentialResult = await credentialUnit.issueCredential(subject, "IdentityCredential", didString); if (!credentialResult.isSuccess) { return result_1.Result.fail(`Failed to issue identity credential: ${credentialResult.errorMessage}`); } const credential = credentialResult.value; // 9. Build identity props const props = { dna: (0, unit_1.createUnitSchema)({ id: "identity", version: VERSION }), alias, did: didString, kid: publicKeyHex, publicKeyHex, privateKeyHex, provider: "did:key", credential: credential, metadata: {}, createdAt: new Date(), didUnit, signerUnit: signer, keyUnit: key, credentialUnit, }; const identity = new Identity(props); // 10. Teach identity how to generate keys, sign and create verifiable credentials identity.learn([signer.teach(), key.teach(), credentialUnit.teach()]); // 11. Full SSI Identity that can issue VCs and sign, while preserving its secrets. return result_1.Result.success(identity); } catch (error) { console.error("Failed to generate identity:", error); return result_1.Result.fail(error instanceof Error ? error.message : "Unknown error occurred", error instanceof Error ? error : undefined); } } // ========================================== // UNIT ARCHITECTURE REQUIRED METHODS // ========================================== whoami() { return `Identity Unit - ${this.props.alias} (${this.props.dna.id}@${this.props.dna.version})`; } capabilities() { return Array.from(this._capabilities.keys()); } help() { console.log(` [👤] Identity Unit - Decentralized Identity Management Native Capabilities: • issueCredential() - Issue verifiable credentials • sign(data) - Sign data with private key • verify(data, signature) - Verify signatures • getDid() - Get DID string • getPublicKey() - Get public key • public() - Get public identity data, without private key • present() - Present identity • toJSON() - export indentity for persistence • toDomain() - convert indentity to domain type IIdentity Getters: • alias • did • metadata • provider • publicKeyHex • privateKeyHex Composed Units: • DID Unit: ${this.props.didUnit.whoami()} • Signer Unit: ${this.props.signerUnit.whoami()} • Key Unit: ${this.props.keyUnit?.whoami() || "Key Unit (not available)"} • Credential Unit: ${this.props.credentialUnit.whoami()} Current State: • Alias: ${this.props.alias} • DID: ${this.props.did} • Provider: ${this.props.provider} • Created: ${this.props.createdAt.toISOString()} Learned Capabilities: ${this._capabilities.size} total ${Array.from(this._capabilities.keys()) .map((cap) => ` • ${cap}`) .join("\n")} `); } teach() { return { unitId: this.props.dna.id, capabilities: { issueCredential: ((...args) => this.issueCredential(args[0], args[1], args[2])), sign: ((...args) => this.sign(args[0])), verify: ((...args) => this.verify(args[0], args[1])), getDid: ((...args) => this.getDid()), getPublicKey: ((...args) => this.getPublicKey()), }, }; } // ========================================== // NATIVE CAPABILITIES // ========================================== /** * @depricated, use generate() instead. */ async generateIdentity(alias) { return Identity.generate(alias); } /** * Issue and sign Verifable Credential. * @param subject * @param type * @param issuer * @returns */ async issueCredential(subject, type, issuer) { if (this.can("credential.issueCredential")) { return this.execute("credential.issueCredential", subject, type, issuer || this.props.did); } // Graceful fallback to native capability const result = await this.props.credentialUnit.issueCredential(subject, type, issuer || this.props.did); // Convert the result type if (!result.isSuccess) { const errorMessage = typeof result.error === "string" ? result.error : result.error?.message || "Failed to issue credential"; return result_1.Result.fail(errorMessage); } return result_1.Result.success(result.value); } async sign(data) { if (this.can("signer.sign")) { return this.execute("signer.sign", data); } // Graceful fallback to native capability if (this.props.privateKeyHex) { return this.props.signerUnit.sign(data); } throw new Error(`[${this.props.dna.id}] Cannot sign - missing 'signer.sign' capability. Learn from: Signer.create().teach()`); } async verify(data, signature) { if (this.can("signer.verify")) { return this.execute("signer.verify", data, signature); } // Graceful fallback to native capability return this.props.signerUnit.verify(data, signature); } get publicKeyHex() { return this.props.publicKeyHex; } get privateKeyHex() { return this.props.privateKeyHex; } get alias() { return this.props.alias; } get did() { return this.props.did; } get credential() { return this.props.credential; } get metadata() { return this.props.metadata; } /** * Get identity provider */ get provider() { return this.props.provider; } getDid() { return this.props.did; } getPublicKey() { return this.props.publicKeyHex; } /** * @deprecated Use getPublicKey() instead */ getPublicKeyHex() { return this.props.publicKeyHex; } // ========================================== // UNIT ACCESS (for operations) // ========================================== didUnit() { return this.props.didUnit; } /** * Get Key unit for public key operations */ keyUnit() { return this.props.keyUnit; } /** * Get Signer unit for signing operations */ signerUnit() { return this.props.signerUnit; } /** * Get Credential unit for verifiable credential operations */ credentialUnit() { return this.props.credentialUnit; } // ========================================== // LEGACY COMPATIBILITY METHODS // ========================================== /** * Get identity alias */ getAlias() { return this.props.alias; } /** * Get key identifier */ getKid() { return this.props.kid; } /** * Get private key in hex format (if available) */ getPrivateKeyHex() { return this.props.privateKeyHex; } /** * Get identity provider */ getProvider() { return this.props.provider; } /** * Get verifiable credential */ getCredential() { return this.props.credential; } /** * Get metadata */ getMetadata() { return this.props.metadata; } /** * Get creation date */ getCreatedAt() { return this.props.createdAt; } toJSON() { return { alias: this.props.alias, did: this.props.did, kid: this.props.kid, publicKeyHex: this.props.publicKeyHex, privateKeyHex: this.props.privateKeyHex, provider: this.props.provider, credential: this.props.credential, metadata: this.props.metadata, createdAt: this.props.createdAt, }; } /** * Convert Identity props to domain entity IIdentity * @returns * */ toDomain() { return { alias: this.props.alias, did: this.props.did, kid: this.props.kid, publicKeyHex: this.props.publicKeyHex, privateKeyHex: this.props.privateKeyHex, provider: this.props.provider, credential: this.props.credential, metadata: this.props.metadata, createdAt: this.props.createdAt, }; } /** * Export public identity data (no private key) */ public() { const { privateKeyHex, ...publicData } = this.props; return publicData; } /** * Presents identity * @returns IdentityPresent { did, publicKeyHex, credential } */ present() { return { did: this.props.did, publicKeyHex: this.props.publicKeyHex, credential: this.props.credential, }; } } exports.Identity = Identity;