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.
Matthew Raymer 3 months 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