fix: improve fingerprint generation and project status handling for cloud projects

This commit is contained in:
Damodar Lohani
2026-02-25 08:14:45 +00:00
parent 1f3a6be410
commit fadeb6fb2b
3 changed files with 29 additions and 31 deletions
+3 -1
View File
@@ -4,6 +4,7 @@ const SECRET = env.PUBLIC_CONSOLE_FINGERPRINT_KEY ?? '';
const CACHE_TTL_MS = 60 * 60 * 1000; // 1 hour
async function sha256(message: string): Promise<string> {
if (!crypto?.subtle) return '';
const data = new TextEncoder().encode(message);
const hash = await crypto.subtle.digest('SHA-256', data);
return Array.from(new Uint8Array(hash))
@@ -12,6 +13,7 @@ async function sha256(message: string): Promise<string> {
}
async function hmacSha256(message: string, secret: string): Promise<string> {
if (!crypto?.subtle) return '';
const key = await crypto.subtle.importKey(
'raw',
new TextEncoder().encode(secret),
@@ -204,7 +206,7 @@ export async function generateFingerprintToken(): Promise<string> {
};
const payload = JSON.stringify(signals);
const encoded = btoa(payload);
const encoded = btoa(unescape(encodeURIComponent(payload)));
if (!SECRET) {
return encoded;
@@ -13,6 +13,7 @@ import { redirect } from '@sveltejs/kit';
import { resolve } from '$app/paths';
import { generateFingerprintToken } from '$lib/helpers/fingerprint';
import { normalizeConsoleVariables } from '$lib/helpers/domains';
import { browser } from '$app/environment';
export const load: LayoutLoad = async ({ params, depends, parent }) => {
const { plansInfo, organizations, preferences: prefs } = await parent();
@@ -103,35 +104,24 @@ export const load: LayoutLoad = async ({ params, depends, parent }) => {
plansInfo.set(organization.billingPlanId, organizationPlan);
}
// Track console access for cloud only (fire-and-forget, backend has 6-day cooldown)
// Don't call if project is paused - user must explicitly resume via createConsoleAccess
if (isCloud) {
const projectInactivityDays = organizationPlan?.projectInactivityDays ?? 0;
const consoleAccessedAt = (project as { consoleAccessedAt?: string }).consoleAccessedAt;
let isPaused = false;
if (projectInactivityDays > 0 && consoleAccessedAt) {
const lastAccess = new Date(consoleAccessedAt);
const now = new Date();
const diffDays = Math.floor(
(now.getTime() - lastAccess.getTime()) / (1000 * 60 * 60 * 24)
);
isPaused = diffDays >= projectInactivityDays;
}
if (!isPaused) {
generateFingerprintToken()
.then((fingerprint) => {
sdk.forConsole.client.headers['X-Appwrite-Console-Fingerprint'] = fingerprint;
return sdk.forConsole.projects.updateConsoleAccess({
projectId: params.project
});
})
.catch(() => {})
.finally(() => {
delete sdk.forConsole.client.headers['X-Appwrite-Console-Fingerprint'];
// 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') {
generateFingerprintToken()
.then((fingerprint) => {
sdk.forConsole.client.headers['X-Appwrite-Console-Fingerprint'] = fingerprint;
return (
sdk.forConsole.projects as unknown as {
updateConsoleAccess(params: { projectId: string }): Promise<unknown>;
}
).updateConsoleAccess({
projectId: params.project
});
}
})
.catch(() => {})
.finally(() => {
delete sdk.forConsole.client.headers['X-Appwrite-Console-Fingerprint'];
});
}
return {
@@ -7,7 +7,6 @@
import { Submit, trackError } from '$lib/actions/analytics';
import { generateFingerprintToken } from '$lib/helpers/fingerprint';
import { Alert, Layout, Modal, Typography } from '@appwrite.io/pink-svelte';
import { Status } from '@appwrite.io/console';
let {
show = $bindable(false),
@@ -29,7 +28,14 @@
sdk.forConsole.client.headers['X-Appwrite-Console-Fingerprint'] = fingerprint;
try {
await sdk.forConsole.projects.updateStatus({ projectId, status: Status.Active });
await (
sdk.forConsole.projects as unknown as {
updateStatus(params: {
projectId: string;
status: string;
}): Promise<unknown>;
}
).updateStatus({ projectId, status: 'active' });
} finally {
delete sdk.forConsole.client.headers['X-Appwrite-Console-Fingerprint'];
}