@synet/identity
Version:
Simple and secure identity management library for Verifiable Identity
469 lines (463 loc) • 16 kB
JavaScript
"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;