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:
parent
969da0cad0
commit
b949255868
3 changed files with 37 additions and 2 deletions
|
|
@ -1,5 +1,6 @@
|
||||||
import { Component, createSignal, Show, onMount, lazy, Suspense } from 'solid-js';
|
import { Component, createSignal, Show, onMount, lazy, Suspense } from 'solid-js';
|
||||||
import { logger } from '@/utils/logger';
|
import { logger } from '@/utils/logger';
|
||||||
|
import { apiClient } from '@/utils/apiClient';
|
||||||
import { STORAGE_KEYS } from '@/utils/localStorage';
|
import { STORAGE_KEYS } from '@/utils/localStorage';
|
||||||
|
|
||||||
const SetupWizard = lazy(() =>
|
const SetupWizard = lazy(() =>
|
||||||
|
|
@ -196,7 +197,7 @@ export const Login: Component<LoginProps> = (props) => {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Use the new login endpoint for better feedback
|
// Use the new login endpoint for better feedback
|
||||||
const response = await fetch('/api/login', {
|
const response = await apiClient.fetch('/api/login', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
|
|
@ -207,7 +208,7 @@ export const Login: Component<LoginProps> = (props) => {
|
||||||
password: password(),
|
password: password(),
|
||||||
rememberMe: rememberMe(),
|
rememberMe: rememberMe(),
|
||||||
}),
|
}),
|
||||||
credentials: 'include', // Important for session cookie
|
skipAuth: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
|
|
|
||||||
|
|
@ -1999,6 +1999,10 @@ func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
if req.URL.Path == "/api/security/validate-bootstrap-token" {
|
if req.URL.Path == "/api/security/validate-bootstrap-token" {
|
||||||
skipCSRF = true
|
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) {
|
if strings.HasPrefix(req.URL.Path, "/api/") && !skipCSRF && !CheckCSRF(w, req) {
|
||||||
http.Error(w, "CSRF token validation failed", http.StatusForbidden)
|
http.Error(w, "CSRF token validation failed", http.StatusForbidden)
|
||||||
LogAuditEvent("csrf_failure", "", GetClientIP(req), req.URL.Path, false, "Invalid CSRF token")
|
LogAuditEvent("csrf_failure", "", GetClientIP(req), req.URL.Path, false, "Invalid CSRF token")
|
||||||
|
|
|
||||||
|
|
@ -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_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"; }
|
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() {
|
check_dependencies() {
|
||||||
local missing=0
|
local missing=0
|
||||||
for cmd in go npm lsof; do
|
for cmd in go npm lsof; do
|
||||||
|
|
@ -268,6 +284,13 @@ else
|
||||||
elif [[ ${PULSE_DATA_DIR} == "${ROOT_DIR}/tmp/dev-config" ]]; then
|
elif [[ ${PULSE_DATA_DIR} == "${ROOT_DIR}/tmp/dev-config" ]]; then
|
||||||
DEV_KEY_FILE="${PULSE_DATA_DIR}/.encryption.key"
|
DEV_KEY_FILE="${PULSE_DATA_DIR}/.encryption.key"
|
||||||
if [[ ! -f "${DEV_KEY_FILE}" ]]; then
|
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}"
|
openssl rand -base64 32 > "${DEV_KEY_FILE}"
|
||||||
chmod 600 "${DEV_KEY_FILE}"
|
chmod 600 "${DEV_KEY_FILE}"
|
||||||
log_info "Generated dev encryption key at ${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}")"
|
export PULSE_ENCRYPTION_KEY="$(<"${DEV_KEY_FILE}")"
|
||||||
elif [[ ${HOT_DEV_USE_PROD_DATA:-false} == "true" ]]; then
|
elif [[ ${HOT_DEV_USE_PROD_DATA:-false} == "true" ]]; then
|
||||||
# Production data mode but no key - generate one to prevent orphaned encrypted data
|
# 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..."
|
log_warn "No encryption key found for ${PULSE_DATA_DIR}. Generating new key..."
|
||||||
openssl rand -base64 32 > "${PULSE_DATA_DIR}/.encryption.key"
|
openssl rand -base64 32 > "${PULSE_DATA_DIR}/.encryption.key"
|
||||||
chmod 600 "${PULSE_DATA_DIR}/.encryption.key"
|
chmod 600 "${PULSE_DATA_DIR}/.encryption.key"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue