#!/usr/bin/env bash # verify.sh — (re)verifica dispositivos E2EE de agentes Matrix # # Genera/sube cross-signing keys y firma el device de cada agente. # Usa el MISMO crypto store que el agente para que las keys queden disponibles. # # Uso: # ./dev-scripts/agent/verify.sh # verifica todos los habilitados con E2EE # ./dev-scripts/agent/verify.sh assistant-bot # verifica uno específico source "$(dirname "$0")/../_common.sh" load_env TARGET="${1:-}" # ── YAML helpers (simple grep-based, no deps) ──────────────────────────── yaml_val() { # Extract a simple YAML value: yaml_val file "key" # Handles both quoted and unquoted values. local file="$1" key="$2" grep -m1 "^\s*${key}:" "$file" 2>/dev/null \ | sed 's/^[^:]*:\s*//' \ | tr -d '"' \ | tr -d "'" \ | xargs } # ── Verify a single agent ──────────────────────────────────────────────── verify_agent() { local cfg="$1" local agent_id; agent_id="$(yaml_val "$cfg" "id")" local agent_dir; agent_dir="$(dirname "$cfg")" # Check E2EE is enabled local enc_enabled; enc_enabled="$(yaml_val "$cfg" "enabled")" # The first "enabled" is agent.enabled; we need encryption.enabled specifically enc_enabled="$(grep -A5 'encryption:' "$cfg" | grep -m1 'enabled:' | awk '{print $2}')" if [[ "$enc_enabled" != "true" ]]; then dim " $agent_id — E2EE deshabilitado, saltando" return 0 fi # Extract config values local user_id; user_id="$(yaml_val "$cfg" "user_id")" local username; username="$(echo "$user_id" | sed 's/@\([^:]*\):.*/\1/')" local token_env; token_env="$(yaml_val "$cfg" "access_token_env")" local pickle_env; pickle_env="$(yaml_val "$cfg" "pickle_key_env")" local recovery_env; recovery_env="$(yaml_val "$cfg" "recovery_key_env")" local store_path; store_path="$(grep -A5 'encryption:' "$cfg" | grep -m1 'store_path:' | sed 's/^[^:]*:\s*//' | tr -d '"' | xargs)" local token="${!token_env:-}" local pickle_key="${!pickle_env:-}" # Find password — convention: MATRIX_PASSWORD_ local norm; norm="$(echo "$username" | tr '-' '_' | tr '[:lower:]' '[:upper:]')" local pass_env="MATRIX_PASSWORD_${norm}" local password="${!pass_env:-}" # Validate required values if [[ -z "$token" ]]; then fail " $agent_id — $token_env no está en .env" return 1 fi if [[ -z "$password" ]]; then warn " $agent_id — $pass_env no está en .env, intentando sin password..." fi info "$agent_id — verificando device..." dim " user: $username" dim " store: $store_path" dim " pickle_env: $pickle_env" dim " token_env: $token_env" # Stop agent if running (crypto store can't be shared) local was_running=false if is_running "$agent_id"; then was_running=true info " Deteniendo $agent_id antes de verificar..." "$REPO_ROOT/dev-scripts/server/stop.sh" "$agent_id" sleep 1 fi # Build verify command local verify_bin="$REPO_ROOT/bin/verify" if [[ ! -x "$verify_bin" ]] || [[ "$(find ./cmd/verify -newer "$verify_bin" 2>/dev/null | head -1)" ]]; then info " Compilando cmd/verify..." mkdir -p "$(dirname "$verify_bin")" "$GO" build -tags goolm -o "$verify_bin" ./cmd/verify || { fail " No se pudo compilar cmd/verify" return 1 } fi # Run verification local verify_args=( --homeserver "$MATRIX_HOMESERVER" --username "$username" --token "$token" --store "$store_path" ) if [[ -n "$password" ]]; then verify_args+=(--password "$password") fi if [[ -n "$pickle_key" ]]; then verify_args+=(--pickle-key "$pickle_key") fi local output if output=$("$verify_bin" "${verify_args[@]}" 2>&1); then ok "$agent_id — verificación exitosa" # Extract recovery key from output if present local new_rk new_rk="$(echo "$output" | grep "^SSSS_RECOVERY_KEY_" | cut -d= -f2-)" if [[ -n "$new_rk" && -n "$recovery_env" ]]; then # Update .env with new recovery key (quoted — keys contain spaces) local quoted_rk="\"${new_rk}\"" if grep -q "^${recovery_env}=" "$REPO_ROOT/.env"; then sed -i "s|^${recovery_env}=.*|${recovery_env}=${quoted_rk}|" "$REPO_ROOT/.env" ok " Recovery key actualizada en .env ($recovery_env)" else echo "${recovery_env}=${quoted_rk}" >> "$REPO_ROOT/.env" ok " Recovery key añadida a .env ($recovery_env)" fi fi else warn "$agent_id — verify output:" echo "$output" # If it says keys already exist, that's usually fine if echo "$output" | grep -q "signed with cross-signing key"; then ok "$agent_id — device firmado con keys existentes" else warn "$agent_id — puede necesitar atención manual" fi fi echo "$output" | sed 's/^/ /' # Restart agent if it was running if [[ "$was_running" == "true" ]]; then info " Reiniciando $agent_id..." "$REPO_ROOT/dev-scripts/server/start.sh" "$agent_id" fi echo } # ── Main ────────────────────────────────────────────────────────────────── echo info "Verificación E2EE de agentes Matrix" echo if [[ -n "$TARGET" ]]; then cfg="$(config_path_for "$TARGET")" [[ -n "$cfg" ]] || fail "Agente '$TARGET' no encontrado" verify_agent "$cfg" else while IFS='|' read -r id version enabled desc cfg; do [[ "$enabled" == "true" ]] || continue verify_agent "$cfg" done < <(list_agents_raw) fi ok "Verificación completada"