#!/usr/bin/env bash set -euo pipefail ROOT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)" LOCAL_FILE="${SPOON_INFISICAL_LOCAL_FILE:-$ROOT_DIR/.local/infisical.env}" INFISICAL_DIR="${HOME}/.infisical" CONFIG_FILE="$INFISICAL_DIR/infisical-config.json" LOCK_FILE="$INFISICAL_DIR/.switch.lock" usage() { printf 'usage: infisical-account \n' >&2 exit 2 } require_command() { local command_name="$1" if ! command -v "$command_name" >/dev/null 2>&1; then printf 'infisical-account: required command not found: %s\n' "$command_name" >&2 exit 1 fi } require_dependencies() { require_command infisical require_command jq require_command flock } require_config() { if [[ ! -f "$CONFIG_FILE" ]]; then printf 'infisical-account: Infisical config not found at ~/.infisical/infisical-config.json.\n' >&2 printf 'Run: infisical login\n' >&2 exit 1 fi } logged_in_user_count() { jq -er ' if (.loggedInUsers | type) == "array" then .loggedInUsers | length else error("loggedInUsers missing") end ' "$CONFIG_FILE" 2>/dev/null || { printf 'infisical-account: Infisical config is invalid or missing loggedInUsers.\n' >&2 printf 'Run: infisical login\n' >&2 exit 1 } } print_logged_in_accounts() { jq -r '(.loggedInUsers // [])[] | " - \(.email)"' "$CONFIG_FILE" } trim() { local value="$1" value="${value#"${value%%[![:space:]]*}"}" value="${value%"${value##*[![:space:]]}"}" printf '%s' "$value" } strip_matching_quotes() { local value="$1" case "$value" in \"*\") value="${value#\"}"; value="${value%\"}" ;; \'*\') value="${value#\'}"; value="${value%\'}" ;; esac printf '%s' "$value" } read_project_email() { if [[ ! -f "$LOCAL_FILE" ]]; then printf 'infisical-account: multiple Infisical users are logged in, but .local/infisical.env is missing.\n\n' >&2 printf 'Create it with:\n' >&2 printf ' mkdir -p .local\n' >&2 printf ' printf "INFISICAL_EMAIL=you@example.com\\n" > .local/infisical.env\n\n' >&2 printf 'Logged-in accounts:\n' >&2 print_logged_in_accounts >&2 exit 1 fi local email="" local line key value while IFS= read -r line || [[ -n "$line" ]]; do line="$(trim "$line")" case "$line" in ''|'#'*) continue ;; esac key="$(trim "${line%%=*}")" value="${line#*=}" if [[ "$key" == "$line" ]]; then continue fi value="$(strip_matching_quotes "$(trim "$value")")" if [[ "$key" == "INFISICAL_EMAIL" ]]; then email="$value" break fi done < "$LOCAL_FILE" if [[ -z "$email" ]]; then printf 'infisical-account: .local/infisical.env must contain INFISICAL_EMAIL=you@example.com.\n' >&2 exit 1 fi printf '%s' "$email" } domain_for_email() { local email="$1" jq -er --arg email "$email" ' first((.loggedInUsers // [])[] | select(.email == $email) | .domain) ' "$CONFIG_FILE" } switch_to_email() { local email="$1" local domain domain="$(domain_for_email "$email")" || { printf 'infisical-account: configured Infisical user is not logged in locally: %s\n' "$email" >&2 printf 'Run: infisical login\n' >&2 exit 1 } local tmp tmp="$(mktemp "$INFISICAL_DIR/infisical-config.XXXXXX")" jq --arg email "$email" --arg domain "$domain" ' .loggedInUserEmail = $email | .LoggedInUserDomain = $domain ' "$CONFIG_FILE" > "$tmp" chmod 600 "$tmp" mv "$tmp" "$CONFIG_FILE" } ensure_account() { require_dependencies require_config ( flock 9 local count count="$(logged_in_user_count)" if [[ "$count" -eq 0 ]]; then printf 'infisical-account: no local Infisical users are logged in.\n' >&2 printf 'Run: infisical login\n' >&2 exit 1 fi if [[ "$count" -eq 1 ]]; then exit 0 fi local email email="$(read_project_email)" switch_to_email "$email" ) 9>"$LOCK_FILE" } status() { ensure_account local count configured active count="$(logged_in_user_count)" configured="not required" if [[ -f "$LOCAL_FILE" ]]; then configured="$(read_project_email 2>/dev/null || printf 'invalid')" fi active="$(jq -r '.loggedInUserEmail // "unknown"' "$CONFIG_FILE")" printf 'Infisical accounts logged in: %s\n' "$count" printf 'Configured project email: %s\n' "$configured" printf 'Active account after ensure: %s\n' "$active" } case "${1:-}" in ensure) ensure_account ;; status) status ;; *) usage ;; esac