Requested: dev-token.sh/.ps1 tokens should last 3h by default, with an argument to override the duration. Server-verified finding: STALWART_RECOVERY_ADMIN (the break-glass account docker-compose.yml and the scripts used) always issues OAuth tokens with a fixed 1h expiry, regardless of the server's configured accessTokenExpiry — confirmed against the live container, including after changing the setting and restarting. Confirmed x:ApiKey objects, by contrast, support an arbitrary expiresAt set per request, and their secret works directly as a bearer token. Add scripts/dev-server-init.sh (+ .ps1): a one-time, idempotent setup step that completes the server's bootstrap wizard (default domain, no TLS certificate request), creates a real "devadmin" admin account, and sets the server's default OAuth token lifetime to 3h. Rework dev-token.sh/.ps1 to authenticate as devadmin and create an x:ApiKey with a caller-supplied expiry (`dev-token.sh 1800` for 30 minutes, defaults to 10800s/3h) instead of running the OAuth PKCE flow against the recovery account. Verified end-to-end against a fresh container, including a real browser session against the running WebUI. Also includes an incidental package-lock.json sync (was still pinned to v1.0.8 / stale dependency ranges from before the upstream merge).
58 lines
2.5 KiB
Bash
58 lines
2.5 KiB
Bash
#!/usr/bin/env bash
|
|
# Local development only. Generates a fresh access token from the local
|
|
# Stalwart dev container (see docker-compose.yml) and writes it to
|
|
# .env.development.local (gitignored). Bash equivalent of dev-token.ps1, for
|
|
# non-Windows shells (and AI agents without PowerShell).
|
|
#
|
|
# Requires scripts/dev-server-init.sh to have been run once first (creates
|
|
# the "devadmin" account this script authenticates as — the
|
|
# STALWART_RECOVERY_ADMIN account is break-glass only and always issues
|
|
# fixed 1h tokens regardless of server config, so it can't honor a custom
|
|
# duration).
|
|
#
|
|
# Usage: dev-token.sh [duration_seconds] [api_base_url]
|
|
# dev-token.sh # 3 hour token (server default, see dev-server-init.sh)
|
|
# dev-token.sh 1800 # 30 minute token
|
|
set -euo pipefail
|
|
|
|
DURATION_SECONDS="${1:-10800}"
|
|
API_BASE_URL="${2:-http://localhost:8080}"
|
|
DEVADMIN_ACCOUNT="devadmin@example.org"
|
|
DEVADMIN_SECRET="DevAdminPass123!"
|
|
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
|
|
if ! date -u -d "+1 minute" +"%Y-%m-%dT%H:%M:%SZ" >/dev/null 2>&1; then
|
|
EXPIRES_AT=$(date -u -v+"${DURATION_SECONDS}"S +"%Y-%m-%dT%H:%M:%SZ") # BSD/macOS date
|
|
else
|
|
EXPIRES_AT=$(date -u -d "+${DURATION_SECONDS} seconds" +"%Y-%m-%dT%H:%M:%SZ") # GNU date
|
|
fi
|
|
|
|
SESSION=$(curl -sf --compressed -u "$DEVADMIN_ACCOUNT:$DEVADMIN_SECRET" "$API_BASE_URL/jmap/session") || {
|
|
echo "Could not reach $API_BASE_URL as $DEVADMIN_ACCOUNT. Is the server running ('npm run dev:server') and initialized ('scripts/dev-server-init.sh')?" >&2
|
|
exit 1
|
|
}
|
|
ACCOUNT_ID=$(printf '%s' "$SESSION" | grep -o '"urn:stalwart:jmap":"[^"]*"' | cut -d'"' -f4)
|
|
|
|
REQ=$(cat <<JSON
|
|
{"using":["urn:ietf:params:jmap:core","urn:stalwart:jmap"],"methodCalls":[["x:ApiKey/set",{"accountId":"$ACCOUNT_ID","create":{"k1":{"description":"dev-token.sh","expiresAt":"$EXPIRES_AT"}}},"0"]]}
|
|
JSON
|
|
)
|
|
|
|
RESPONSE=$(curl -sf --compressed -u "$DEVADMIN_ACCOUNT:$DEVADMIN_SECRET" -X POST -H "Content-Type: application/json" -d "$REQ" "$API_BASE_URL/jmap/")
|
|
TOKEN=$(printf '%s' "$RESPONSE" | grep -o '"secret":"[^"]*"' | cut -d'"' -f4)
|
|
|
|
if [ -z "$TOKEN" ]; then
|
|
echo "Unexpected x:ApiKey/set response: $RESPONSE" >&2
|
|
exit 1
|
|
fi
|
|
|
|
ENV_PATH="$ROOT_DIR/.env.development.local"
|
|
cat > "$ENV_PATH" <<EOF
|
|
# Generated by scripts/dev-token.sh - gitignored, do not commit.
|
|
# Empty base URL: API calls stay same-origin and go through the Vite proxy.
|
|
VITE_API_BASE_URL=
|
|
VITE_ACCESS_TOKEN=$TOKEN
|
|
EOF
|
|
|
|
echo "Token written to $ENV_PATH (expires $EXPIRES_AT, in ${DURATION_SECONDS}s). Restart 'npm run dev' to pick it up."
|