OverviewFilesCommitsIssuesDocsReleasesPeers

hyperident / test-device-chain-workflow.js

155 lines · javascript ref:
import { IdentityManager } from './lib/identity-manager.js';
import { FileManager } from './lib/file-ops.js';
import fs from 'fs';
import path from 'path';

async function testCompleteDeviceChainWorkflow() {
  console.log('=== Testing Complete Device Chain Workflow ===\n');
  
  try {
    // Clean up any existing test data
    const testDir = path.join(FileManager.getHyperidentPath());
    if (fs.existsSync(testDir)) {
      fs.rmSync(testDir, { recursive: true, force: true });
      console.log('✓ Cleaned up existing test data');
    }
    
    // Step 1: Generate new identity with device chain
    console.log('\n--- Step 1: Generate Identity with Device Chain ---');
    const identity = await IdentityManager.generateIdentity(null, 'laptop-main');
    console.log('✓ Generated identity:', {
      publicKey: identity.publicKey.substring(0, 16) + '...',
      algorithm: identity.algorithm,
      deviceChain: identity.deviceChain,
      created: identity.created
    });
    
    // Step 2: Verify device chain exists and is valid
    console.log('\n--- Step 2: Verify Device Chain ---');
    const chainExists = await IdentityManager.deviceChainExists();
    console.log('✓ Device chain exists:', chainExists);
    
    if (chainExists) {
      const deviceChain = await IdentityManager.loadDeviceChain();
      console.log('✓ Device chain loaded:', {
        publicKeyLength: deviceChain.keyPair.publicKey.length,
        secretKeyLength: deviceChain.keyPair.secretKey.length,
        proofLength: deviceChain.proof.length,
        deviceName: deviceChain.metadata.name
      });
      
      // Verify the proof
      const verification = await IdentityManager.verifyDeviceProof(deviceChain.proof);
      console.log('✓ Device proof verified:', verification !== null);
      if (verification) {
        console.log('  - Identity matches:', verification.identityPublicKey.toString('hex').substring(0, 16) + '...');
        console.log('  - Device matches:', verification.devicePublicKey.toString('hex').substring(0, 16) + '...');
      }
    }
    
    // Step 3: Create a profile and test address generation
    console.log('\n--- Step 3: Create Profile and Test Address ---');
    await IdentityManager.createProfile('test-profile', 'Test profile for device chain');
    const address = await IdentityManager.getProfileAddress('test-profile');
    console.log('✓ Profile created with address:', address.substring(0, 16) + '...');
    
    // Step 4: Export device bundle
    console.log('\n--- Step 4: Export Device Bundle ---');
    const bundle = await IdentityManager.exportDeviceBundle();
    console.log('✓ Device bundle exported:', {
      version: bundle.version,
      hasIdentity: !!bundle.identity,
      hasDeviceChain: !!bundle.deviceChain,
      hasProfiles: !!bundle.profiles,
      profileCount: Object.keys(bundle.profiles).length
    });
    
    // Step 5: Simulate importing on a new device
    console.log('\n--- Step 5: Simulate New Device Import ---');
    
    // Clean up current identity to simulate new device
    fs.rmSync(testDir, { recursive: true, force: true });
    console.log('✓ Cleaned up for new device simulation');
    
    // Import the bundle on "new device"
    await IdentityManager.importDeviceBundle(bundle, 'phone-secondary');
    console.log('✓ Bundle imported on new device');
    
    // Step 6: Verify new device chain
    console.log('\n--- Step 6: Verify New Device Chain ---');
    const newChainExists = await IdentityManager.deviceChainExists();
    console.log('✓ New device chain exists:', newChainExists);
    
    if (newChainExists) {
      const newDeviceChain = await IdentityManager.loadDeviceChain();
      console.log('✓ New device chain loaded:', {
        deviceName: newDeviceChain.metadata.name,
        proofLength: newDeviceChain.proof.length
      });
      
      // Verify the new device proof
      const newVerification = await IdentityManager.verifyDeviceProof(newDeviceChain.proof);
      console.log('✓ New device proof verified:', newVerification !== null);
      if (newVerification) {
        console.log('  - Same identity:', newVerification.identityPublicKey.toString('hex').substring(0, 16) + '...');
        console.log('  - New device key:', newVerification.devicePublicKey.toString('hex').substring(0, 16) + '...');
      }
    }
    
    // Step 7: Verify profiles were imported
    console.log('\n--- Step 7: Verify Profile Import ---');
    const profiles = await IdentityManager.listProfiles();
    console.log('✓ Profiles imported:', Object.keys(profiles.profiles));
    
    if (profiles.profiles['test-profile']) {
      const importedAddress = await IdentityManager.getProfileAddress('test-profile');
      console.log('✓ Profile address matches:', address === importedAddress);
    }
    
    // Step 8: Test cross-device attestation
    console.log('\n--- Step 8: Test Cross-Device Attestation ---');
    
    // Generate a third device keypair
    const { CryptoManager } = await import('./lib/crypto.js');
    const thirdDeviceKeyPair = await CryptoManager.generateRawDeviceKeyPair();
    
    // Attest the third device using the second device
    const thirdDeviceProof = await IdentityManager.attestNewDevice(thirdDeviceKeyPair.publicKey);
    console.log('✓ Third device attested, proof length:', thirdDeviceProof.length);
    
    // Verify the third device proof
    const thirdVerification = await IdentityManager.verifyDeviceProof(thirdDeviceProof);
    console.log('✓ Third device proof verified:', thirdVerification !== null);
    
    console.log('\n=== All Tests Passed! ===');
    console.log('✓ Device chain generation works');
    console.log('✓ Device proof verification works');
    console.log('✓ Device bundle export/import works');
    console.log('✓ Cross-device attestation works');
    console.log('✓ Profile addresses are consistent across devices');
    
    return true;
    
  } catch (error) {
    console.error('\n❌ Test failed:', error.message);
    console.error('Stack:', error.stack);
    return false;
  }
}

// Run the test
testCompleteDeviceChainWorkflow()
  .then(success => {
    if (success) {
      console.log('\n🎉 Complete device chain workflow test PASSED!');
      process.exit(0);
    } else {
      console.log('\n💥 Complete device chain workflow test FAILED!');
      process.exit(1);
    }
  })
  .catch(error => {
    console.error('\n💥 Unexpected error:', error);
    process.exit(1);
  });