A community based topic aggregation platform built on atproto
1#!/bin/bash
2# Generate cryptographic keys for Coves did:web DID document
3#
4# This script generates a secp256k1 (K-256) key pair as required by atproto.
5# Reference: https://atproto.com/specs/cryptography
6#
7# Key format:
8# - Curve: secp256k1 (K-256) - same as Bitcoin/Ethereum
9# - Type: Multikey
10# - Encoding: publicKeyMultibase with base58btc ('z' prefix)
11# - Multicodec: 0xe7 for secp256k1 compressed public key
12#
13# Output:
14# - Private key (hex) for PDS_PLC_ROTATION_KEY_K256_PRIVATE_KEY_HEX
15# - Public key (multibase) for did.json publicKeyMultibase field
16# - Complete did.json file
17
18set -e
19
20SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
21PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
22OUTPUT_DIR="$PROJECT_DIR/static/.well-known"
23
24# Colors
25GREEN='\033[0;32m'
26YELLOW='\033[1;33m'
27RED='\033[0;31m'
28NC='\033[0m'
29
30log() { echo -e "${GREEN}[KEYGEN]${NC} $1"; }
31warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
32error() { echo -e "${RED}[ERROR]${NC} $1"; exit 1; }
33
34# Check for required tools
35if ! command -v openssl &> /dev/null; then
36 error "openssl is required but not installed"
37fi
38
39if ! command -v python3 &> /dev/null; then
40 error "python3 is required for base58 encoding"
41fi
42
43# Check for base58 library
44if ! python3 -c "import base58" 2>/dev/null; then
45 warn "Installing base58 Python library..."
46 pip3 install base58 || error "Failed to install base58. Run: pip3 install base58"
47fi
48
49log "Generating secp256k1 key pair for did:web..."
50
51# Generate private key
52PRIVATE_KEY_PEM=$(mktemp)
53openssl ecparam -name secp256k1 -genkey -noout -out "$PRIVATE_KEY_PEM" 2>/dev/null
54
55# Extract private key as hex (for PDS config)
56PRIVATE_KEY_HEX=$(openssl ec -in "$PRIVATE_KEY_PEM" -text -noout 2>/dev/null | \
57 grep -A 3 "priv:" | tail -n 3 | tr -d ' :\n' | tr -d '\r')
58
59# Extract public key as compressed format
60# OpenSSL outputs the public key, we need to get the compressed form
61PUBLIC_KEY_HEX=$(openssl ec -in "$PRIVATE_KEY_PEM" -pubout -conv_form compressed -outform DER 2>/dev/null | \
62 tail -c 33 | xxd -p | tr -d '\n')
63
64# Clean up temp file
65rm -f "$PRIVATE_KEY_PEM"
66
67# Encode public key as multibase with multicodec
68# Multicodec 0xe7 = secp256k1 compressed public key
69# Then base58btc encode with 'z' prefix
70PUBLIC_KEY_MULTIBASE=$(python3 << EOF
71import base58
72
73# Compressed public key bytes
74pub_hex = "$PUBLIC_KEY_HEX"
75pub_bytes = bytes.fromhex(pub_hex)
76
77# Prepend multicodec 0xe7 for secp256k1-pub
78# 0xe7 as varint is just 0xe7 (single byte, < 128)
79multicodec = bytes([0xe7, 0x01]) # 0xe701 for secp256k1-pub compressed
80key_with_codec = multicodec + pub_bytes
81
82# Base58btc encode
83encoded = base58.b58encode(key_with_codec).decode('ascii')
84
85# Add 'z' prefix for multibase
86print('z' + encoded)
87EOF
88)
89
90log "Keys generated successfully!"
91echo ""
92echo "============================================"
93echo " PRIVATE KEY (keep secret!)"
94echo "============================================"
95echo ""
96echo "Add this to your .env.prod file:"
97echo ""
98echo "PDS_ROTATION_KEY=$PRIVATE_KEY_HEX"
99echo ""
100echo "============================================"
101echo " PUBLIC KEY (for did.json)"
102echo "============================================"
103echo ""
104echo "publicKeyMultibase: $PUBLIC_KEY_MULTIBASE"
105echo ""
106
107# Generate the did.json file
108log "Generating did.json..."
109
110mkdir -p "$OUTPUT_DIR"
111
112cat > "$OUTPUT_DIR/did.json" << EOF
113{
114 "id": "did:web:coves.social",
115 "alsoKnownAs": ["at://coves.social"],
116 "verificationMethod": [
117 {
118 "id": "did:web:coves.social#atproto",
119 "type": "Multikey",
120 "controller": "did:web:coves.social",
121 "publicKeyMultibase": "$PUBLIC_KEY_MULTIBASE"
122 }
123 ],
124 "service": [
125 {
126 "id": "#atproto_pds",
127 "type": "AtprotoPersonalDataServer",
128 "serviceEndpoint": "https://coves.me"
129 }
130 ]
131}
132EOF
133
134log "Created: $OUTPUT_DIR/did.json"
135echo ""
136echo "============================================"
137echo " NEXT STEPS"
138echo "============================================"
139echo ""
140echo "1. Copy the PDS_ROTATION_KEY value to your .env.prod file"
141echo ""
142echo "2. Verify the did.json looks correct:"
143echo " cat $OUTPUT_DIR/did.json"
144echo ""
145echo "3. After deployment, verify it's accessible:"
146echo " curl https://coves.social/.well-known/did.json"
147echo ""
148warn "IMPORTANT: Keep the private key secret! Only share the public key."
149warn "The did.json file with the public key IS safe to commit to git."