fix(auth): real client IP rate-limiting + remote default-password guard

- Add custom-server.js: inject unspoofable socket IP, strip client XFF
  (wired into Docker CMD + CLI spawn + build-cli copy)
- loginLimiter: key on trusted x-9r-real-ip, TRUST_PROXY opt-in, global fallback
- Force password change on first remote login while default is in use
- Add /api/auth/reset-password (local-only) so CLI reset writes live SQLite
- CLI settings: reset via API instead of stale db.json
- Fix OAuth modals opening duplicate browser tabs on add-connection
- Add cli:pack / cli:publish scripts

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
decolua
2026-06-08 12:10:02 +07:00
co-authored by Cursor
parent c572c68717
commit 7648c3412b
17 changed files with 185 additions and 44 deletions
+12 -3
View File
@@ -1,6 +1,6 @@
"use client";
import { useState, useEffect } from "react";
import { useState, useEffect, useRef } from "react";
import PropTypes from "prop-types";
import { Modal, Button, Input } from "@/shared/components";
import { useCopyToClipboard } from "@/shared/hooks/useCopyToClipboard";
@@ -16,6 +16,12 @@ export default function KiroSocialOAuthModal({ isOpen, provider, onSuccess, onCl
const [callbackUrl, setCallbackUrl] = useState("");
const [error, setError] = useState(null);
const { copied, copy } = useCopyToClipboard();
const openedRef = useRef(false);
// Reset auto-open guard when modal closes so it can re-open next session.
useEffect(() => {
if (!isOpen) openedRef.current = false;
}, [isOpen]);
// Initialize auth flow
useEffect(() => {
@@ -37,8 +43,11 @@ export default function KiroSocialOAuthModal({ isOpen, provider, onSuccess, onCl
setAuthUrl(data.authUrl);
setStep("input");
// Auto-open browser
window.open(data.authUrl, "_blank");
// Auto-open browser once per modal session.
if (!openedRef.current) {
openedRef.current = true;
window.open(data.authUrl, "_blank");
}
} catch (err) {
setError(err.message);
setStep("error");
+5
View File
@@ -20,6 +20,7 @@ export default function OAuthModal({ isOpen, provider, providerInfo, onSuccess,
const [polling, setPolling] = useState(false);
const popupRef = useRef(null);
const pollingAbortRef = useRef(false);
const openedRef = useRef(false);
const { copied, copy } = useCopyToClipboard();
// State for client-only values to avoid hydration mismatch
@@ -310,6 +311,9 @@ export default function OAuthModal({ isOpen, provider, providerInfo, onSuccess,
// Reset state and start OAuth when modal opens
useEffect(() => {
if (isOpen && provider) {
// Guard against StrictMode/effect re-runs auto-opening multiple tabs.
if (openedRef.current) return;
openedRef.current = true;
setAuthData(null);
setCallbackUrl("");
setError(null);
@@ -321,6 +325,7 @@ export default function OAuthModal({ isOpen, provider, providerInfo, onSuccess,
} else if (!isOpen) {
// Abort polling and cleanup proxy when modal closes
pollingAbortRef.current = true;
openedRef.current = false;
if (provider === "codex") {
fetch("/api/oauth/codex/stop-proxy").catch(() => {});
} else if (provider === "xai") {
+13 -1
View File
@@ -8,7 +8,7 @@ import {
isTunnelManuallyDisabled, isTunnelReconnecting, isTailscaleReconnecting,
getTunnelService, getTailscaleService, setTunnelUnexpectedExitCallback,
killCloudflared, isCloudflaredRunning, ensureCloudflared,
isTailscaleRunning, isTailscaleRunningStrict,
isTailscaleRunning, isTailscaleRunningStrict, isDaemonAlive, startFunnel,
checkInternet,
RESTART_COOLDOWN_MS, NETWORK_SETTLE_MS,
WATCHDOG_INTERVAL_MS, NETWORK_CHECK_INTERVAL_MS, VIRTUAL_IFACE_REGEX,
@@ -176,6 +176,18 @@ async function safeRestartTailscale(reason) {
const running = reason === "startup" ? await isTailscaleRunningStrict() : isTailscaleRunning();
if (running) return;
// Daemon alive but funnel dropped → recover funnel only; never full-restart (preserves login/daemon).
if (isDaemonAlive() && svc.activeLocalPort) {
try {
await startFunnel(svc.activeLocalPort);
svc.lastRestartAt = Date.now();
console.log("[Tailscale] funnel re-established (daemon alive)");
} catch (err) {
console.log("[Tailscale] funnel recovery failed:", err.message);
}
return;
}
const force = FORCE_RESTART_REASONS.test(reason);
if (!force && Date.now() - svc.lastRestartAt < RESTART_COOLDOWN_MS) {
console.log(`[Tailscale] degraded but cooldown active, skip (${reason})`);