OverviewFilesCommitsIssuesDocsReleasesPeers

pear-git / test / test-signatures.js

113 lines · javascript ref:
#!/usr/bin/env node

/**
 * Test ANProto signatures
 */

import crypto from 'hypercore-crypto'
import b4a from 'b4a'

const BASE_URL = 'http://localhost:5005/git';

async function test() {
  console.log('🧪 Testing ANProto signatures...\n');

  // Step 1: Generate identity
  console.log('1. Generating identity...');
  const genResponse = await fetch(`${BASE_URL}/api/identity/generate`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' }
  });

  if (!genResponse.ok) {
    console.error('❌ Failed to generate identity:', genResponse.status);
    process.exit(1);
  }

  const identity = await genResponse.json();
  const publicKey = identity.publicKey;
  const keypair = identity.keypair;
  const secretKeyB64 = keypair.substring(44, 132);

  console.log('✓ Identity generated:', publicKey.substring(0, 8) + '...');
  console.log('  Keypair length:', keypair.length);

  // Step 2: Get challenge
  console.log('\n2. Getting challenge...');
  const challengeResponse = await fetch(`${BASE_URL}/api/auth/challenge`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ context: 'test' })
  });

  if (!challengeResponse.ok) {
    console.error('❌ Failed to get challenge:', challengeResponse.status);
    process.exit(1);
  }

  const challengeData = await challengeResponse.json();
  console.log('✓ Challenge received:', challengeData.challengeId.substring(0, 8) + '...');
  console.log('  Challenge:', challengeData.challenge.substring(0, 20) + '...');
  console.log('  Expires in:', Math.floor((challengeData.expiresAt - Date.now()) / 1000), 'seconds');

  // Step 3: Sign challenge
  console.log('\n3. Signing challenge...');
  const secretKeyBytes = b4a.from(secretKeyB64, 'base64');
  const challengeBytes = b4a.from(challengeData.challenge, 'utf8');

  // Use 2-argument form which returns the signature
  const signature = crypto.sign(challengeBytes, secretKeyBytes);

  const signatureB64 = b4a.toString(signature, 'base64');
  console.log('✓ Signature created:', signatureB64.substring(0, 20) + '...');
  console.log('  Signature length:', signatureB64.length, 'chars');

  // Step 4: Test with signature
  console.log('\n4. Testing with signature...');
  const authResponse = await fetch(`${BASE_URL}/api/user/identities`, {
    headers: {
      'X-Wirecore-PublicKey': publicKey,
      'X-Wirecore-Signature': signatureB64,
      'X-Wirecore-Challenge': challengeData.challengeId
    }
  });

  console.log('  Status:', authResponse.status, authResponse.statusText);

  if (authResponse.ok) {
    const data = await authResponse.json();
    console.log('✅ Authenticated with signature!');
    console.log('  User ID:', data.user?.userId);
    console.log('  Identities:', data.identities.length);
  } else {
    const errorText = await authResponse.text();
    console.error('❌ Signature authentication failed!');
    console.error('  Error:', errorText);
    process.exit(1);
  }

  // Step 5: Test legacy (without signature)
  console.log('\n5. Testing legacy mode (no signature)...');
  const legacyResponse = await fetch(`${BASE_URL}/api/user/identities`, {
    headers: {
      'X-Wirecore-PublicKey': publicKey
    }
  });

  console.log('  Status:', legacyResponse.status, legacyResponse.statusText);

  if (legacyResponse.ok) {
    console.log('✓ Legacy mode still works');
  } else {
    console.log('✗ Legacy mode disabled');
  }

  console.log('\n✅ ANProto signatures working!');
}

test().catch(err => {
  console.error('\n❌ Test failed:', err.message);
  console.error(err.stack);
  process.exit(1);
});