enrollment: the server mints the §2.1 bootstrap link, the app consumes it
POST /admin/enroll-tokens now returns the whole link, not just the token: echolot://enroll?v=1&u=<control URL>&p=pin-sha256:<b64>&t=<token> The server is the only party that knows all three parts at once, and the part an operator gets wrong by hand is the base64 pin — which does not fail loudly, it just never matches, surfacing days later as an inscrutable TLS error. The app takes the link from a paste or from an echolot:// deep link (QR scan), and writes URL, pin and credential together or not at all. One trap the tests pin: an unencoded "+" in a query string decodes to a space, so a hand-assembled link arrives with a pin wrong by one character. Base64 has no spaces, so they are restored — unambiguous, and it cannot damage a correctly encoded pin. Also fixes a spec divergence: §2.1 names the field device_credential and the first implementation shipped "credential". Both are sent now and the client prefers the spec's; the alias goes once nothing reads it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
8166611af1
commit
ad85f3bfcd
@@ -19,13 +19,23 @@ UDP_PORT="${ECHOLOT_UDP_PORT:-8442}"
|
||||
CTL_URL="https://${CTL_HOST}:${CTL_PORT}"
|
||||
|
||||
echo "· minting enrollment token on ${SSH_HOST} ..."
|
||||
TOKEN=$(ssh -o BatchMode=yes "$SSH_HOST" \
|
||||
'curl -s -X POST http://127.0.0.1:8444/admin/enroll-tokens' \
|
||||
| python -c 'import json,sys;print(json.load(sys.stdin)["token"])')
|
||||
MINTED=$(ssh -o BatchMode=yes "$SSH_HOST" \
|
||||
'curl -s -X POST http://127.0.0.1:8444/admin/enroll-tokens')
|
||||
TOKEN=$(printf '%s' "$MINTED" | python -c 'import json,sys;print(json.load(sys.stdin)["token"])')
|
||||
# The server also returns the whole §2.1 bootstrap link. LiveEnrollmentTest redeems that link,
|
||||
# which is what proves the Go side and the Kotlin side agree on its encoding — a disagreement
|
||||
# there yields a pin wrong by one character, which fails much later and looks like anything but.
|
||||
ENROLL_URI=$(printf '%s' "$MINTED" \
|
||||
| python -c 'import json,sys;print(json.load(sys.stdin).get("enroll_uri",""))')
|
||||
|
||||
echo "· enrolling over ${CTL_URL} ..."
|
||||
CRED=$(curl -sk -X POST "${CTL_URL}/v1/enroll" -H "Authorization: Bearer ${TOKEN}" \
|
||||
| python -c 'import json,sys;print(json.load(sys.stdin)["credential"])')
|
||||
# A second token, because the one above is single-use and may be spent by LiveEnrollmentTest.
|
||||
TOKEN2=$(ssh -o BatchMode=yes "$SSH_HOST" \
|
||||
'curl -s -X POST http://127.0.0.1:8444/admin/enroll-tokens' \
|
||||
| python -c 'import json,sys;print(json.load(sys.stdin)["token"])')
|
||||
CRED=$(curl -sk -X POST "${CTL_URL}/v1/enroll" -H "Authorization: Bearer ${TOKEN2}" \
|
||||
-H "X-Echolot-App-Version: 0.2.0" \
|
||||
| python -c 'import json,sys;d=json.load(sys.stdin);print(d.get("device_credential") or d["credential"])')
|
||||
|
||||
echo "· computing SPKI pin from served cert ..."
|
||||
PIN=$(echo | openssl s_client -connect "${CTL_HOST}:${CTL_PORT}" 2>/dev/null \
|
||||
@@ -43,5 +53,6 @@ ECHOLOT_LIVE_PIN="$PIN" \
|
||||
ECHOLOT_LIVE_CRED="$CRED" \
|
||||
ECHOLOT_LIVE_UDP="${CTL_HOST}:${UDP_PORT}" \
|
||||
ECHOLOT_LIVE_TARGET="${ECHOLOT_LIVE_TARGET:-fmr}" \
|
||||
ECHOLOT_ENROLL_URI="$ENROLL_URI" \
|
||||
./gradlew "$TASK" --tests "$FILTER" --info --rerun-tasks --console=plain \
|
||||
2>&1 | grep -E "profile:|capabilities:|session:|echo |primed|mtu probe|downtrain|big_send|largest|observations bytes|Live[A-Za-z]*Test|BUILD|FAIL|PASS|^e:" || true
|
||||
2>&1 | grep -E "profile:|capabilities:|session:|echo |primed|mtu probe|downtrain|big_send|largest|observations bytes|link:|parsed:|enrolled:|refused|Live[A-Za-z]*Test|BUILD|FAIL|PASS|^e:" || true
|
||||
|
||||
Reference in New Issue
Block a user