diff --git a/requirements.txt b/requirements.txt index 2c0390a..9b32aa2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ +eth_keys pywebview pyinstaller>=6.12.0 # For development diff --git a/test-scripts/check-did.sh b/test-scripts/check-did.sh index 8a5861b..c33f2ef 100755 --- a/test-scripts/check-did.sh +++ b/test-scripts/check-did.sh @@ -1,9 +1,10 @@ #!/bin/bash +# Requirements: jq, python, and `pip install -r requirements.txt` # 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"} +API_URL=${ENDORSER_API_URL:-"https://test-api.endorser.ch/api"} ADMIN_DID="did:ethr:0x0000694B58C2cC69658993A90D3840C560f2F51F" ADMIN_KEY="2b6472c026ec2aa2c4235c994a63868fc9212d18b58f6cbfe861b52e71330f5b" diff --git a/test-scripts/did_generator.sh b/test-scripts/did_generator.sh index c22a1b0..3e6cc19 100755 --- a/test-scripts/did_generator.sh +++ b/test-scripts/did_generator.sh @@ -18,10 +18,18 @@ fi ADMIN_DID=${ADMIN_DID:-"did:ethr:0x0000694B58C2cC69658993A90D3840C560f2F51F"} ADMIN_PRIVATE_KEY=${ADMIN_PRIVATE_KEY:-"2b6472c026ec2aa2c4235c994a63868fc9212d18b58f6cbfe861b52e71330f5b"} API_URL=${ENDORSER_API_URL:-"https://test-api.endorser.ch/api/v2/claim"} +DEBUG=${DEBUG:-0} + +# Function to log debug info +debug_log() { + if [ "$DEBUG" = "1" ]; then + echo "$@" >&2 + fi +} # Function to generate a new keypair generate_keypair() { - echo "Generating new keypair..." + debug_log "Generating new keypair..." # Create a temporary directory for key operations TMPDIR=$(mktemp -d) @@ -52,12 +60,13 @@ generate_keypair() { # Create DID DID="did:ethr:0x$ADDRESS" - echo "Generated DID Details:" - echo "----------------------" - echo "DID: $DID" - echo "Address: 0x$ADDRESS" - echo "Private Key: $PRIVATE_KEY" - echo "Public Key: $PUBLIC_KEY" + # Print debug info if enabled + debug_log "Generated DID Details:" + debug_log "----------------------" + debug_log "DID: $DID" + debug_log "Address: $ADDRESS" + debug_log "Private Key: $PRIVATE_KEY" + debug_log "Public Key: $PUBLIC_KEY" # Export variables for other functions export DID PRIVATE_KEY PUBLIC_KEY ADDRESS @@ -69,6 +78,67 @@ hex_to_dec() { printf "%d" "0x$1" } +# Function to attempt signing with retries +attempt_signing() { + local max_attempts=5 + local attempt=1 + + while [ $attempt -le $max_attempts ]; do + debug_log "Signing attempt $attempt of $max_attempts..." + + # Sign message and get DER format signature + openssl dgst -sha256 -sign "$TMPDIR/private.pem" "$TMPDIR/message.txt" 2>/dev/null > "$TMPDIR/signature.der" + + # Convert DER signature to hex + der_sig=$(xxd -p -c 256 "$TMPDIR/signature.der") + + debug_log "Debug - Full DER signature:" + debug_log "$der_sig" + + # Parse DER structure with length checking + 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 + seq_len="${BASH_REMATCH[1]}" + r_len="${BASH_REMATCH[2]}" + r_val="${BASH_REMATCH[3]}" + s_len="${BASH_REMATCH[4]}" + s_val="${BASH_REMATCH[5]}" + + # Convert lengths to decimal + r_len_dec=$((16#$r_len)) + s_len_dec=$((16#$s_len)) + + debug_log "R length: $r_len_dec bytes" + debug_log "S length: $s_len_dec bytes" + + # Handle R value + if [ $r_len_dec -gt 32 ]; then + r_val=${r_val: -64} # Take last 32 bytes + elif [ $r_len_dec -lt 32 ]; then + r_val=$(printf "%064s" "$r_val" | tr ' ' '0') # Left pad + fi + + # Handle S value + if [ $s_len_dec -gt 32 ]; then + s_val=${s_val: -64} # Take last 32 bytes + elif [ $s_len_dec -lt 32 ]; then + s_val=$(printf "%064s" "$s_val" | tr ' ' '0') # Left pad + fi + + # Validate final lengths + if [ ${#r_val} -eq 64 ] && [ ${#s_val} -eq 64 ]; then + debug_log "Valid signature found on attempt $attempt" + return 0 + fi + fi + + debug_log "Invalid signature on attempt $attempt, retrying..." + attempt=$((attempt + 1)) + done + + echo "Failed to generate valid signature after $max_attempts attempts" >&2 + return 1 +} + # Function to create and sign JWT create_jwt() { local now=$(date +%s) @@ -103,58 +173,25 @@ create_jwt() { # Write message to file echo -n "$message" > "$TMPDIR/message.txt" - # Sign message and get DER format signature - openssl dgst -sha256 -sign "$TMPDIR/private.pem" "$TMPDIR/message.txt" 2>/dev/null > "$TMPDIR/signature.der" - - # Convert DER signature to R+S format - der_sig=$(xxd -p -c 256 "$TMPDIR/signature.der") - - # Debug the full DER signature - echo "Debug - Full DER signature:" - echo "$der_sig" - - # Parse DER structure - more robust version - 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 - seq_len="${BASH_REMATCH[1]}" - r_len="${BASH_REMATCH[2]}" - r_val="${BASH_REMATCH[3]}" - s_len="${BASH_REMATCH[4]}" - s_val="${BASH_REMATCH[5]}" - - echo "Debug - DER parsing:" - echo "Sequence length: $seq_len" - echo "R length: $r_len" - echo "R value: $r_val" - echo "S length: $s_len" - echo "S value: $s_val" - - # Remove leading zeros if present - r_val=${r_val#"00"} - s_val=${s_val#"00"} - - # Pad R and S to 32 bytes each - r_val=$(printf "%064s" "$r_val" | tr ' ' '0') - s_val=$(printf "%064s" "$s_val" | tr ' ' '0') + # Attempt signing with retries + if attempt_signing; then + # Create final JWT + concat_sig="${r_val}${s_val}" + signature=$(echo -n "$concat_sig" | xxd -r -p | base64 -w 0 | tr '/+' '_-' | tr -d '=') + JWT="$message.$signature" - # Concatenate R+S and convert to base64url - signature=$(echo -n "${r_val}${s_val}" | xxd -r -p | base64 -w 0 | tr '/+' '_-' | tr -d '=') + debug_log "Created JWT: ${JWT:0:50}..." + export JWT + return 0 else - echo "Error: Invalid DER signature format" - echo "DER: $der_sig" + echo "Failed to generate valid signature" >&2 return 1 fi - - # Create final JWT - JWT="$message.$signature" - - echo -e "\nCreated JWT: ${JWT:0:50}..." - export JWT - return 0 } # Function to register DID register_did() { - echo "Attempting registration..." + debug_log "Attempting registration..." # Create request body body="{\"jwtEncoded\":\"$JWT\"}" @@ -166,24 +203,64 @@ register_did() { # Check response if echo "$response" | jq -e '.success' >/dev/null 2>&1; then - echo "Registration successful!" - echo "Response:" - echo "$response" | jq '.' + debug_log "Registration successful!" + debug_log "Response: $(echo "$response" | jq -c '.')" + + # Output only the JSON result + debug_log "About to output JSON..." + jq -n \ + --arg did "$DID" \ + --arg private_key "$PRIVATE_KEY" \ + --arg registration_id "$(echo "$response" | jq -r '.success.registrationId')" \ + --arg claim_id "$(echo "$response" | jq -r '.success.claimId')" \ + '{ + status: "success", + did: $did, + privateKey: $private_key, + registrationId: $registration_id, + claimId: $claim_id + }' + debug_log "JSON output complete" + exit 0 else - echo "Registration failed!" - echo "Error: $(echo "$response" | jq -r '.error.message // empty')" - echo "Full response:" - echo "$response" | jq '.' || echo "$response" + error_msg=$(echo "$response" | jq -r '.error.message // "Unknown error"') + debug_log "Registration failed: $error_msg" + debug_log "Full response: $(echo "$response" | jq -c '.' || echo "$response")" + + # Output error as JSON + jq -n \ + --arg error "$error_msg" \ + --arg stage "registration" \ + '{ + status: "error", + stage: $stage, + error: $error + }' + exit 1 fi } # Main execution -echo "Starting DID Generation..." -echo "Using admin DID: $ADMIN_DID" -echo "API URL: $API_URL" +debug_log "Starting DID Generation..." +debug_log "Using admin DID: $ADMIN_DID" +debug_log "API URL: $API_URL" -generate_keypair && \ -create_jwt && \ -register_did +if ! generate_keypair; then + jq -n '{ + status: "error", + stage: "keypair", + error: "Failed to generate keypair" + }' + exit 1 +fi + +if ! create_jwt; then + jq -n '{ + status: "error", + stage: "jwt", + error: "Failed to generate valid signature" + }' + exit 1 +fi -exit $? \ No newline at end of file +register_did \ No newline at end of file diff --git a/test-scripts/dids_seen.sh b/test-scripts/dids_seen.sh new file mode 100755 index 0000000..508d7e8 --- /dev/null +++ b/test-scripts/dids_seen.sh @@ -0,0 +1,284 @@ +#!/bin/bash +# DID Visibility Check Script +# @author Matthew Raymer +# +# This script checks visibility permissions for DIDs within the endorser.ch system. +# It creates a signed JWT using admin credentials and queries the visibility API. +# +# Features: +# - JWT creation and signing using ES256K-R +# - DID visibility checking +# - Environment variable support +# - Debug logging +# - Command line argument parsing +# +# Usage: +# ./dids_seen.sh [-d did_to_check] +# DEBUG=1 ./dids_seen.sh # For debug output +# +# Environment Variables: +# ADMIN_DID - Admin DID for authorization +# ADMIN_PRIVATE_KEY - Private key for signing +# ENDORSER_API_URL - API endpoint (defaults to test) +# DEBUG - Enable debug logging when set to 1 + +# Enhanced debug logging +debug_log() { + if [ "${DEBUG:-0}" = "1" ]; then + echo "DEBUG: $*" >&2 + fi +} + +# Parse command line arguments +# -d: Specific DID to check visibility for +CHECK_DID="" +while getopts "d:" opt; do + case $opt in + d) CHECK_DID="$OPTARG" ;; + \?) echo "Usage: $0 [-d did_to_check]" >&2; exit 1 ;; + esac +done + +# Load environment variables from .env file if present +# Supports: +# - ADMIN_DID +# - ADMIN_PRIVATE_KEY +# - ENDORSER_API_URL +if [ -f .env ]; then + export $(cat .env | grep -v '^#' | xargs) +fi + +# Default values for required parameters +ADMIN_DID=${ADMIN_DID:-"did:ethr:0x0000694B58C2cC69658993A90D3840C560f2F51F"} +ADMIN_PRIVATE_KEY=${ADMIN_PRIVATE_KEY:-"2b6472c026ec2aa2c4235c994a63868fc9212d18b58f6cbfe861b52e71330f5b"} +API_URL=${ENDORSER_API_URL:-"https://test-api.endorser.ch/api/report/whichDidsICanSee"} + +# Create JWT payload with: +# - Issuer (iss) +# - Subject (sub) +# - Issued At (iat) +# - Expiration (exp) +now=$(date +%s) +exp=$((now + 86400)) # 24 hours from now + +payload=$(jq -n \ + --arg iss "$ADMIN_DID" \ + --arg sub "$ADMIN_DID" \ + --arg iat "$now" \ + --arg exp "$exp" \ + '{ + iss: $iss, + sub: $sub, + iat: ($iat | tonumber), + exp: ($exp | tonumber) + }') + +# Base64url encode header and payload +# Header specifies ES256K-R algorithm for Ethereum compatibility +header='{"alg":"ES256K-R","typ":"JWT"}' +header_b64=$(echo -n "$header" | base64 -w 0 | tr '/+' '_-' | tr -d '=') +payload_b64=$(echo -n "$payload" | base64 -w 0 | tr '/+' '_-' | tr -d '=') + +# Create message to sign (header.payload) +message="$header_b64.$payload_b64" + +# Add debug points +debug_log "Creating JWT with:" +debug_log "ADMIN_DID: $ADMIN_DID" +debug_log "API_URL: $API_URL" +debug_log "Payload: $payload" +debug_log "Header base64: $header_b64" +debug_log "Payload base64: $payload_b64" +debug_log "Message to sign: $message" + +# Create temporary directory for key operations +# Uses trap to ensure cleanup on exit +TMPDIR=$(mktemp -d) +trap 'rm -rf "$TMPDIR"' EXIT + +# Create private key PEM file +# Converts raw private key to PEM format for OpenSSL +echo "-----BEGIN EC PRIVATE KEY-----" > "$TMPDIR/private.pem" +( + echo "302e0201010420" # Private key header + echo -n "$ADMIN_PRIVATE_KEY" # Private key bytes + echo "a00706052b8104000a" # secp256k1 OID +) | xxd -r -p | base64 >> "$TMPDIR/private.pem" +echo "-----END EC PRIVATE KEY-----" >> "$TMPDIR/private.pem" + +# Write message to file for signing +echo -n "$message" > "$TMPDIR/message.txt" + +# Sign message and get DER format signature +openssl dgst -sha256 -sign "$TMPDIR/private.pem" "$TMPDIR/message.txt" > "$TMPDIR/signature.der" + +# Convert DER signature to hex +der_sig=$(xxd -p -c 256 "$TMPDIR/signature.der") + +# Parse DER structure +# Extracts R and S values from signature +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_len="${BASH_REMATCH[2]}" + r_val="${BASH_REMATCH[3]}" + s_len="${BASH_REMATCH[4]}" + s_val="${BASH_REMATCH[5]}" + + debug_log "Raw signature values:" + debug_log " R (${#r_val} chars): $r_val" + debug_log " S (${#s_val} chars): $s_val" + + # Convert lengths to decimal + r_len_dec=$((16#$r_len)) + s_len_dec=$((16#$s_len)) + + # Handle R value padding + if [ $r_len_dec -gt 32 ]; then + r_val=${r_val: -64} # Take last 32 bytes + elif [ $r_len_dec -lt 32 ]; then + r_val=$(printf "%064s" "$r_val" | tr ' ' '0') # Left pad + fi + + # Handle S value padding + if [ $s_len_dec -gt 32 ]; then + s_val=${s_val: -64} # Take last 32 bytes + elif [ $s_len_dec -lt 32 ]; then + s_val=$(printf "%064s" "$s_val" | tr ' ' '0') # Left pad + fi + + # Ensure both values are exactly 64 characters + r_val=$(printf "%064s" "$r_val" | tr ' ' '0') + s_val=$(printf "%064s" "$s_val" | tr ' ' '0') + + debug_log "Normalized values:" + debug_log " R (${#r_val} chars): $r_val" + debug_log " S (${#s_val} chars): $s_val" + + # Create final signature + concat_sig="${r_val}${s_val}" + + # Debug the DER parsing + debug_log "DER Signature Analysis:" + debug_log " Full DER: $der_sig" + debug_log " Sequence length: ${BASH_REMATCH[1]}" + debug_log " R length: $r_len ($r_len_dec bytes)" + debug_log " S length: $s_len ($s_len_dec bytes)" + + # Debug signature components + debug_log "Signature components:" + debug_log " R value: $r_val (length: ${#r_val})" + debug_log " S value: $s_val (length: ${#s_val})" + debug_log " Concatenated: $concat_sig (length: ${#concat_sig})" + + # Try both normal and high-S value signatures + s_val_alt="" + if [ $s_len_dec -gt 32 ]; then + # Store alternative S value + s_val_alt="$s_val" + # Calculate N - s for high-S values + n="FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141" + # Use Python for hex math to avoid bc issues + normalized_s=$(python3 -c " + n = int('$n', 16) + s = int('${s_val}', 16) + result = hex(n - s)[2:].zfill(64) + print(result.lower()) + " 2>/dev/null || echo "ERROR") + if [ "$normalized_s" = "ERROR" ]; then + debug_log " Failed to normalize S value" + # Keep original s_val if normalization fails + s_val_alt="" + else + s_val=$(printf "%064s" "$normalized_s" | tr ' ' '0' | tr '[:upper:]' '[:lower:]') + debug_log " Normalized S value: $s_val" + fi + fi + + # Calculate recovery bit (v) + # Try each possible recovery value (0-3) until we find one that works + for v in {0..3}; do + # Try both S values if we have an alternative + s_values=("$s_val") + if [ -n "$s_val_alt" ]; then + s_values+=("$s_val_alt") + fi + + for current_s in "${s_values[@]}"; do + concat_sig="${r_val}${current_s}" + debug_log "Trying with S value: $current_s" + + recovery_sig=$(printf "%s%02x" "$concat_sig" "$v") + debug_log "Recovery attempt $v:" + debug_log " Concatenated signature: $concat_sig" + debug_log " Recovery signature: $recovery_sig" + debug_log " Recovery signature length: ${#recovery_sig}" + + # Ensure signature is exactly 65 bytes (130 hex chars) + if [ ${#recovery_sig} -ne 130 ]; then + debug_log " Invalid signature length: ${#recovery_sig}, expected 130" + continue + fi + + # Convert hex to binary, then to base64url + signature=$(echo -n "$recovery_sig" | xxd -r -p 2>/dev/null | base64 -w 0 | tr '/+' '_-' | tr -d '=') + debug_log " Base64URL signature: $signature" + + # Create JWT with this signature + JWT="$message.$signature" + debug_log " Testing JWT: $JWT" + + # Test the JWT against the API + response=$(curl -s -X GET "$API_URL" \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer $JWT") + debug_log " API Response: $response" + + # Check if the JWT worked + if ! echo "$response" | grep -q "JWT.*failed"; then + echo "JWT Token:" + echo "$JWT" + debug_log "Success with v=$v and S=${current_s:0:8}..." + echo + echo "Export command:" + echo "export TOKEN='$JWT'" + echo + if [ -n "$CHECK_DID" ]; then + # Check if specific DID is in the list + if echo "$response" | jq -e --arg did "$CHECK_DID" 'contains([$did])' > /dev/null; then + echo "✅ DID $CHECK_DID is in the list" + exit 0 + else + echo "❌ DID $CHECK_DID is not in the list" + echo "Attempting to add visibility..." + + # Request visibility + visibility_response=$(curl -s -X POST \ + 'http://test-api.endorser.ch/api/report/canSeeMe' \ + -H "Authorization: Bearer $JWT" \ + -H "Content-Type: application/json" \ + -d "{\"did\": \"$CHECK_DID\"}") + + if echo "$visibility_response" | grep -q "error"; then + echo "❌ Failed to add visibility:" + echo "$visibility_response" | jq '.' --indent 2 + exit 1 + else + echo "✅ Successfully requested visibility. Please try checking again." + exit 0 + fi + fi + else + # Show full list of visible DIDs + echo "$response" | jq '.' --indent 2 + fi + exit 0 + fi + done + done + + echo "Error: Could not find valid recovery bit" + exit 1 +else + echo "Error: Invalid DER signature format" + echo "DER: $der_sig" + exit 1 +fi diff --git a/test-scripts/run-deeplink-tests.sh b/test-scripts/run-deeplink-tests.sh index 8f87b50..91de29f 100755 --- a/test-scripts/run-deeplink-tests.sh +++ b/test-scripts/run-deeplink-tests.sh @@ -41,27 +41,81 @@ else # Function to extract DID info from did_generator.sh output extract_did_info() { local output="$1" - local did=$(echo "$output" | grep "^DID: " | cut -d' ' -f2-) - local private_key=$(echo "$output" | grep "^Private Key: " | cut -d' ' -f3-) - printf '%s\n' "{\"did\":\"$did\",\"privateKey\":\"$private_key\"}" + + # Debug: Show what we received + echo "DEBUG: extract_did_info received: '$output'" >&2 + + # Parse and validate JSON + if ! printf '%s' "$output" | jq -e 'if type == "object" and .status == "success" then true else false end' >/dev/null 2>&1; then + echo "Error: DID generation failed" >&2 + echo "Error details:" >&2 + if ! printf '%s' "$output" | jq -e . >/dev/null 2>&1; then + echo "Invalid JSON output: $output" >&2 + else + printf '%s' "$output" | jq -r '"\(.stage): \(.error // "Unknown error")"' >&2 + fi + return 1 + fi + + # Return the successful JSON + printf '%s' "$output" } echo "Generating first contact DID..." - 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" - echo "Extracted Key: $CONTACT1_KEY" + # Debug: Show raw command output + DEBUG_OUTPUT=$(DEBUG=0 ./test-scripts/did_generator.sh) + GEN_STATUS=$? + echo "DEBUG: Raw did_generator.sh output: '$DEBUG_OUTPUT'" >&2 + + if [ $GEN_STATUS -ne 0 ]; then + echo "Error: did_generator.sh failed with status $GEN_STATUS" >&2 + exit 1 + fi + + CONTACT1_OUTPUT=$(printf '%s' "$DEBUG_OUTPUT" | tr -d '\r') + echo "DEBUG: After tr command: '$CONTACT1_OUTPUT'" >&2 + + # Debug: Show what we're passing to extract_did_info + echo "DEBUG: Calling extract_did_info with: '$CONTACT1_OUTPUT'" >&2 + CONTACT1_INFO=$(extract_did_info "$CONTACT1_OUTPUT") + EXTRACT_STATUS=$? + echo "DEBUG: extract_did_info returned status: $EXTRACT_STATUS" >&2 + echo "DEBUG: CONTACT1_INFO: '$CONTACT1_INFO'" >&2 + + if [ $EXTRACT_STATUS -ne 0 ]; then + echo "DEBUG: extract_did_info failed" >&2 + exit 1 + fi + CONTACT1_DID=$(printf '%s' "$CONTACT1_INFO" | jq -r .did) + CONTACT1_KEY=$(printf '%s' "$CONTACT1_INFO" | jq -r .privateKey) echo "Generating second contact DID (Jordan)..." - CONTACT2_INFO=$(./test-scripts/did_generator.sh 2>&1 | tee /dev/stderr | extract_did_info) - CONTACT2_DID=$(echo "$CONTACT2_INFO" | jq -r .did) - CONTACT2_KEY=$(echo "$CONTACT2_INFO" | jq -r .privateKey) + DEBUG_OUTPUT=$(DEBUG=0 ./test-scripts/did_generator.sh) + CONTACT2_OUTPUT=$(printf '%s' "$DEBUG_OUTPUT" | tr -d '\r') + CONTACT2_INFO=$(extract_did_info "$CONTACT2_OUTPUT") + if [ $? -ne 0 ]; then + exit 1 + fi + CONTACT2_DID=$(printf '%s' "$CONTACT2_INFO" | jq -r .did) + CONTACT2_KEY=$(printf '%s' "$CONTACT2_INFO" | jq -r .privateKey) echo "Generating issuer DID..." - ISSUER_INFO=$(./test-scripts/did_generator.sh 2>&1 | tee /dev/stderr | extract_did_info) - ISSUER_DID=$(echo "$ISSUER_INFO" | jq -r .did) - ISSUER_KEY=$(echo "$ISSUER_INFO" | jq -r .privateKey) + DEBUG_OUTPUT=$(DEBUG=0 ./test-scripts/did_generator.sh) + ISSUER_OUTPUT=$(printf '%s' "$DEBUG_OUTPUT" | tr -d '\r') + ISSUER_INFO=$(extract_did_info "$ISSUER_OUTPUT") + if [ $? -ne 0 ]; then + exit 1 + fi + ISSUER_DID=$(printf '%s' "$ISSUER_INFO" | jq -r .did) + ISSUER_KEY=$(printf '%s' "$ISSUER_INFO" | jq -r .privateKey) + + # Add some visual feedback about the generated DIDs + echo + echo "Generated DIDs:" + echo " Contact 1: ${CONTACT1_DID:0:20}..." + echo " Contact 2: ${CONTACT2_DID:0:20}..." + echo " Issuer: ${ISSUER_DID:0:20}..." + echo # Create a temporary env file with the generated DIDs echo "Creating test-env.sh with generated DIDs..."