Fix : MITM
This commit is contained in:
parent
1c3ba6ef69
commit
f4e08fcd16
11 changed files with 497 additions and 150 deletions
|
|
@ -10,6 +10,7 @@ import Image from "next/image";
|
|||
* - Start/Stop DNS replaces Save Mappings button
|
||||
* - Toggle switch removed; status badge is display-only
|
||||
* - Skips sudo modal if password is already cached
|
||||
* - Model mappings can only be edited when DNS is active
|
||||
*/
|
||||
export default function MitmToolCard({
|
||||
tool,
|
||||
|
|
@ -17,7 +18,6 @@ export default function MitmToolCard({
|
|||
onToggle,
|
||||
serverRunning,
|
||||
dnsActive,
|
||||
certCovered,
|
||||
hasCachedPassword,
|
||||
apiKeys,
|
||||
activeProviders,
|
||||
|
|
@ -104,10 +104,19 @@ export default function MitmToolCard({
|
|||
});
|
||||
const data = await res.json();
|
||||
if (!res.ok) throw new Error(data.error || "Failed to toggle DNS");
|
||||
setMessage({
|
||||
type: "success",
|
||||
text: action === "enable" ? "DNS enabled — traffic intercepted" : "DNS disabled — traffic restored",
|
||||
});
|
||||
|
||||
if (action === "enable") {
|
||||
setMessage({
|
||||
type: "success",
|
||||
text: `DNS enabled successfully. Please restart ${tool.name} to apply changes.`,
|
||||
});
|
||||
} else {
|
||||
setMessage({
|
||||
type: "success",
|
||||
text: "DNS disabled — traffic restored",
|
||||
});
|
||||
}
|
||||
|
||||
setShowPasswordModal(false);
|
||||
setSudoPassword("");
|
||||
onDnsChange?.(data);
|
||||
|
|
@ -154,7 +163,7 @@ export default function MitmToolCard({
|
|||
<Badge variant="warning" size="sm">DNS off</Badge>
|
||||
)}
|
||||
</div>
|
||||
<p className="text-xs text-text-muted truncate">{tool.mitmDomain}</p>
|
||||
<p className="text-xs text-text-muted">Intercept {tool.name} requests via MITM proxy</p>
|
||||
</div>
|
||||
</div>
|
||||
<span className={`material-symbols-outlined text-text-muted text-[20px] transition-transform ${isExpanded ? "rotate-180" : ""}`}>
|
||||
|
|
@ -166,19 +175,12 @@ export default function MitmToolCard({
|
|||
<div className="mt-4 pt-4 border-t border-border flex flex-col gap-4">
|
||||
{/* Info */}
|
||||
<div className="flex flex-col gap-0.5 text-[11px] text-text-muted px-1">
|
||||
<p>
|
||||
<span className="font-medium text-text-main">Domain:</span>{" "}
|
||||
<code className="text-[10px] bg-surface px-1 rounded">{tool.mitmDomain}</code>
|
||||
{certCovered !== undefined && (
|
||||
<span className={`ml-1.5 ${certCovered ? "text-green-600" : "text-red-500"}`}>
|
||||
<span className="material-symbols-outlined text-[11px] align-middle">
|
||||
{certCovered ? "verified" : "warning"}
|
||||
</span>
|
||||
{certCovered ? " cert OK" : " cert missing domain"}
|
||||
</span>
|
||||
)}
|
||||
</p>
|
||||
<p>Toggle DNS to redirect {tool.name} traffic through 9Router via MITM.</p>
|
||||
{!dnsActive && (
|
||||
<p className="text-amber-600 text-[10px] mt-1">
|
||||
⚠️ Enable DNS to edit model mappings
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{message && (
|
||||
|
|
@ -201,12 +203,13 @@ export default function MitmToolCard({
|
|||
onChange={(e) => handleModelMappingChange(model.alias, e.target.value)}
|
||||
onBlur={(e) => handleMappingBlur(model.alias, e.target.value)}
|
||||
placeholder="provider/model-id"
|
||||
className="flex-1 px-2 py-1.5 bg-surface rounded border border-border text-xs focus:outline-none focus:ring-1 focus:ring-primary/50"
|
||||
disabled={!dnsActive}
|
||||
className={`flex-1 px-2 py-1.5 bg-surface rounded border border-border text-xs focus:outline-none focus:ring-1 focus:ring-primary/50 ${!dnsActive ? "opacity-50 cursor-not-allowed" : ""}`}
|
||||
/>
|
||||
<button
|
||||
onClick={() => openModelSelector(model.alias)}
|
||||
disabled={!hasActiveProviders}
|
||||
className={`px-2 py-1.5 rounded border text-xs transition-colors shrink-0 ${hasActiveProviders ? "bg-surface border-border hover:border-primary cursor-pointer" : "opacity-50 cursor-not-allowed border-border"}`}
|
||||
disabled={!hasActiveProviders || !dnsActive}
|
||||
className={`px-2 py-1.5 rounded border text-xs transition-colors shrink-0 ${hasActiveProviders && dnsActive ? "bg-surface border-border hover:border-primary cursor-pointer" : "opacity-50 cursor-not-allowed border-border"}`}
|
||||
>
|
||||
Select
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ export default function MitmPageClient() {
|
|||
const [apiKeys, setApiKeys] = useState([]);
|
||||
const [cloudEnabled, setCloudEnabled] = useState(false);
|
||||
const [expandedTool, setExpandedTool] = useState(null);
|
||||
const [mitmStatus, setMitmStatus] = useState({ running: false, certExists: false, dnsStatus: {}, certCoversTools: {}, hasCachedPassword: false });
|
||||
const [mitmStatus, setMitmStatus] = useState({ running: false, certExists: false, dnsStatus: {}, hasCachedPassword: false });
|
||||
|
||||
useEffect(() => {
|
||||
fetchConnections();
|
||||
|
|
@ -78,7 +78,6 @@ export default function MitmPageClient() {
|
|||
onToggle={() => setExpandedTool(expandedTool === toolId ? null : toolId)}
|
||||
serverRunning={mitmStatus.running}
|
||||
dnsActive={mitmStatus.dnsStatus?.[toolId] || false}
|
||||
certCovered={mitmStatus.certCoversTools?.[toolId] || false}
|
||||
hasCachedPassword={mitmStatus.hasCachedPassword || false}
|
||||
apiKeys={apiKeys}
|
||||
activeProviders={getActiveProviders()}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
import { NextResponse } from "next/server";
|
||||
import { getMitmAlias, setMitmAliasAll } from "@/models";
|
||||
import { getMitmStatus } from "@/mitm/manager";
|
||||
|
||||
// GET - Get MITM aliases for a tool
|
||||
export async function GET(request) {
|
||||
|
|
@ -25,6 +26,15 @@ export async function PUT(request) {
|
|||
return NextResponse.json({ error: "tool and mappings required" }, { status: 400 });
|
||||
}
|
||||
|
||||
// Check if DNS is enabled for this tool
|
||||
const status = await getMitmStatus();
|
||||
if (!status.dnsStatus || !status.dnsStatus[tool]) {
|
||||
return NextResponse.json(
|
||||
{ error: `DNS must be enabled for ${tool} before editing model mappings` },
|
||||
{ status: 403 }
|
||||
);
|
||||
}
|
||||
|
||||
const filtered = {};
|
||||
for (const [alias, model] of Object.entries(mappings)) {
|
||||
if (model && model.trim()) {
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ export async function GET() {
|
|||
pid: status.pid || null,
|
||||
certExists: status.certExists || false,
|
||||
dnsStatus: status.dnsStatus || {},
|
||||
certCoversTools: status.certCoversTools || {},
|
||||
hasCachedPassword: !!getCachedPassword(),
|
||||
});
|
||||
} catch (error) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue