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]
# 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_KEY="2b6472c026ec2aa2c4235c994a63868fc9212d18b58f6cbfe861b52e71330f5b"

207
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 $?
register_did

82
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..."

Loading…
Cancel
Save