mirror of
https://github.com/fosrl/pangolin.git
synced 2026-08-07 21:19:03 +02:00
use resource name in ssh/rdp/vnc page meta
This commit is contained in:
@@ -58,6 +58,7 @@ export async function getBrowserTarget(
|
|||||||
authToken: browserGatewayTarget.authToken,
|
authToken: browserGatewayTarget.authToken,
|
||||||
resourceId: resources.resourceId,
|
resourceId: resources.resourceId,
|
||||||
niceId: resources.niceId,
|
niceId: resources.niceId,
|
||||||
|
name: resources.name,
|
||||||
orgId: resources.orgId,
|
orgId: resources.orgId,
|
||||||
pamMode: resources.pamMode,
|
pamMode: resources.pamMode,
|
||||||
authDaemonMode: resources.authDaemonMode
|
authDaemonMode: resources.authDaemonMode
|
||||||
@@ -93,7 +94,8 @@ export async function getBrowserTarget(
|
|||||||
authDaemonMode: browserTarget.authDaemonMode,
|
authDaemonMode: browserTarget.authDaemonMode,
|
||||||
orgId: browserTarget.orgId,
|
orgId: browserTarget.orgId,
|
||||||
resourceId: browserTarget.resourceId,
|
resourceId: browserTarget.resourceId,
|
||||||
niceId: browserTarget.niceId
|
niceId: browserTarget.niceId,
|
||||||
|
name: browserTarget.name
|
||||||
},
|
},
|
||||||
success: true,
|
success: true,
|
||||||
error: false,
|
error: false,
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ export type GetBrowserTargetResponse = {
|
|||||||
orgId: string;
|
orgId: string;
|
||||||
resourceId: number;
|
resourceId: number;
|
||||||
niceId: string;
|
niceId: string;
|
||||||
|
name: string;
|
||||||
pamMode: "passthrough" | "push" | null;
|
pamMode: "passthrough" | "push" | null;
|
||||||
authDaemonMode: "site" | "remote" | "native" | null;
|
authDaemonMode: "site" | "remote" | "native" | null;
|
||||||
};
|
};
|
||||||
|
|||||||
+7
-24
@@ -1,34 +1,17 @@
|
|||||||
import { headers } from "next/headers";
|
import { generateBrowserGatewayMetadata } from "@app/lib/browserGatewayMetadata";
|
||||||
import { priv } from "@app/lib/api";
|
import { getBrowserTargetForRequest } from "@app/lib/getBrowserTargetForRequest";
|
||||||
import { AxiosResponse } from "axios";
|
|
||||||
import { GetBrowserTargetResponse } from "@server/routers/browserGatewayTarget";
|
|
||||||
import RdpClient from "./RdpClient";
|
import RdpClient from "./RdpClient";
|
||||||
import AuthFooter from "@app/components/AuthFooter";
|
import AuthFooter from "@app/components/AuthFooter";
|
||||||
|
|
||||||
export const dynamic = "force-dynamic";
|
export const dynamic = "force-dynamic";
|
||||||
|
|
||||||
export const metadata = {
|
export async function generateMetadata() {
|
||||||
title: "RDP"
|
return generateBrowserGatewayMetadata("RDP");
|
||||||
};
|
}
|
||||||
|
|
||||||
export default async function RdpPage() {
|
export default async function RdpPage() {
|
||||||
const headersList = await headers();
|
const { target } = await getBrowserTargetForRequest();
|
||||||
const host = headersList.get("host") || "";
|
const error = target ? null : "No resource found for this domain";
|
||||||
const hostname = host.split(":")[0];
|
|
||||||
|
|
||||||
let target: GetBrowserTargetResponse | null = null;
|
|
||||||
const error: string | null = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const res = await priv.get<AxiosResponse<GetBrowserTargetResponse>>(
|
|
||||||
`/resource/browser-target?fullDomain=${encodeURIComponent(hostname)}`
|
|
||||||
);
|
|
||||||
target = res.data.data;
|
|
||||||
console.log("Fetched browser target:", target);
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error fetching browser target:", error);
|
|
||||||
error = "No resource found for this domain";
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="h-full flex flex-col">
|
<div className="h-full flex flex-col">
|
||||||
|
|||||||
+41
-46
@@ -1,5 +1,7 @@
|
|||||||
import { headers } from "next/headers";
|
import { headers } from "next/headers";
|
||||||
import { priv } from "@app/lib/api";
|
import { priv } from "@app/lib/api";
|
||||||
|
import { generateBrowserGatewayMetadata } from "@app/lib/browserGatewayMetadata";
|
||||||
|
import { getBrowserTargetForRequest } from "@app/lib/getBrowserTargetForRequest";
|
||||||
import { AxiosResponse } from "axios";
|
import { AxiosResponse } from "axios";
|
||||||
import { GetBrowserTargetResponse } from "@server/routers/browserGatewayTarget";
|
import { GetBrowserTargetResponse } from "@server/routers/browserGatewayTarget";
|
||||||
import SshClient from "./SshClient";
|
import SshClient from "./SshClient";
|
||||||
@@ -99,14 +101,12 @@ function generateEphemeralKeyPair(): {
|
|||||||
|
|
||||||
export const dynamic = "force-dynamic";
|
export const dynamic = "force-dynamic";
|
||||||
|
|
||||||
export const metadata = {
|
export async function generateMetadata() {
|
||||||
title: "SSH"
|
return generateBrowserGatewayMetadata("SSH");
|
||||||
};
|
}
|
||||||
|
|
||||||
export default async function SshPage() {
|
export default async function SshPage() {
|
||||||
const headersList = await headers();
|
const headersList = await headers();
|
||||||
const host = headersList.get("host") || "";
|
|
||||||
const hostname = host.split(":")[0];
|
|
||||||
const cookieHeader = headersList.get("cookie") || "";
|
const cookieHeader = headersList.get("cookie") || "";
|
||||||
|
|
||||||
let target: GetBrowserTargetResponse | null = null;
|
let target: GetBrowserTargetResponse | null = null;
|
||||||
@@ -114,49 +114,44 @@ export default async function SshPage() {
|
|||||||
let privateKey: string | null = null;
|
let privateKey: string | null = null;
|
||||||
let error: string | null = null;
|
let error: string | null = null;
|
||||||
|
|
||||||
try {
|
const { target: browserTarget } = await getBrowserTargetForRequest();
|
||||||
const res = await priv.get<AxiosResponse<GetBrowserTargetResponse>>(
|
target = browserTarget;
|
||||||
`/resource/browser-target?fullDomain=${encodeURIComponent(hostname)}`
|
|
||||||
);
|
|
||||||
target = res.data.data;
|
|
||||||
|
|
||||||
if (target.pamMode === "push") {
|
if (!target) {
|
||||||
try {
|
|
||||||
const { privateKeyPem, publicKeyOpenSSH } =
|
|
||||||
generateEphemeralKeyPair();
|
|
||||||
privateKey = privateKeyPem;
|
|
||||||
const res = await priv.post<AxiosResponse<SignSshKeyResponse>>(
|
|
||||||
`/org/${target.orgId}/ssh/sign-key`,
|
|
||||||
{
|
|
||||||
publicKey: publicKeyOpenSSH,
|
|
||||||
resourceId: target.resourceId,
|
|
||||||
type: "public"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
Cookie: cookieHeader
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
signedKeyData = res.data.data;
|
|
||||||
|
|
||||||
const messageIds =
|
|
||||||
signedKeyData.messageIds.length > 0
|
|
||||||
? signedKeyData.messageIds
|
|
||||||
: signedKeyData.messageId
|
|
||||||
? [signedKeyData.messageId]
|
|
||||||
: [];
|
|
||||||
|
|
||||||
await waitForRoundTripCompletion(messageIds, cookieHeader);
|
|
||||||
} catch (err) {
|
|
||||||
console.error("Error signing SSH key:", err);
|
|
||||||
error =
|
|
||||||
"Failed to sign SSH key for PAM push authentication. Did you sign in as a user?";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.error("Error fetching browser target:", err);
|
|
||||||
error = "No resource found for this domain";
|
error = "No resource found for this domain";
|
||||||
|
} else if (target.pamMode === "push") {
|
||||||
|
try {
|
||||||
|
const { privateKeyPem, publicKeyOpenSSH } =
|
||||||
|
generateEphemeralKeyPair();
|
||||||
|
privateKey = privateKeyPem;
|
||||||
|
const res = await priv.post<AxiosResponse<SignSshKeyResponse>>(
|
||||||
|
`/org/${target.orgId}/ssh/sign-key`,
|
||||||
|
{
|
||||||
|
publicKey: publicKeyOpenSSH,
|
||||||
|
resourceId: target.resourceId,
|
||||||
|
type: "public"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Cookie: cookieHeader
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
signedKeyData = res.data.data;
|
||||||
|
|
||||||
|
const messageIds =
|
||||||
|
signedKeyData.messageIds.length > 0
|
||||||
|
? signedKeyData.messageIds
|
||||||
|
: signedKeyData.messageId
|
||||||
|
? [signedKeyData.messageId]
|
||||||
|
: [];
|
||||||
|
|
||||||
|
await waitForRoundTripCompletion(messageIds, cookieHeader);
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Error signing SSH key:", err);
|
||||||
|
error =
|
||||||
|
"Failed to sign SSH key for PAM push authentication. Did you sign in as a user?";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
+7
-23
@@ -1,33 +1,17 @@
|
|||||||
import { headers } from "next/headers";
|
import { generateBrowserGatewayMetadata } from "@app/lib/browserGatewayMetadata";
|
||||||
import { priv } from "@app/lib/api";
|
import { getBrowserTargetForRequest } from "@app/lib/getBrowserTargetForRequest";
|
||||||
import { AxiosResponse } from "axios";
|
|
||||||
import { GetBrowserTargetResponse } from "@server/routers/browserGatewayTarget";
|
|
||||||
import VncClient from "./VncClient";
|
import VncClient from "./VncClient";
|
||||||
import AuthFooter from "@app/components/AuthFooter";
|
import AuthFooter from "@app/components/AuthFooter";
|
||||||
|
|
||||||
export const dynamic = "force-dynamic";
|
export const dynamic = "force-dynamic";
|
||||||
|
|
||||||
export const metadata = {
|
export async function generateMetadata() {
|
||||||
title: "VNC"
|
return generateBrowserGatewayMetadata("VNC");
|
||||||
};
|
}
|
||||||
|
|
||||||
export default async function VncPage() {
|
export default async function VncPage() {
|
||||||
const headersList = await headers();
|
const { target } = await getBrowserTargetForRequest();
|
||||||
const host = headersList.get("host") || "";
|
const error = target ? null : "No resource found for this domain";
|
||||||
const hostname = host.split(":")[0];
|
|
||||||
|
|
||||||
let target: GetBrowserTargetResponse | null = null;
|
|
||||||
const error: string | null = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const res = await priv.get<AxiosResponse<GetBrowserTargetResponse>>(
|
|
||||||
`/resource/browser-target?fullDomain=${encodeURIComponent(hostname)}`
|
|
||||||
);
|
|
||||||
target = res.data.data;
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error fetching browser target:", error);
|
|
||||||
error = "No resource found for this domain";
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="h-full flex flex-col">
|
<div className="h-full flex flex-col">
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import { getBrowserTargetForRequest } from "@app/lib/getBrowserTargetForRequest";
|
||||||
|
import type { Metadata } from "next";
|
||||||
|
|
||||||
|
export async function generateBrowserGatewayMetadata(
|
||||||
|
protocol: "SSH" | "RDP" | "VNC"
|
||||||
|
): Promise<Metadata> {
|
||||||
|
const { target } = await getBrowserTargetForRequest();
|
||||||
|
return {
|
||||||
|
title: target?.name
|
||||||
|
? `${protocol} - ${target.name}`
|
||||||
|
: `${protocol} - Pangolin`
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import { priv } from "@app/lib/api";
|
||||||
|
import { GetBrowserTargetResponse } from "@server/routers/browserGatewayTarget";
|
||||||
|
import { AxiosResponse } from "axios";
|
||||||
|
import { headers } from "next/headers";
|
||||||
|
import { cache } from "react";
|
||||||
|
|
||||||
|
export const getBrowserTargetForRequest = cache(async () => {
|
||||||
|
const headersList = await headers();
|
||||||
|
const host = headersList.get("host") || "";
|
||||||
|
const hostname = host.split(":")[0];
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await priv.get<AxiosResponse<GetBrowserTargetResponse>>(
|
||||||
|
`/resource/browser-target?fullDomain=${encodeURIComponent(hostname)}`
|
||||||
|
);
|
||||||
|
return { target: res.data.data };
|
||||||
|
} catch {
|
||||||
|
return { target: null };
|
||||||
|
}
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user