forked from trent_larson/crowd-funder-for-time-pwa
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.
This commit is contained in:
@@ -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()
|
||||
admin_keypair = {
|
||||
'did': 'did:ethr:0x0000694B58C2cC69658993A90D3840C560f2F51F',
|
||||
'private_key': '2b6472c026ec2aa2c4235c994a63868fc9212d18b58f6cbfe861b52e71330f5b'
|
||||
|
||||
# Get admin credentials from environment
|
||||
admin_keypair = {
|
||||
'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
Executable file
189
test-scripts/did_generator.sh
Executable file
@@ -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 $?
|
||||
@@ -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';
|
||||
|
||||
const admin_keypair = {
|
||||
did: 'did:ethr:0x0000694B58C2cC69658993A90D3840C560f2F51F',
|
||||
privateKey: '2b6472c026ec2aa2c4235c994a63868fc9212d18b58f6cbfe861b52e71330f5b'
|
||||
}
|
||||
// Default admin DID
|
||||
// Load environment variables
|
||||
config();
|
||||
|
||||
const admin_keypair = {
|
||||
did: process.env.ADMIN_DID || 'did:ethr:0x0000694B58C2cC69658993A90D3840C560f2F51F',
|
||||
privateKey: process.env.ADMIN_PRIVATE_KEY || '2b6472c026ec2aa2c4235c994a63868fc9212d18b58f6cbfe861b52e71330f5b'
|
||||
};
|
||||
|
||||
// Default values from environment
|
||||
const DEFAULT_ADMIN_DID = admin_keypair.did;
|
||||
|
||||
// Add constant for default API URL
|
||||
const DEFAULT_API_URL = 'https://test-api.endorser.ch/api/v2/claim';
|
||||
const DEFAULT_API_URL = process.env.ENDORSER_API_URL || 'https://test-api.endorser.ch/api/v2/claim';
|
||||
|
||||
/**
|
||||
* Result interface for DID creation process
|
||||
|
||||
@@ -2,4 +2,5 @@ eth-account>=0.8.0
|
||||
eth-keys>=0.4.0
|
||||
PyJWT>=2.8.0
|
||||
requests>=2.31.0
|
||||
cryptography>=41.0.0
|
||||
cryptography>=41.0.0
|
||||
python-dotenv==1.0.0
|
||||
Reference in New Issue
Block a user