Fix Nitro client launcher: read the nitro_path setting
The /client launcher read a non-existent `nitro_client_url` setting, so it
always fell through to "No client configured" and the client never launched.
Faithful to AtomCMS's NitroController + nitro.blade.php, build the launch URL
as {nitro_path}/index.html?sso=<ticket> plus the toolbar colour params, via a
shared buildNitroClientUrl helper. The Flash launcher's Nitro fallback used the
same dead key and is fixed too.
This commit is contained in:
1 parent
54ec99de6d
commit
56cd6fd058
4 files changed
+62
-26
No files matched your search
@@ -3,6 +3,7 @@ import { headers } from "next/headers";
|
|||||||
import { redirect } from "next/navigation";
|
import { redirect } from "next/navigation";
|
||||||
import { ContentCard, EmptyState } from "@/components/public/ui";
|
import { ContentCard, EmptyState } from "@/components/public/ui";
|
||||||
import { issueSsoTicket } from "@/lib/auth/sso-ticket";
|
import { issueSsoTicket } from "@/lib/auth/sso-ticket";
|
||||||
|
import { buildNitroClientUrl } from "@/lib/services/clients";
|
||||||
import { auth } from "@/lib/auth";
|
import { auth } from "@/lib/auth";
|
||||||
import { prisma } from "@/lib/prisma";
|
import { prisma } from "@/lib/prisma";
|
||||||
import { siteSettings } from "@/lib/services/site-settings";
|
import { siteSettings } from "@/lib/services/site-settings";
|
||||||
@@ -14,17 +15,13 @@ export default async function FlashClientPage() {
|
|||||||
if (!session?.user?.id) redirect("/login");
|
if (!session?.user?.id) redirect("/login");
|
||||||
|
|
||||||
const userId = Number(session.user.id);
|
const userId = Number(session.user.id);
|
||||||
// The Flash client URL may be stored under either key depending on the
|
// The Flash client base URL may be stored under either settings key.
|
||||||
// AtomCMS settings seed — try both, then fall back to the Nitro URL so the
|
const [hotelNameRaw, flashUrl, flashUrlAlt] = await Promise.all([
|
||||||
// launcher still issues a working SSO ticket.
|
|
||||||
const [hotelName, flashUrl, flashUrlAlt, nitroUrl] = await Promise.all([
|
|
||||||
siteSettings.get("hotel_name", "Atom").catch(() => "Atom"),
|
siteSettings.get("hotel_name", "Atom").catch(() => "Atom"),
|
||||||
siteSettings.get("flash_client_url", "").catch(() => ""),
|
siteSettings.get("flash_client_url", "").catch(() => ""),
|
||||||
siteSettings.get("client_flash_url", "").catch(() => ""),
|
siteSettings.get("client_flash_url", "").catch(() => ""),
|
||||||
siteSettings.get("nitro_client_url", "").catch(() => ""),
|
|
||||||
]);
|
]);
|
||||||
|
const hotelName = hotelNameRaw ?? "Atom";
|
||||||
const clientUrl = flashUrl || flashUrlAlt || nitroUrl || "";
|
|
||||||
|
|
||||||
const hdrs = await headers();
|
const hdrs = await headers();
|
||||||
const ip =
|
const ip =
|
||||||
@@ -32,11 +29,15 @@ export default async function FlashClientPage() {
|
|||||||
|
|
||||||
// Faithful to AtomCMS's client controllers: issue (and persist) the SSO ticket
|
// Faithful to AtomCMS's client controllers: issue (and persist) the SSO ticket
|
||||||
// on the launcher render, then hand it to the Flash client.
|
// on the launcher render, then hand it to the Flash client.
|
||||||
const ticket = await issueSsoTicket(prisma, userId, hotelName ?? "Atom", ip);
|
const ticket = await issueSsoTicket(prisma, userId, hotelName, ip);
|
||||||
|
|
||||||
const src = clientUrl
|
// Use a configured Flash base URL (with the SSO ticket appended); otherwise
|
||||||
? `${clientUrl}${clientUrl.includes("?") ? "&" : "?"}sso=${encodeURIComponent(ticket)}`
|
// fall back to the Nitro client so the launcher still works.
|
||||||
|
const flashBase = flashUrl || flashUrlAlt || "";
|
||||||
|
const flashSrc = flashBase
|
||||||
|
? `${flashBase}${flashBase.includes("?") ? "&" : "?"}sso=${encodeURIComponent(ticket)}`
|
||||||
: "";
|
: "";
|
||||||
|
const src = flashSrc || (await buildNitroClientUrl(ticket));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main style={{ display: "grid", gap: "1.5rem" }}>
|
<main style={{ display: "grid", gap: "1.5rem" }}>
|
||||||
|
|||||||
+11
-15
@@ -3,6 +3,7 @@ import { headers } from "next/headers";
|
|||||||
import { redirect } from "next/navigation";
|
import { redirect } from "next/navigation";
|
||||||
import { ContentCard, EmptyState } from "@/components/public/ui";
|
import { ContentCard, EmptyState } from "@/components/public/ui";
|
||||||
import { issueSsoTicket } from "@/lib/auth/sso-ticket";
|
import { issueSsoTicket } from "@/lib/auth/sso-ticket";
|
||||||
|
import { buildNitroClientUrl } from "@/lib/services/clients";
|
||||||
import { auth } from "@/lib/auth";
|
import { auth } from "@/lib/auth";
|
||||||
import { prisma } from "@/lib/prisma";
|
import { prisma } from "@/lib/prisma";
|
||||||
import { siteSettings } from "@/lib/services/site-settings";
|
import { siteSettings } from "@/lib/services/site-settings";
|
||||||
@@ -14,28 +15,22 @@ export default async function ClientPage() {
|
|||||||
if (!session?.user?.id) redirect("/login");
|
if (!session?.user?.id) redirect("/login");
|
||||||
|
|
||||||
const userId = Number(session.user.id);
|
const userId = Number(session.user.id);
|
||||||
const [hotelName, clientUrl] = await Promise.all([
|
const hotelName = (await siteSettings.get("hotel_name", "Atom")) ?? "Atom";
|
||||||
siteSettings.get("hotel_name", "Atom"),
|
|
||||||
siteSettings.get("nitro_client_url", ""),
|
|
||||||
]);
|
|
||||||
|
|
||||||
const hdrs = await headers();
|
const hdrs = await headers();
|
||||||
const ip =
|
const ip =
|
||||||
hdrs.get("x-forwarded-for")?.split(",")[0]?.trim() ?? hdrs.get("x-real-ip") ?? "0.0.0.0";
|
hdrs.get("x-forwarded-for")?.split(",")[0]?.trim() ?? hdrs.get("x-real-ip") ?? "0.0.0.0";
|
||||||
|
|
||||||
// Faithful to AtomCMS's NitroController: issue (and persist) the SSO ticket on
|
// Faithful to AtomCMS's NitroController: issue (and persist) the SSO ticket on
|
||||||
// the launcher render, then hand it to the client.
|
// the launcher render, then hand it to the Nitro client at {nitro_path}.
|
||||||
const ticket = await issueSsoTicket(prisma, userId, hotelName ?? "Atom", ip);
|
const ticket = await issueSsoTicket(prisma, userId, hotelName, ip);
|
||||||
|
const src = await buildNitroClientUrl(ticket);
|
||||||
const src = clientUrl
|
|
||||||
? `${clientUrl}${clientUrl.includes("?") ? "&" : "?"}sso=${encodeURIComponent(ticket)}`
|
|
||||||
: "";
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main style={{ display: "grid", gap: "1.5rem" }}>
|
<main style={{ display: "grid", gap: "1.5rem" }}>
|
||||||
<ContentCard
|
<ContentCard
|
||||||
icon="🏨"
|
icon="🏨"
|
||||||
title={`Launching ${hotelName ?? "Atom"}…`}
|
title={`Launching ${hotelName}…`}
|
||||||
subtitle="Your single sign-on ticket is ready"
|
subtitle="Your single sign-on ticket is ready"
|
||||||
action={
|
action={
|
||||||
<Link href="/client/flash" className="btn btn-outline">
|
<Link href="/client/flash" className="btn btn-outline">
|
||||||
@@ -49,14 +44,15 @@ export default async function ClientPage() {
|
|||||||
<iframe
|
<iframe
|
||||||
title="Hotel client"
|
title="Hotel client"
|
||||||
src={src}
|
src={src}
|
||||||
style={{ width: "100%", height: "80vh", border: 0, borderRadius: 10, display: "block" }}
|
style={{ width: "100%", height: "85vh", border: 0, borderRadius: 10, display: "block" }}
|
||||||
/>
|
/>
|
||||||
</ContentCard>
|
</ContentCard>
|
||||||
) : (
|
) : (
|
||||||
<ContentCard icon="🔌" title="No client configured" subtitle="Set nitro_client_url in settings">
|
<ContentCard icon="🔌" title="No client configured" subtitle="Set nitro_path in settings">
|
||||||
<EmptyState icon="🔌">
|
<EmptyState icon="🔌">
|
||||||
No client URL configured (set <code>nitro_client_url</code> in settings). SSO ticket
|
No Nitro client configured — set <code>nitro_path</code> (e.g.{" "}
|
||||||
issued for this session: <code>{ticket}</code>
|
<code>/Nitro-V3/dist</code>) in the admin settings. SSO ticket issued for this session:{" "}
|
||||||
|
<code>{ticket}</code>
|
||||||
</EmptyState>
|
</EmptyState>
|
||||||
</ContentCard>
|
</ContentCard>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
import { siteSettings } from "./site-settings";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds the Nitro client launch URL, faithful to AtomCMS's NitroController +
|
||||||
|
* nitro.blade.php:
|
||||||
|
*
|
||||||
|
* {nitro_path}/index.html?sso={ticket}&toolbar_primary=…&toolbar_hover=…
|
||||||
|
* &toolbar_border=…&toolbar_text=…
|
||||||
|
*
|
||||||
|
* The client files are served by the web root at `nitro_path` (e.g.
|
||||||
|
* `/Nitro-V3/dist`). Returns "" when no `nitro_path` is configured.
|
||||||
|
*/
|
||||||
|
export async function buildNitroClientUrl(ticket: string): Promise<string> {
|
||||||
|
const [nitroPathRaw, tPrimary, tHover, tBorder, tText, bPrimary, bHover, bBorder, bText] =
|
||||||
|
await Promise.all([
|
||||||
|
siteSettings.get("nitro_path", ""),
|
||||||
|
siteSettings.get("toolbar_primary_color", ""),
|
||||||
|
siteSettings.get("toolbar_hover_color", ""),
|
||||||
|
siteSettings.get("toolbar_border_color", ""),
|
||||||
|
siteSettings.get("toolbar_text_color", ""),
|
||||||
|
siteSettings.get("button_primary_color", ""),
|
||||||
|
siteSettings.get("button_hover_color", ""),
|
||||||
|
siteSettings.get("button_border_color", ""),
|
||||||
|
siteSettings.get("button_text_color", ""),
|
||||||
|
]);
|
||||||
|
|
||||||
|
const nitroPath = (nitroPathRaw ?? "").trim().replace(/\/+$/, "");
|
||||||
|
if (!nitroPath) return "";
|
||||||
|
|
||||||
|
// Same fallbacks as the blade: toolbar_* color, else button_* color, else the
|
||||||
|
// atom defaults. URLSearchParams encodes "#" → "%23" so the query is valid.
|
||||||
|
const params = new URLSearchParams({ sso: ticket });
|
||||||
|
params.set("toolbar_primary", tPrimary || bPrimary || "#eeb425");
|
||||||
|
params.set("toolbar_hover", tHover || bHover || "#cf9d15");
|
||||||
|
params.set("toolbar_border", tBorder || bBorder || "#cf9d15");
|
||||||
|
params.set("toolbar_text", tText || bText || "#1a1a2e");
|
||||||
|
|
||||||
|
return `${nitroPath}/index.html?${params.toString()}`;
|
||||||
|
}
|
||||||
@@ -6,7 +6,7 @@ const DEFAULTS: Record<string, string> = {
|
|||||||
hotel_name: "Atom",
|
hotel_name: "Atom",
|
||||||
habbo_imaging_url: "https://www.habbo.com/habbo-imaging/avatarimage",
|
habbo_imaging_url: "https://www.habbo.com/habbo-imaging/avatarimage",
|
||||||
logo_url: "",
|
logo_url: "",
|
||||||
nitro_client_url: "",
|
nitro_path: "",
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in new issue
Block a user