/**
* Debug Manager - Debugging and diagnostic tools for hyperident
* Provides identity inspection, network diagnostics, and troubleshooting utilities
*/
import { IdentityManager } from './identity-manager.js'
import { DeviceMeshManager } from './device-mesh-manager.js'
import { DeviceLinkingManager } from './device-linking-manager.js'
import { FileManager } from './file-ops.js'
import { CryptoManager } from './crypto.js'
export class DebugManager {
/**
* Check if network dependencies are available
* @returns {Promise<boolean>} True if network dependencies are available
*/
static async isNetworkAvailable() {
try {
await import('hyperswarm')
await import('hypercore-id-encoding')
await import('b4a')
return true
} catch (error) {
return false
}
}
/**
* Get comprehensive identity inspection data
* @param {string} passphrase - Optional passphrase for encrypted identities
* @returns {Promise<Object>} Identity inspection data
*/
static async inspectIdentity(passphrase = null) {
const inspection = {
timestamp: new Date().toISOString(),
identity: null,
deviceChain: null,
profiles: null,
files: {
identity: false,
identityPub: false,
profiles: false,
deviceKey: false,
devicePub: false,
deviceProof: false,
deviceJson: false,
bootstrapProof: false
},
errors: []
}
try {
// Check file existence
const hyperidentPath = FileManager.getHyperidentPath()
try {
inspection.files.identity = await FileManager.fileExists(`${hyperidentPath}/identity`)
} catch (e) { inspection.errors.push(`Identity file check: ${e.message}`) }
try {
inspection.files.identityPub = await FileManager.fileExists(`${hyperidentPath}/identity.pub`)
} catch (e) { inspection.errors.push(`Identity.pub file check: ${e.message}`) }
try {
inspection.files.profiles = await FileManager.fileExists(`${hyperidentPath}/profiles.json`)
} catch (e) { inspection.errors.push(`Profiles file check: ${e.message}`) }
try {
inspection.files.deviceKey = await FileManager.fileExists(`${hyperidentPath}/device.key`)
} catch (e) { inspection.errors.push(`Device.key file check: ${e.message}`) }
try {
inspection.files.devicePub = await FileManager.fileExists(`${hyperidentPath}/device.pub`)
} catch (e) { inspection.errors.push(`Device.pub file check: ${e.message}`) }
try {
inspection.files.deviceProof = await FileManager.fileExists(`${hyperidentPath}/device.proof`)
} catch (e) { inspection.errors.push(`Device.proof file check: ${e.message}`) }
try {
inspection.files.deviceJson = await FileManager.fileExists(`${hyperidentPath}/device.json`)
} catch (e) { inspection.errors.push(`Device.json file check: ${e.message}`) }
try {
inspection.files.bootstrapProof = await FileManager.fileExists(`${hyperidentPath}/bootstrap.proof`)
} catch (e) { inspection.errors.push(`Bootstrap.proof file check: ${e.message}`) }
// Load identity data
try {
inspection.identity = await IdentityManager.loadIdentity(passphrase)
} catch (e) {
inspection.errors.push(`Identity load: ${e.message}`)
}
// Load device chain
try {
if (await IdentityManager.deviceChainExists()) {
inspection.deviceChain = await IdentityManager.loadDeviceChain()
}
} catch (e) {
inspection.errors.push(`Device chain load: ${e.message}`)
}
// Load profiles
try {
inspection.profiles = await IdentityManager.listProfiles()
} catch (e) {
inspection.errors.push(`Profiles load: ${e.message}`)
}
} catch (error) {
inspection.errors.push(`General inspection error: ${error.message}`)
}
return inspection
}
/**
* Run network diagnostics
* @returns {Promise<Object>} Network diagnostic results
*/
static async runNetworkDiagnostics() {
const diagnostics = {
timestamp: new Date().toISOString(),
networkAvailable: false,
dependencies: {
hyperswarm: false,
hypercoreIdEncoding: false,
b4a: false
},
meshStatus: null,
linkingStatus: null,
errors: []
}
// Check network dependencies
try {
await import('hyperswarm')
diagnostics.dependencies.hyperswarm = true
} catch (e) {
diagnostics.errors.push(`Hyperswarm dependency: ${e.message}`)
}
try {
await import('hypercore-id-encoding')
diagnostics.dependencies.hypercoreIdEncoding = true
} catch (e) {
diagnostics.errors.push(`Hypercore-id-encoding dependency: ${e.message}`)
}
try {
await import('b4a')
diagnostics.dependencies.b4a = true
} catch (e) {
diagnostics.errors.push(`B4a dependency: ${e.message}`)
}
diagnostics.networkAvailable = diagnostics.dependencies.hyperswarm &&
diagnostics.dependencies.hypercoreIdEncoding &&
diagnostics.dependencies.b4a
if (diagnostics.networkAvailable) {
// Test mesh manager
try {
const meshManager = new DeviceMeshManager()
diagnostics.meshStatus = await meshManager.getMeshStatus()
await meshManager.cleanup()
} catch (e) {
diagnostics.errors.push(`Mesh status check: ${e.message}`)
}
// Test linking manager
try {
const linkingManager = new DeviceLinkingManager()
diagnostics.linkingStatus = {
available: await DeviceLinkingManager.isNetworkAvailable(),
initialized: true
}
await linkingManager.cleanup()
} catch (e) {
diagnostics.errors.push(`Linking manager check: ${e.message}`)
}
}
return diagnostics
}
/**
* Verify trust relationships for identity and devices
* @param {string} passphrase - Optional passphrase for encrypted identities
* @returns {Promise<Object>} Trust verification results
*/
static async verifyTrust(passphrase = null) {
const verification = {
timestamp: new Date().toISOString(),
identityValid: false,
deviceChainValid: false,
bootstrapProofValid: false,
signingCapable: false,
trustChain: [],
errors: []
}
try {
// Verify identity exists and is loadable
if (IdentityManager.identityExists()) {
try {
const identity = await IdentityManager.loadIdentity(passphrase)
verification.identityValid = true
verification.trustChain.push({
type: 'identity',
publicKey: identity.publicKey,
valid: true,
created: identity.created
})
} catch (e) {
verification.errors.push(`Identity verification: ${e.message}`)
}
} else {
verification.errors.push('Identity does not exist')
}
// Verify device chain
try {
if (await IdentityManager.deviceChainExists()) {
const deviceChain = await IdentityManager.loadDeviceChain()
verification.deviceChainValid = true
verification.trustChain.push({
type: 'device',
publicKey: deviceChain.metadata.publicKey,
name: deviceChain.metadata.name,
valid: true,
created: deviceChain.metadata.created
})
} else {
verification.errors.push('Device chain does not exist')
}
} catch (e) {
verification.errors.push(`Device chain verification: ${e.message}`)
}
// Verify bootstrap proof
try {
const hyperidentPath = FileManager.getHyperidentPath()
if (await FileManager.fileExists(`${hyperidentPath}/bootstrap.proof`)) {
verification.bootstrapProofValid = true
verification.trustChain.push({
type: 'bootstrap_proof',
valid: true,
purpose: 'signing_operations'
})
} else {
verification.errors.push('Bootstrap proof does not exist')
}
} catch (e) {
verification.errors.push(`Bootstrap proof verification: ${e.message}`)
}
// Test signing capability
try {
if (verification.identityValid && verification.deviceChainValid && verification.bootstrapProofValid) {
// Test with small data
const testData = Buffer.from('hyperident-trust-test')
const signature = await IdentityManager.signData(testData, passphrase)
const verificationResult = await IdentityManager.verifySignature(signature, testData)
if (verificationResult) {
verification.signingCapable = true
verification.trustChain.push({
type: 'signing_test',
valid: true,
tested: true
})
} else {
verification.errors.push('Signing test failed - signature did not verify')
}
} else {
verification.errors.push('Cannot test signing - missing required components')
}
} catch (e) {
verification.errors.push(`Signing capability test: ${e.message}`)
}
} catch (error) {
verification.errors.push(`General trust verification error: ${error.message}`)
}
return verification
}
/**
* Get system information relevant to hyperident
* @returns {Promise<Object>} System information
*/
static async getSystemInfo() {
const systemInfo = {
timestamp: new Date().toISOString(),
node: {
version: process.version,
platform: process.platform,
arch: process.arch
},
hyperident: {
version: '0.1.0', // TODO: Read from package.json
workingDirectory: process.cwd(),
hyperidentPath: FileManager.getHyperidentPath()
},
environment: {
debug: !!process.env.DEBUG,
nodeEnv: process.env.NODE_ENV || 'development'
},
memory: process.memoryUsage(),
uptime: process.uptime()
}
return systemInfo
}
/**
* Run comprehensive health check
* @param {string} passphrase - Optional passphrase for encrypted identities
* @returns {Promise<Object>} Health check results
*/
static async healthCheck(passphrase = null) {
const health = {
timestamp: new Date().toISOString(),
overall: 'unknown',
checks: {
identity: { status: 'unknown', details: null },
network: { status: 'unknown', details: null },
trust: { status: 'unknown', details: null },
system: { status: 'unknown', details: null }
},
summary: {
passed: 0,
failed: 0,
warnings: 0
}
}
// Identity check
try {
const identityInspection = await this.inspectIdentity(passphrase)
if (identityInspection.errors.length === 0 && identityInspection.identity) {
health.checks.identity.status = 'pass'
} else if (identityInspection.identity) {
health.checks.identity.status = 'warning'
health.summary.warnings++
} else {
health.checks.identity.status = 'fail'
health.summary.failed++
}
health.checks.identity.details = identityInspection
} catch (e) {
health.checks.identity.status = 'fail'
health.checks.identity.details = { error: e.message }
health.summary.failed++
}
// Network check
try {
const networkDiagnostics = await this.runNetworkDiagnostics()
if (networkDiagnostics.networkAvailable && networkDiagnostics.errors.length === 0) {
health.checks.network.status = 'pass'
health.summary.passed++
} else if (networkDiagnostics.networkAvailable) {
health.checks.network.status = 'warning'
health.summary.warnings++
} else {
health.checks.network.status = 'fail'
health.summary.failed++
}
health.checks.network.details = networkDiagnostics
} catch (e) {
health.checks.network.status = 'fail'
health.checks.network.details = { error: e.message }
health.summary.failed++
}
// Trust check
try {
const trustVerification = await this.verifyTrust(passphrase)
if (trustVerification.signingCapable && trustVerification.errors.length === 0) {
health.checks.trust.status = 'pass'
health.summary.passed++
} else if (trustVerification.identityValid) {
health.checks.trust.status = 'warning'
health.summary.warnings++
} else {
health.checks.trust.status = 'fail'
health.summary.failed++
}
health.checks.trust.details = trustVerification
} catch (e) {
health.checks.trust.status = 'fail'
health.checks.trust.details = { error: e.message }
health.summary.failed++
}
// System check
try {
const systemInfo = await this.getSystemInfo()
health.checks.system.status = 'pass'
health.checks.system.details = systemInfo
health.summary.passed++
} catch (e) {
health.checks.system.status = 'fail'
health.checks.system.details = { error: e.message }
health.summary.failed++
}
// Determine overall health
if (health.summary.failed === 0 && health.summary.warnings === 0) {
health.overall = 'healthy'
} else if (health.summary.failed === 0) {
health.overall = 'warning'
} else {
health.overall = 'unhealthy'
}
return health
}
}