Browse Source

feat: Add environment variable support for DID registration

- Bash implementation of DID creation-registration
- Move admin credentials to .env file for better security
- Add .env.example with default values
- Add dotenv support to TypeScript, Python and Bash implementations
- Update dependencies to include dotenv packages
- Fix JWT signature format in Bash implementation
- Add DER signature parsing for ES256K in Bash script

The admin DID and private key can now be configured via environment
variables, with fallback to default values if not set. This allows
for easier testing and deployment across different environments.
pull/127/head
Matthew Raymer 1 week ago
parent
commit
3dae8f7f7f
  1. 6
      .env.example
  2. 1
      .gitignore
  3. 3
      package.json
  4. 15
      test-scripts/did_generator.py
  5. 189
      test-scripts/did_generator.sh
  6. 19
      test-scripts/did_generator.ts
  7. 1
      test-scripts/requirements.txt

6
.env.example

@ -0,0 +1,6 @@
# Admin DID credentials
ADMIN_DID=did:ethr:0x0000694B58C2cC69658993A90D3840C560f2F51F
ADMIN_PRIVATE_KEY=2b6472c026ec2aa2c4235c994a63868fc9212d18b58f6cbfe861b52e71330f5b
# API Configuration
ENDORSER_API_URL=https://test-api.endorser.ch/api/v2/claim

1
.gitignore

@ -42,3 +42,4 @@ test-playwright
dist-electron-packages
ios
.ruby-version
+.env

3
package.json

@ -104,7 +104,8 @@
"vue-qrcode-reader": "^5.5.3",
"vue-router": "^4.5.0",
"web-did-resolver": "^2.0.27",
"zod": "^3.24.2"
"zod": "^3.24.2",
"dotenv": "^16.0.3"
},
"devDependencies": {
"@playwright/test": "^1.45.2",

15
test-scripts/did_generator.py

@ -22,6 +22,8 @@ Dependencies:
base64: For JWT encoding
argparse: For command-line argument parsing
pathlib: For path handling
dotenv: For environment variable loading
os: For environment variable access
Usage:
python did_generator.py [options]
@ -46,6 +48,11 @@ import argparse
import secrets
import hashlib
from pathlib import Path
from dotenv import load_dotenv
import os
# Load environment variables
load_dotenv()
class DIDRegistration:
"""
@ -305,12 +312,14 @@ def main():
parser.add_argument(
'--api-url',
help='Override API URL',
default="https://test-api.endorser.ch/api/v2/claim"
default=os.getenv('ENDORSER_API_URL', 'https://test-api.endorser.ch/api/v2/claim')
)
args = parser.parse_args()
# Get admin credentials from environment
admin_keypair = {
'did': 'did:ethr:0x0000694B58C2cC69658993A90D3840C560f2F51F',
'private_key': '2b6472c026ec2aa2c4235c994a63868fc9212d18b58f6cbfe861b52e71330f5b'
'did': os.getenv('ADMIN_DID', 'did:ethr:0x0000694B58C2cC69658993A90D3840C560f2F51F'),
'private_key': os.getenv('ADMIN_PRIVATE_KEY', '2b6472c026ec2aa2c4235c994a63868fc9212d18b58f6cbfe861b52e71330f5b')
}
admin_did = args.admin_did

189
test-scripts/did_generator.sh

@ -0,0 +1,189 @@
#!/bin/bash
# Check for required commands
for cmd in openssl xxd jq curl base64; do
if ! command -v $cmd &> /dev/null; then
echo "Error: $cmd is not installed. Please install it first."
echo "On Arch Linux: sudo pacman -S $cmd"
exit 1
fi
done
# Load environment variables
if [ -f .env ]; then
export $(cat .env | grep -v '^#' | xargs)
fi
# Default values
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"}
# Function to generate a new keypair
generate_keypair() {
echo "Generating new keypair..."
# Create a temporary directory for key operations
TMPDIR=$(mktemp -d)
trap 'rm -rf "$TMPDIR"' EXIT
# Generate private key
openssl ecparam -name secp256k1 -genkey -noout > "$TMPDIR/private.pem"
# Extract raw private key
PRIVATE_KEY=$(openssl ec -in "$TMPDIR/private.pem" -text -noout 2>/dev/null | \
grep priv -A 3 | tail -n +2 | \
tr -d '\n[:space:]:' | \
sed 's/^00//')
# Generate public key (compressed format)
PUBLIC_KEY=$(openssl ec -in "$TMPDIR/private.pem" -pubout -outform DER 2>/dev/null | \
tail -c 65 | \
xxd -p -c 65 | \
sed 's/^04/02/')
# Generate Ethereum address
ADDRESS=$(echo -n "$PUBLIC_KEY" | \
xxd -r -p | \
openssl dgst -sha3-256 -binary | \
tail -c 20 | \
xxd -p)
# 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"
# Export variables for other functions
export DID PRIVATE_KEY PUBLIC_KEY ADDRESS
return 0
}
# Function to hex_to_dec
hex_to_dec() {
printf "%d" "0x$1"
}
# Function to create and sign JWT
create_jwt() {
local now=$(date +%s)
local exp=$((now + 300))
# Create header (compact JSON)
local header='{"typ":"JWT","alg":"ES256K"}'
# Create registration claim (compact JSON)
local claim="{\"iat\":$now,\"exp\":$exp,\"sub\":\"RegisterAction\",\"vc\":{\"@context\":[\"https://www.w3.org/2018/credentials/v1\"],\"type\":[\"VerifiableCredential\"],\"credentialSubject\":{\"@context\":\"https://schema.org\",\"@type\":\"RegisterAction\",\"agent\":{\"did\":\"$ADMIN_DID\"},\"participant\":{\"did\":\"$DID\"},\"object\":\"endorser.ch\"}},\"iss\":\"$ADMIN_DID\"}"
# Base64url encode header and claim
header_b64=$(echo -n "$header" | base64 -w 0 | tr '/+' '_-' | tr -d '=')
claim_b64=$(echo -n "$claim" | base64 -w 0 | tr '/+' '_-' | tr -d '=')
# Create message to sign
message="$header_b64.$claim_b64"
# Create temporary directory for key operations
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 "$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
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')
# Concatenate R+S and convert to base64url
signature=$(echo -n "${r_val}${s_val}" | xxd -r -p | base64 -w 0 | tr '/+' '_-' | tr -d '=')
else
echo "Error: Invalid DER signature format"
echo "DER: $der_sig"
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..."
# Create request body
body="{\"jwtEncoded\":\"$JWT\"}"
# Send registration request
response=$(curl -s -X POST "$API_URL" \
-H "Content-Type: application/json" \
-d "$body")
# Check response
if echo "$response" | jq -e '.success' >/dev/null 2>&1; then
echo "Registration successful!"
echo "Response:"
echo "$response" | jq '.'
else
echo "Registration failed!"
echo "Error: $(echo "$response" | jq -r '.error.message // empty')"
echo "Full response:"
echo "$response" | jq '.' || echo "$response"
fi
}
# Main execution
echo "Starting DID Generation..."
echo "Using admin DID: $ADMIN_DID"
echo "API URL: $API_URL"
generate_keypair && \
create_jwt && \
register_did
exit $?

19
test-scripts/did_generator.ts

@ -18,6 +18,7 @@
* ethers: For Ethereum account operations
* node-fetch: For API communication
* commander: For CLI argument parsing
* dotenv: For environment variable loading
*
* Usage:
* npm run generate-did -- [options]
@ -37,16 +38,20 @@ import * as didJwt from 'did-jwt';
import { ethers } from 'ethers';
import fetch from 'node-fetch';
import { program } from 'commander';
import * as dotenv from 'dotenv';
import { config } from 'dotenv';
// Load environment variables
config();
const admin_keypair = {
did: 'did:ethr:0x0000694B58C2cC69658993A90D3840C560f2F51F',
privateKey: '2b6472c026ec2aa2c4235c994a63868fc9212d18b58f6cbfe861b52e71330f5b'
}
// Default admin DID
const DEFAULT_ADMIN_DID = admin_keypair.did;
did: process.env.ADMIN_DID || 'did:ethr:0x0000694B58C2cC69658993A90D3840C560f2F51F',
privateKey: process.env.ADMIN_PRIVATE_KEY || '2b6472c026ec2aa2c4235c994a63868fc9212d18b58f6cbfe861b52e71330f5b'
};
// Add constant for default API URL
const DEFAULT_API_URL = 'https://test-api.endorser.ch/api/v2/claim';
// Default values from environment
const DEFAULT_ADMIN_DID = admin_keypair.did;
const DEFAULT_API_URL = process.env.ENDORSER_API_URL || 'https://test-api.endorser.ch/api/v2/claim';
/**
* Result interface for DID creation process

1
test-scripts/requirements.txt

@ -3,3 +3,4 @@ eth-keys>=0.4.0
PyJWT>=2.8.0
requests>=2.31.0
cryptography>=41.0.0
python-dotenv==1.0.0
Loading…
Cancel
Save