From 2fbb9532325fa932e891e62ac591d226199874a9 Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Sun, 29 Mar 2026 07:06:34 +0000 Subject: [PATCH] fix: use Date header from health/version instead of health.getTime() health.getTime() requires health.read scope which regular console users don't have. Instead, parse the Date header from the existing health/version fetch that already happens on console load. Co-Authored-By: Claude Opus 4.6 (1M context) --- src/lib/helpers/fingerprint.ts | 20 ++++++------------- src/routes/(console)/+layout.ts | 9 ++++++++- .../project-[region]-[project]/+layout.ts | 8 ++------ .../pausedProjectModal.svelte | 6 +----- 4 files changed, 17 insertions(+), 26 deletions(-) diff --git a/src/lib/helpers/fingerprint.ts b/src/lib/helpers/fingerprint.ts index 8ecbc8b60..25de4e452 100644 --- a/src/lib/helpers/fingerprint.ts +++ b/src/lib/helpers/fingerprint.ts @@ -7,23 +7,15 @@ const CACHE_TTL_MS = 60 * 60 * 1000; // 1 hour let serverTimeCache: { serverSecs: number; fetchedAtMs: number } | null = null; /** - * Fetch and cache the server's clock so fingerprint timestamps always align - * with the backend's clock, regardless of local clock drift. + * Cache the server's clock so fingerprint timestamps always align with the + * backend's clock, regardless of local clock drift. * - * @param getServerTime - callback that returns the server's unix timestamp in seconds - * (e.g. `health.getTime()` → `response.localTime`) + * @param serverTimeSecs - the server's unix timestamp in seconds + * (e.g. parsed from a response Date header) */ -export async function syncServerTime( - getServerTime: () => Promise -): Promise { +export function syncServerTime(serverTimeSecs: number): void { if (serverTimeCache) return; - try { - const fetchedAtMs = Date.now(); - const serverSecs = await getServerTime(); - serverTimeCache = { serverSecs, fetchedAtMs }; - } catch { - console.warn('Failed to sync server time for fingerprint'); - } + serverTimeCache = { serverSecs: serverTimeSecs, fetchedAtMs: Date.now() }; } function getServerTimestamp(): number { diff --git a/src/routes/(console)/+layout.ts b/src/routes/(console)/+layout.ts index 5edbc5545..1d766b48a 100644 --- a/src/routes/(console)/+layout.ts +++ b/src/routes/(console)/+layout.ts @@ -6,6 +6,7 @@ import { Platform, Query } from '@appwrite.io/console'; import { makePlansMap } from '$lib/helpers/billing'; import { plansInfo as plansInfoStore } from '$lib/stores/billing'; import { normalizeConsoleVariables } from '$lib/helpers/domains'; +import { syncServerTime } from '$lib/helpers/fingerprint'; export const load: LayoutLoad = async ({ depends, parent }) => { const { organizations, plansInfo } = await parent(); @@ -28,7 +29,13 @@ export const load: LayoutLoad = async ({ depends, parent }) => { plansArrayPromise, fetch(`${endpoint}/health/version`, { headers: { 'X-Appwrite-Project': project as string } - }).then((response) => response.json() as { version?: string }), + }).then((response) => { + const dateHeader = response.headers.get('Date'); + if (dateHeader) { + syncServerTime(Math.floor(new Date(dateHeader).getTime() / 1000)); + } + return response.json() as { version?: string }; + }), sdk.forConsole.console.variables() ]); diff --git a/src/routes/(console)/project-[region]-[project]/+layout.ts b/src/routes/(console)/project-[region]-[project]/+layout.ts index 760241a15..8da51bb51 100644 --- a/src/routes/(console)/project-[region]-[project]/+layout.ts +++ b/src/routes/(console)/project-[region]-[project]/+layout.ts @@ -11,7 +11,7 @@ import { loadAvailableRegions } from '$routes/(console)/regions'; import { type Models, Platform } from '@appwrite.io/console'; import { redirect } from '@sveltejs/kit'; import { resolve } from '$app/paths'; -import { generateFingerprintToken, syncServerTime } from '$lib/helpers/fingerprint'; +import { generateFingerprintToken } from '$lib/helpers/fingerprint'; import { normalizeConsoleVariables } from '$lib/helpers/domains'; import { browser } from '$app/environment'; @@ -107,11 +107,7 @@ export const load: LayoutLoad = async ({ params, depends, parent }) => { // Track console access for cloud projects (fire-and-forget, backend has 6-day cooldown). // Skip if paused — user must explicitly resume via the paused project modal. if (isCloud && browser && project.status !== 'paused') { - syncServerTime(async () => { - const { localTime } = await sdk.forConsole.health.getTime(); - return localTime; - }) - .then(() => generateFingerprintToken()) + generateFingerprintToken() .then((fingerprint) => { sdk.forConsole.client.headers['X-Appwrite-Console-Fingerprint'] = fingerprint; return sdk.forConsole.projects.updateConsoleAccess({ diff --git a/src/routes/(console)/project-[region]-[project]/pausedProjectModal.svelte b/src/routes/(console)/project-[region]-[project]/pausedProjectModal.svelte index 734416965..8c5fd1f17 100644 --- a/src/routes/(console)/project-[region]-[project]/pausedProjectModal.svelte +++ b/src/routes/(console)/project-[region]-[project]/pausedProjectModal.svelte @@ -6,7 +6,7 @@ import { Dependencies } from '$lib/constants'; import { addNotification } from '$lib/stores/notifications'; import { Submit, trackError } from '$lib/actions/analytics'; - import { generateFingerprintToken, syncServerTime } from '$lib/helpers/fingerprint'; + import { generateFingerprintToken } from '$lib/helpers/fingerprint'; import { Alert, Layout, Modal, Typography } from '@appwrite.io/pink-svelte'; import { Status } from '@appwrite.io/console'; @@ -28,10 +28,6 @@ error = null; try { - await syncServerTime(async () => { - const { localTime } = await sdk.forConsole.health.getTime(); - return localTime; - }); const fingerprint = await generateFingerprintToken(); sdk.forConsole.client.headers['X-Appwrite-Console-Fingerprint'] = fingerprint;