diff --git a/test-scripts/check-did.sh b/test-scripts/check-did.sh new file mode 100755 index 0000000..8a5861b --- /dev/null +++ b/test-scripts/check-did.sh @@ -0,0 +1,59 @@ +#!/bin/bash + +# Usage: ./check-did.sh [did] +# If no DID provided, lists all visible DIDs + +API_URL=${ENDORSER_API_URL:-"https://test-api.endorser.ch/api/v2/claim"} +ADMIN_DID="did:ethr:0x0000694B58C2cC69658993A90D3840C560f2F51F" +ADMIN_KEY="2b6472c026ec2aa2c4235c994a63868fc9212d18b58f6cbfe861b52e71330f5b" + +# Create verification JWT using Python (equivalent to uport-credentials) +jwt=$(python3 -c " +from eth_keys import keys +import hashlib, base64, json, time + +# Create header and payload +header = {'typ': 'JWT', 'alg': 'ES256K'} +payload = { + 'iss': '$ADMIN_DID', + 'exp': int(time.time()) + 300 # 5 minutes from now +} + +# Base64url encode header and payload +def b64url(data): + return base64.urlsafe_b64encode(json.dumps(data).encode()).decode().rstrip('=') + +header_b64 = b64url(header) +payload_b64 = b64url(payload) +message = f'{header_b64}.{payload_b64}' + +# Sign using admin key +private_key = keys.PrivateKey(bytes.fromhex('$ADMIN_KEY')) +message_hash = hashlib.sha256(message.encode()).digest() +signature = private_key.sign_msg_hash(message_hash) +signature_bytes = signature.r.to_bytes(32, 'big') + signature.s.to_bytes(32, 'big') +signature_b64 = base64.urlsafe_b64encode(signature_bytes).decode().rstrip('=') + +# Output complete JWT +print(f'{message}.{signature_b64}') +") + +REQUEST_URL="$API_URL/report/whichDidsICanSee" +echo "Making request to: $REQUEST_URL" +echo "Getting visible DIDs..." +response=$(curl -s -X GET "$REQUEST_URL" \ + -H "Authorization: Bearer $jwt" \ + -H "Content-Type: application/json") + +echo -e "\nResponse:" +echo "$response" | jq '.' + +# If specific DID provided, check if it's in the list +if [ -n "$1" ]; then + echo -e "\nChecking if DID $1 is visible..." + if echo "$response" | jq -e --arg did "$1" '.[] | select(. == $did)' > /dev/null; then + echo "✅ DID is registered and visible" + else + echo "❌ DID not found in visible list" + fi +fi \ No newline at end of file diff --git a/test-scripts/generate-test-claim.sh b/test-scripts/generate-test-claim.sh index 8975720..c34ac6d 100755 --- a/test-scripts/generate-test-claim.sh +++ b/test-scripts/generate-test-claim.sh @@ -7,6 +7,19 @@ if [ ! -f .generated/test-env.sh ]; then fi source .generated/test-env.sh +# Verify we have the required DIDs +if [ -z "$CONTACT1_DID" ] || [ -z "$CONTACT1_KEY" ]; then + echo "Error: Contact1 DID info not found in environment" + exit 1 +fi + +# Use CONTACT1 as the issuer since we know it's registered +REGISTERED_DID="$CONTACT1_DID" +REGISTERED_KEY="$CONTACT1_KEY" + +# Default API URL (can be overridden by environment) +API_URL=${ENDORSER_API_URL:-"https://test-api.endorser.ch/api/v2/claim"} + # Function to sign a message using ES256K sign_message() { local message="$1" @@ -17,62 +30,62 @@ sign_message() { tmpdir=$(mktemp -d) trap 'rm -rf "$tmpdir"' EXIT - # Create private key PEM file - echo "-----BEGIN EC PRIVATE KEY-----" > "$tmpdir/private.pem" - ( - echo "302e0201010420" # Private key header - echo -n "$private_key" # Private key bytes - echo "a00706052b8104000a" # secp256k1 OID - ) | xxd -r -p | base64 >> "$tmpdir/private.pem" - echo "-----END EC PRIVATE KEY-----" >> "$tmpdir/private.pem" + # Debug output + echo "Signing message: $message" >&2 + echo "Using private key: $private_key" >&2 - # Write message to file - echo -n "$message" > "$tmpdir/message.txt" + # Hash the message with SHA-256 + echo -n "$message" | openssl dgst -sha256 -binary > "$tmpdir/message.hash" - # Sign message and get DER format signature - openssl dgst -sha256 -sign "$tmpdir/private.pem" "$tmpdir/message.txt" > "$tmpdir/signature.der" + # Sign the hash directly using the private key + # This avoids OpenSSL's PEM format issues with secp256k1 + python3 -c " +import sys +from eth_keys import keys +import hashlib - # Convert DER signature to R+S format - der_sig=$(xxd -p -c 256 "$tmpdir/signature.der") +# Read message hash +with open('$tmpdir/message.hash', 'rb') as f: + message_hash = f.read() - # Parse DER structure - if [[ $der_sig =~ ^30([0-9a-f]{2})02([0-9a-f]{2})([0-9a-f]*)02([0-9a-f]{2})([0-9a-f]*)$ ]]; then - r_val="${BASH_REMATCH[3]}" - s_val="${BASH_REMATCH[5]}" +# Create private key object +private_key_bytes = bytes.fromhex('$private_key') +private_key = keys.PrivateKey(private_key_bytes) - # Remove leading zeros - r_val=${r_val#"00"} - s_val=${s_val#"00"} +# Sign the message hash +signature = private_key.sign_msg_hash(message_hash) - # Pad to 64 chars - r_val=$(printf "%064s" "$r_val" | tr ' ' '0') - s_val=$(printf "%064s" "$s_val" | tr ' ' '0') +# Output R and S values as hex +print(f'{hex(signature.r)[2:]:0>64}') +print(f'{hex(signature.s)[2:]:0>64}') +" > "$tmpdir/signature.txt" - # Take last 64 chars if longer - r_val=${r_val:(-64)} - s_val=${s_val:(-64)} + # Read R and S values + { read -r r_val; read -r s_val; } < "$tmpdir/signature.txt" - # Concatenate R+S and convert to base64url - echo -n "${r_val}${s_val}" | xxd -r -p | base64 -w 0 | tr '/+' '_-' | tr -d '=' - else - echo "Error: Invalid DER signature format" >&2 - return 1 - fi + # Debug R and S values + echo "R value: $r_val" >&2 + echo "S value: $s_val" >&2 + + # Concatenate R+S and convert to base64url + echo -n "${r_val}${s_val}" | xxd -r -p | base64 -w 0 | tr '/+' '_-' | tr -d '=' } # Create a test claim payload create_claim_payload() { local issuer_did="$1" - local subject_did="$2" - # Create registration claim with issuer as agent + # Create a test claim matching the app's structure cat << EOF { "@context": "https://schema.org", "@type": "TestClaim", - "agent": { "did": "$issuer_did" }, - "participant": { "did": "$subject_did" }, - "object": "test.endorser.ch" + "identifier": "test-claim-$(date +%s)", + "name": "Test Claim", + "description": "Generated test claim", + "agent": { + "did": "$issuer_did" + } } EOF } @@ -83,9 +96,9 @@ create_jwt() { local issuer_did="$2" local private_key="$3" - # Create header and payload + # Create header and payload matching the app's structure local header='{"typ":"JWT","alg":"ES256K"}' - local payload="{\"iat\":$(date +%s),\"exp\":$(($(date +%s) + 300)),\"sub\":\"TestClaim\",\"vc\":{\"@context\":[\"https://www.w3.org/2018/credentials/v1\"],\"type\":[\"VerifiableCredential\"],\"credentialSubject\":$claim},\"iss\":\"$issuer_did\"}" + local payload="{\"iat\":$(date +%s),\"exp\":$(($(date +%s) + 300)),\"iss\":\"$issuer_did\",\"vc\":{\"@context\":[\"https://www.w3.org/2018/credentials/v1\"],\"type\":[\"VerifiableCredential\"],\"credentialSubject\":$claim}}" # Base64url encode header and payload local header_b64=$(echo -n "$header" | base64 -w 0 | tr '/+' '_-' | tr -d '=') @@ -94,24 +107,69 @@ create_jwt() { # Create message to sign local message="$header_b64.$payload_b64" - # Sign message - local signature=$(sign_message "$message" "$private_key") - + # Sign message using eth_keys (same as did-jwt library) + local signature=$(python3 -c " +from eth_keys import keys +import hashlib + +# Create private key object +private_key_bytes = bytes.fromhex('$private_key') +private_key = keys.PrivateKey(private_key_bytes) + +# Hash the message +message_hash = hashlib.sha256('$message'.encode()).digest() + +# Sign using ES256K +signature = private_key.sign_msg_hash(message_hash) + +# Format as R+S concatenated and base64url encoded +import base64 +signature_bytes = signature.r.to_bytes(32, 'big') + signature.s.to_bytes(32, 'big') +print(base64.urlsafe_b64encode(signature_bytes).decode().rstrip('=')) +") + # Return complete JWT echo "$message.$signature" } +# Function to register claim with API +register_claim() { + local jwt="$1" + + echo "Registering claim with API..." + response=$(curl -s -X POST "$API_URL" \ + -H "Content-Type: application/json" \ + -d "{\"jwtEncoded\":\"$jwt\"}") + + # Check response + if echo "$response" | jq -e '.success' >/dev/null 2>&1; then + echo "Registration successful!" + echo "Response:" + echo "$response" | jq '.' + return 0 + else + echo "Registration failed!" + echo "Error: $(echo "$response" | jq -r '.error.message // empty')" + echo "Full response:" + echo "$response" | jq '.' || echo "$response" + return 1 + fi +} + # Main execution echo "Generating test claim..." # Create claim payload -claim=$(create_claim_payload "$ISSUER_DID" "$CONTACT1_DID") +claim=$(create_claim_payload "$REGISTERED_DID") echo "Claim payload:" echo "$claim" | jq '.' # Create and sign JWT echo "Generating signed JWT..." -jwt=$(create_jwt "$claim" "$ISSUER_DID" "$ISSUER_KEY") +jwt=$(create_jwt "$claim" "$REGISTERED_DID" "$REGISTERED_KEY") + +# Output just the JWT for piping +echo "$jwt" -echo -e "\nGenerated JWT: ${jwt:0:50}..." -echo "$jwt" # Output just the JWT for piping \ No newline at end of file +# Register the claim +register_claim "$jwt" \ No newline at end of file diff --git a/test-scripts/run-deeplink-tests.sh b/test-scripts/run-deeplink-tests.sh index c73d223..8f87b50 100755 --- a/test-scripts/run-deeplink-tests.sh +++ b/test-scripts/run-deeplink-tests.sh @@ -40,37 +40,14 @@ if [ -f .generated/test-env.sh ] && [ "$GENERATE_ONLY" = false ]; then else # Function to extract DID info from did_generator.sh output extract_did_info() { - local output - # Read all input into output variable - output=$(cat) - - # Debug the input - echo "Parsing output:" >&2 - echo "$output" >&2 - - # Extract values using more robust patterns + local output="$1" local did=$(echo "$output" | grep "^DID: " | cut -d' ' -f2-) local private_key=$(echo "$output" | grep "^Private Key: " | cut -d' ' -f3-) - - # Debug the extracted values - echo "Found DID: $did" >&2 - echo "Found Key: $private_key" >&2 - - # Output JSON only if both values were found - if [ -n "$did" ] && [ -n "$private_key" ]; then - printf '%s\n' "{\"did\":\"$did\",\"privateKey\":\"$private_key\"}" - else - echo "Error: Could not extract DID info from output" >&2 - return 1 - fi + printf '%s\n' "{\"did\":\"$did\",\"privateKey\":\"$private_key\"}" } echo "Generating first contact DID..." - CONTACT1_INFO=$(./test-scripts/did_generator.sh | tee /dev/stderr | extract_did_info) - if [ $? -ne 0 ]; then - echo "Failed to generate first contact DID" - exit 1 - fi + CONTACT1_INFO=$(./test-scripts/did_generator.sh 2>&1 | tee /dev/stderr | extract_did_info) CONTACT1_DID=$(echo "$CONTACT1_INFO" | jq -r .did) CONTACT1_KEY=$(echo "$CONTACT1_INFO" | jq -r .privateKey) echo "Extracted DID: $CONTACT1_DID"