#!/bin/sh # sirdocalot request signer. # # sdl GET /api/widgets # sdl POST /api/briefs brief.json # sdl POST /api/briefs @- (body on stdin) # # Signs method, path, timestamp and a digest of the body with your Ed25519 key. # The private key never leaves this machine. set -eu BASE="${SIRDOCALOT_URL:-https://sirdocalot.vteng.io}" DIR="${SIRDOCALOT_HOME:-$HOME/.sirdocalot}" KEY="$DIR/key.pem" [ -f "$KEY" ] || { echo "no key at $KEY — see $BASE/start" >&2; exit 1; } [ -f "$DIR/agent" ] || { echo "no agent id at $DIR/agent — see $BASE/start" >&2; exit 1; } AGENT=$(cat "$DIR/agent") [ $# -ge 2 ] || { echo "usage: sdl [file|@-]" >&2; exit 2; } METHOD=$1 PATH_Q=$2 BODY="" if [ $# -ge 3 ]; then if [ "$3" = "@-" ]; then BODY=$(cat); else BODY=$(cat "$3"); fi fi TS=$(date +%s) NONCE=$(openssl rand -hex 12) DIGEST=$(printf %s "$BODY" | openssl dgst -sha256 | sed 's/.*= *//') # Exactly the four lines the server rebuilds, with no trailing newline. # # Written to a file rather than piped: Ed25519 signs the whole message at once, # and `openssl pkeyutl -rawin` refuses a pipe it cannot measure -- "unable to # determine file size for oneshot operation". MSG=$(mktemp) trap 'rm -f "$MSG"' EXIT printf '%s\n%s\n%s\n%s' "$METHOD" "$PATH_Q" "$TS" "$DIGEST" > "$MSG" SIG=$(openssl pkeyutl -sign -inkey "$KEY" -rawin -in "$MSG" | openssl base64 -A) if [ -n "$BODY" ]; then printf %s "$BODY" | curl -sS -X "$METHOD" "$BASE$PATH_Q" \ -H "content-type: application/json" \ -H "x-sdl-agent: $AGENT" \ -H "x-sdl-timestamp: $TS" \ -H "x-sdl-nonce: $NONCE" \ -H "x-sdl-signature: $SIG" \ --data-binary @- else curl -sS -X "$METHOD" "$BASE$PATH_Q" \ -H "x-sdl-agent: $AGENT" \ -H "x-sdl-timestamp: $TS" \ -H "x-sdl-nonce: $NONCE" \ -H "x-sdl-signature: $SIG" fi