fix: harden secrets and session checks

This commit is contained in:
JetSprow
2026-04-29 17:18:36 +10:00
parent 69be1d6fcc
commit 58fa4fefa4
44 changed files with 454 additions and 154 deletions

View File

@@ -1,8 +1,13 @@
import type { Prisma } from "@prisma/client";
import { prisma } from "@/lib/prisma";
import { notFound } from "next/navigation";
import { sanitizeInboundSettings, sanitizeStreamSettings } from "@/services/node-inbound-sanitize";
const nodeDetailInclude = {
const nodeDetailSelect = {
id: true,
name: true,
panelUrl: true,
status: true,
inbounds: {
where: { isActive: true },
orderBy: { updatedAt: "desc" },
@@ -12,17 +17,25 @@ const nodeDetailInclude = {
},
},
},
} satisfies Prisma.NodeServerInclude;
} satisfies Prisma.NodeServerSelect;
export type NodeDetail = Prisma.NodeServerGetPayload<{
include: typeof nodeDetailInclude;
select: typeof nodeDetailSelect;
}>;
export async function getNodeDetail(id: string): Promise<NodeDetail> {
const node = await prisma.nodeServer.findUnique({
where: { id },
include: nodeDetailInclude,
select: nodeDetailSelect,
});
if (!node) notFound();
return node;
return {
...node,
inbounds: node.inbounds.map((inbound) => ({
...inbound,
settings: sanitizeInboundSettings(inbound.settings),
streamSettings: sanitizeStreamSettings(inbound.streamSettings),
})),
};
}

View File

@@ -60,7 +60,6 @@ function NodeCard({ node, siteUrl }: { node: NodeServerRow; siteUrl: string | nu
name: node.name,
panelUrl: node.panelUrl,
panelUsername: node.panelUsername,
panelPassword: node.panelPassword,
}}
triggerLabel="编辑"
triggerVariant="outline"

View File

@@ -22,7 +22,6 @@ interface NodeFormValue {
name: string;
panelUrl: string | null;
panelUsername: string | null;
panelPassword: string | null;
}
export function NodeForm({
@@ -92,7 +91,13 @@ export function NodeForm({
</div>
<div>
<Label></Label>
<Input name="panelPassword" type="password" defaultValue={node?.panelPassword ?? ""} required />
<Input
name="panelPassword"
type="password"
placeholder={isEdit ? "留空则沿用当前密码" : "请输入面板密码"}
required={!isEdit}
autoComplete="new-password"
/>
</div>
</div>

View File

@@ -2,8 +2,15 @@ import type { Prisma } from "@prisma/client";
import { prisma } from "@/lib/prisma";
import { parsePage } from "@/lib/utils";
import { getConfiguredSiteUrl } from "@/services/site-url";
import { sanitizeInboundSettings } from "@/services/node-inbound-sanitize";
const nodeInclude = {
const nodeSelect = {
id: true,
name: true,
panelUrl: true,
panelUsername: true,
status: true,
agentToken: true,
_count: { select: { inbounds: true } },
inbounds: {
where: { isActive: true },
@@ -16,10 +23,10 @@ const nodeInclude = {
},
orderBy: { updatedAt: "desc" },
},
} satisfies Prisma.NodeServerInclude;
} satisfies Prisma.NodeServerSelect;
export type NodeServerRow = Prisma.NodeServerGetPayload<{
include: typeof nodeInclude;
select: typeof nodeSelect;
}>;
export async function getNodeServers(
@@ -44,7 +51,7 @@ export async function getNodeServers(
const [nodes, total, siteUrl] = await Promise.all([
prisma.nodeServer.findMany({
where,
include: nodeInclude,
select: nodeSelect,
orderBy: { createdAt: "desc" },
skip,
take: pageSize,
@@ -53,5 +60,14 @@ export async function getNodeServers(
getConfiguredSiteUrl(),
]);
return { nodes, total, page, pageSize, filters: { q, status }, siteUrl };
const safeNodes = nodes.map((node) => ({
...node,
agentToken: node.agentToken ? "configured" : null,
inbounds: node.inbounds.map((inbound) => ({
...inbound,
settings: sanitizeInboundSettings(inbound.settings),
})),
}));
return { nodes: safeNodes, total, page, pageSize, filters: { q, status }, siteUrl };
}