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") {