Browse Source

refactor: improve DID generation and error handling

- Convert did_generator.sh to output clean JSON
- Add structured error reporting with stages
- Improve debug logging with DEBUG flag
- Better error handling in run-deeplink-tests.sh
- Add detailed debug tracing
- Fix JSON parsing and validation
- Add visual feedback for generated DIDs
- Use printf instead of echo for consistent output
- Remove stderr mixing with stdout
- Add proper exit status handling

This refactors the DID generation process to be more reliable
and maintainable by using structured JSON output and proper
error handling throughout the pipeline.
pull/127/head
Matthew Raymer 1 week ago
parent
commit
a974ab4f51
  1. 2
      test-scripts/check-did.sh
  2. 207
      test-scripts/did_generator.sh
  3. 82
      test-scripts/run-deeplink-tests.sh

2
test-scripts/check-did.sh

@ -3,7 +3,7 @@
# Usage: ./check-did.sh [did] # Usage: ./check-did.sh [did]
# If no DID provided, lists all visible DIDs # 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/whichDidsICanSee"}
ADMIN_DID="did:ethr:0x0000694B58C2cC69658993A90D3840C560f2F51F" ADMIN_DID="did:ethr:0x0000694B58C2cC69658993A90D3840C560f2F51F"
ADMIN_KEY="2b6472c026ec2aa2c4235c994a63868fc9212d18b58f6cbfe861b52e71330f5b" ADMIN_KEY="2b6472c026ec2aa2c4235c994a63868fc9212d18b58f6cbfe861b52e71330f5b"

207
test-scripts/did_generator.sh

@ -18,10 +18,18 @@ fi
ADMIN_DID=${ADMIN_DID:-"did:ethr:0x0000694B58C2cC69658993A90D3840C560f2F51F"} ADMIN_DID=${ADMIN_DID:-"did:ethr:0x0000694B58C2cC69658993A90D3840C560f2F51F"}
ADMIN_PRIVATE_KEY=${ADMIN_PRIVATE_KEY:-"2b6472c026ec2aa2c4235c994a63868fc9212d18b58f6cbfe861b52e71330f5b"} ADMIN_PRIVATE_KEY=${ADMIN_PRIVATE_KEY:-"2b6472c026ec2aa2c4235c994a63868fc9212d18b58f6cbfe861b52e71330f5b"}
API_URL=${ENDORSER_API_URL:-"https://test-api.endorser.ch/api/v2/claim"} 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 # Function to generate a new keypair
generate_keypair() { generate_keypair() {
echo "Generating new keypair..." debug_log "Generating new keypair..."
# Create a temporary directory for key operations # Create a temporary directory for key operations
TMPDIR=$(mktemp -d) TMPDIR=$(mktemp -d)
@ -52,12 +60,13 @@ generate_keypair() {
# Create DID # Create DID
DID="did:ethr:0x$ADDRESS" DID="did:ethr:0x$ADDRESS"
echo "Generated DID Details:" # Print debug info if enabled
echo "----------------------" debug_log "Generated DID Details:"
echo "DID: $DID" debug_log "----------------------"
echo "Address: 0x$ADDRESS" debug_log "DID: $DID"
echo "Private Key: $PRIVATE_KEY" debug_log "Address: $ADDRESS"
echo "Public Key: $PUBLIC_KEY" debug_log "Private Key: $PRIVATE_KEY"
debug_log "Public Key: $PUBLIC_KEY"
# Export variables for other functions # Export variables for other functions
export DID PRIVATE_KEY PUBLIC_KEY ADDRESS export DID PRIVATE_KEY PUBLIC_KEY ADDRESS
@ -69,6 +78,67 @@ hex_to_dec() {
printf "%d" "0x$1" 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 # Function to create and sign JWT
create_jwt() { create_jwt() {
local now=$(date +%s) local now=$(date +%s)
@ -103,58 +173,25 @@ create_jwt() {
# Write message to file # Write message to file
echo -n "$message" > "$TMPDIR/message.txt" echo -n "$message" > "$TMPDIR/message.txt"
# Sign message and get DER format signature # Attempt signing with retries
openssl dgst -sha256 -sign "$TMPDIR/private.pem" "$TMPDIR/message.txt" 2>/dev/null > "$TMPDIR/signature.der" if attempt_signing; then
# Create final JWT
# Convert DER signature to R+S format concat_sig="${r_val}${s_val}"
der_sig=$(xxd -p -c 256 "$TMPDIR/signature.der") signature=$(echo -n "$concat_sig" | xxd -r -p | base64 -w 0 | tr '/+' '_-' | tr -d '=')
JWT="$message.$signature"
# 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')
# Concatenate R+S and convert to base64url debug_log "Created JWT: ${JWT:0:50}..."
signature=$(echo -n "${r_val}${s_val}" | xxd -r -p | base64 -w 0 | tr '/+' '_-' | tr -d '=') export JWT
return 0
else else
echo "Error: Invalid DER signature format" echo "Failed to generate valid signature" >&2
echo "DER: $der_sig"
return 1 return 1
fi fi
# Create final JWT
JWT="$message.$signature"
echo -e "\nCreated JWT: ${JWT:0:50}..."
export JWT
return 0
} }
# Function to register DID # Function to register DID
register_did() { register_did() {
echo "Attempting registration..." debug_log "Attempting registration..."
# Create request body # Create request body
body="{\"jwtEncoded\":\"$JWT\"}" body="{\"jwtEncoded\":\"$JWT\"}"
@ -166,24 +203,64 @@ register_did() {
# Check response # Check response
if echo "$response" | jq -e '.success' >/dev/null 2>&1; then if echo "$response" | jq -e '.success' >/dev/null 2>&1; then
echo "Registration successful!" debug_log "Registration successful!"
echo "Response:" debug_log "Response: $(echo "$response" | jq -c '.')"
echo "$response" | jq '.'
# 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 else
echo "Registration failed!" error_msg=$(echo "$response" | jq -r '.error.message // "Unknown error"')
echo "Error: $(echo "$response" | jq -r '.error.message // empty')" debug_log "Registration failed: $error_msg"
echo "Full response:" debug_log "Full response: $(echo "$response" | jq -c '.' || echo "$response")"
echo "$response" | jq '.' || echo "$response"
# Output error as JSON
jq -n \
--arg error "$error_msg" \
--arg stage "registration" \
'{
status: "error",
stage: $stage,
error: $error
}'
exit 1
fi fi
} }
# Main execution # Main execution
echo "Starting DID Generation..." debug_log "Starting DID Generation..."
echo "Using admin DID: $ADMIN_DID" debug_log "Using admin DID: $ADMIN_DID"
echo "API URL: $API_URL" debug_log "API URL: $API_URL"
generate_keypair && \ if ! generate_keypair; then
create_jwt && \ jq -n '{
register_did 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 $? register_did

82
test-scripts/run-deeplink-tests.sh

@ -41,27 +41,81 @@ else
# Function to extract DID info from did_generator.sh output # Function to extract DID info from did_generator.sh output
extract_did_info() { extract_did_info() {
local output="$1" local output="$1"
local did=$(echo "$output" | grep "^DID: " | cut -d' ' -f2-)
local private_key=$(echo "$output" | grep "^Private Key: " | cut -d' ' -f3-) # Debug: Show what we received
printf '%s\n' "{\"did\":\"$did\",\"privateKey\":\"$private_key\"}" 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..." echo "Generating first contact DID..."
CONTACT1_INFO=$(./test-scripts/did_generator.sh 2>&1 | tee /dev/stderr | extract_did_info) # Debug: Show raw command output
CONTACT1_DID=$(echo "$CONTACT1_INFO" | jq -r .did) DEBUG_OUTPUT=$(DEBUG=0 ./test-scripts/did_generator.sh)
CONTACT1_KEY=$(echo "$CONTACT1_INFO" | jq -r .privateKey) GEN_STATUS=$?
echo "Extracted DID: $CONTACT1_DID" echo "DEBUG: Raw did_generator.sh output: '$DEBUG_OUTPUT'" >&2
echo "Extracted Key: $CONTACT1_KEY"
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)..." echo "Generating second contact DID (Jordan)..."
CONTACT2_INFO=$(./test-scripts/did_generator.sh 2>&1 | tee /dev/stderr | extract_did_info) DEBUG_OUTPUT=$(DEBUG=0 ./test-scripts/did_generator.sh)
CONTACT2_DID=$(echo "$CONTACT2_INFO" | jq -r .did) CONTACT2_OUTPUT=$(printf '%s' "$DEBUG_OUTPUT" | tr -d '\r')
CONTACT2_KEY=$(echo "$CONTACT2_INFO" | jq -r .privateKey) 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..." echo "Generating issuer DID..."
ISSUER_INFO=$(./test-scripts/did_generator.sh 2>&1 | tee /dev/stderr | extract_did_info) DEBUG_OUTPUT=$(DEBUG=0 ./test-scripts/did_generator.sh)
ISSUER_DID=$(echo "$ISSUER_INFO" | jq -r .did) ISSUER_OUTPUT=$(printf '%s' "$DEBUG_OUTPUT" | tr -d '\r')
ISSUER_KEY=$(echo "$ISSUER_INFO" | jq -r .privateKey) 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 # Create a temporary env file with the generated DIDs
echo "Creating test-env.sh with generated DIDs..." echo "Creating test-env.sh with generated DIDs..."

Loading…
Cancel
Save