fix(web): hand the new heartbeat token over in sessionStorage, not the URL
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import { useParams, useRouter, useSearchParams } from "next/navigation";
|
||||
import { useParams, useRouter } from "next/navigation";
|
||||
import Link from "next/link";
|
||||
import { api, Incident, Rollup } from "@/lib/api";
|
||||
import { Button, ConfirmDialog, friendlyMessage, useToast } from "@/components/ui";
|
||||
@@ -322,7 +322,6 @@ function Row({ label, value }: { label: string; value: React.ReactNode }) {
|
||||
export default function MonitorDetailPage() {
|
||||
const params = useParams();
|
||||
const router = useRouter();
|
||||
const searchParams = useSearchParams();
|
||||
const queryClient = useQueryClient();
|
||||
const monitorId = params.id as string;
|
||||
const [confirmDelete, setConfirmDelete] = useState(false);
|
||||
@@ -330,19 +329,21 @@ export default function MonitorDetailPage() {
|
||||
const [range, setRange] = useState<Range>(RANGES[0]);
|
||||
const toast = useToast();
|
||||
|
||||
/* The token is only ever handed back once, on the create response, riding
|
||||
in the query string for this one navigation. Keep it in state and strip
|
||||
the query immediately so a reload, a bookmark or browser history never
|
||||
holds it. */
|
||||
/* The token is only ever handed back once, on the create response. The
|
||||
create page parks it in sessionStorage for this one navigation, because a
|
||||
query string would reach proxy access logs. Read it once and remove it
|
||||
straight away so a reload or another tab never shows it again. */
|
||||
const [heartbeatToken, setHeartbeatToken] = useState<string | null>(null);
|
||||
useEffect(() => {
|
||||
const t = searchParams.get("token");
|
||||
if (t) {
|
||||
setHeartbeatToken(t);
|
||||
router.replace(`/monitors/${monitorId}`);
|
||||
const key = `vantage:hbtoken:${monitorId}`;
|
||||
try {
|
||||
const t = sessionStorage.getItem(key);
|
||||
sessionStorage.removeItem(key);
|
||||
if (t) setHeartbeatToken(t);
|
||||
} catch {
|
||||
// Storage blocked: nothing was handed over.
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
}, [monitorId]);
|
||||
|
||||
const { data: monitor, isLoading } = useQuery({
|
||||
queryKey: ["monitors", monitorId],
|
||||
|
||||
@@ -24,11 +24,16 @@ export default function NewMonitorPage() {
|
||||
// survive the route change, which is the one thing an inline
|
||||
// banner on the form cannot do. The error stays on the form.
|
||||
toast.success(`Created ${m.name}. First check runs within its interval.`);
|
||||
// The token is shown once. Hand it over in memory, never in the
|
||||
// URL: the RSC fetch for a query string lands in proxy access logs.
|
||||
if (m.heartbeat_token) {
|
||||
router.push(`/monitors/${m.monitor_id}?token=${encodeURIComponent(m.heartbeat_token)}`);
|
||||
} else {
|
||||
router.push(`/monitors/${m.monitor_id}`);
|
||||
try {
|
||||
sessionStorage.setItem(`vantage:hbtoken:${m.monitor_id}`, m.heartbeat_token);
|
||||
} catch {
|
||||
// Storage blocked: the user can rotate to get a token.
|
||||
}
|
||||
}
|
||||
router.push(`/monitors/${m.monitor_id}`);
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ test("heartbeat monitor: URL ping, /fail, header ping", async ({ page, request }
|
||||
const incidents = await (await page.request.get(`${BASE_URL}/api/monitors/${monitor.monitor_id}/incidents`)).json();
|
||||
expect(incidents.length).toBeGreaterThan(0);
|
||||
|
||||
await new Promise((r) => setTimeout(r, 1100));
|
||||
await new Promise((r) => setTimeout(r, 1100)); // same kind (ping) as the first request; limit is 1/s per token and kind
|
||||
const headerPing = await request.post(`${BASE_URL}/public/hb`, { headers: { "X-Vantage-Token": monitor.heartbeat_token } });
|
||||
expect(headerPing.status()).toBe(200);
|
||||
got = await (await page.request.get(`${BASE_URL}/api/monitors/${monitor.monitor_id}`)).json();
|
||||
|
||||
Reference in New Issue
Block a user