Fix login re-auth with stale sessions and hot-dev encryption safety

- Login.tsx: Use apiClient.fetch with skipAuth to avoid auth loops
- router.go: Skip CSRF validation for /api/login endpoint
- hot-dev.sh: Detect encrypted files before generating new key to prevent data loss
This commit is contained in:
rcourtman 2025-12-20 13:45:11 +00:00
parent 969da0cad0
commit b949255868
3 changed files with 37 additions and 2 deletions

View file

@ -1,5 +1,6 @@
import { Component, createSignal, Show, onMount, lazy, Suspense } from 'solid-js';
import { logger } from '@/utils/logger';
import { apiClient } from '@/utils/apiClient';
import { STORAGE_KEYS } from '@/utils/localStorage';
const SetupWizard = lazy(() =>
@ -196,7 +197,7 @@ export const Login: Component<LoginProps> = (props) => {
try {
// Use the new login endpoint for better feedback
const response = await fetch('/api/login', {
const response = await apiClient.fetch('/api/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
@ -207,7 +208,7 @@ export const Login: Component<LoginProps> = (props) => {
password: password(),
rememberMe: rememberMe(),
}),
credentials: 'include', // Important for session cookie
skipAuth: true,
});
const data = await response.json();

View file

@ -1999,6 +1999,10 @@ func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
if req.URL.Path == "/api/security/validate-bootstrap-token" {
skipCSRF = true
}
// Skip CSRF for login to avoid blocking re-auth when a stale session cookie exists.
if req.URL.Path == "/api/login" {
skipCSRF = true
}
if strings.HasPrefix(req.URL.Path, "/api/") && !skipCSRF && !CheckCSRF(w, req) {
http.Error(w, "CSRF token validation failed", http.StatusForbidden)
LogAuditEvent("csrf_failure", "", GetClientIP(req), req.URL.Path, false, "Invalid CSRF token")

View file

@ -10,6 +10,22 @@ log_info() { printf "\033[0;34m[hot-dev]\033[0m %s\n" "$1"; }
log_warn() { printf "\033[0;33m[hot-dev] WARNING:\033[0m %s\n" "$1"; }
log_error() { printf "\033[0;31m[hot-dev] ERROR:\033[0m %s\n" "$1"; }
detect_encrypted_files() {
local data_dir=$1
local patterns=(nodes.enc* email.enc* webhooks.enc* oidc.enc* ai.enc*)
local files=()
for pattern in "${patterns[@]}"; do
for path in "${data_dir}/${pattern}"; do
if [[ -s "${path}" ]]; then
files+=("$(basename "${path}")")
fi
done
done
printf '%s\n' "${files[@]}"
}
check_dependencies() {
local missing=0
for cmd in go npm lsof; do
@ -268,6 +284,13 @@ else
elif [[ ${PULSE_DATA_DIR} == "${ROOT_DIR}/tmp/dev-config" ]]; then
DEV_KEY_FILE="${PULSE_DATA_DIR}/.encryption.key"
if [[ ! -f "${DEV_KEY_FILE}" ]]; then
mapfile -t ENCRYPTED_FILES < <(detect_encrypted_files "${PULSE_DATA_DIR}")
if [[ ${#ENCRYPTED_FILES[@]} -gt 0 ]]; then
log_error "Encryption key is missing but encrypted data exists."
log_error "Restore ${DEV_KEY_FILE} from backup before continuing."
log_error "Encrypted files: ${ENCRYPTED_FILES[*]}"
exit 1
fi
openssl rand -base64 32 > "${DEV_KEY_FILE}"
chmod 600 "${DEV_KEY_FILE}"
log_info "Generated dev encryption key at ${DEV_KEY_FILE}"
@ -275,6 +298,13 @@ else
export PULSE_ENCRYPTION_KEY="$(<"${DEV_KEY_FILE}")"
elif [[ ${HOT_DEV_USE_PROD_DATA:-false} == "true" ]]; then
# Production data mode but no key - generate one to prevent orphaned encrypted data
mapfile -t ENCRYPTED_FILES < <(detect_encrypted_files "${PULSE_DATA_DIR}")
if [[ ${#ENCRYPTED_FILES[@]} -gt 0 ]]; then
log_error "Encryption key is missing but encrypted data exists."
log_error "Restore ${PULSE_DATA_DIR}/.encryption.key from backup before continuing."
log_error "Encrypted files: ${ENCRYPTED_FILES[*]}"
exit 1
fi
log_warn "No encryption key found for ${PULSE_DATA_DIR}. Generating new key..."
openssl rand -base64 32 > "${PULSE_DATA_DIR}/.encryption.key"
chmod 600 "${PULSE_DATA_DIR}/.encryption.key"