mirror of
https://github.com/Hackdex-App/hackdex-website.git
synced 2026-08-22 08:34:13 -05:00
Add a local-dev fallback for download device IDs
crypto.randomUUID is unavailable on HTTP, which breaks download counting during local development. Production still uses the native UUID. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -13,6 +13,7 @@ import {
|
||||
isArchiveFile,
|
||||
isAnyRomExtension,
|
||||
} from "@/utils/romFile";
|
||||
import { getOrCreateDeviceId } from "@/utils/deviceId";
|
||||
import { collectFetchDiagnostics, HTTPError, runConnectivityProbes } from "@/utils/patches/download-telemetry";
|
||||
import type { SelectablePatch } from "@/types/patcher";
|
||||
import { applyPatch, patchFormatFromFilename, type PatchFormat } from "@/utils/patching";
|
||||
@@ -436,12 +437,8 @@ const HackActions: React.FC<HackActionsProps> = ({
|
||||
try {
|
||||
const countPatchId = selectedPatch?.id ?? patchId;
|
||||
if (countPatchId != null) {
|
||||
const key = "deviceId";
|
||||
let deviceId = localStorage.getItem(key);
|
||||
if (!deviceId) {
|
||||
deviceId = crypto.randomUUID();
|
||||
localStorage.setItem(key, deviceId);
|
||||
}
|
||||
const deviceId = getOrCreateDeviceId();
|
||||
if (!deviceId) return;
|
||||
// Defer count update to avoid Safari cancelling the request
|
||||
setTimeout(async () => {
|
||||
const deviceIdObscured = deviceId.split("-");
|
||||
|
||||
@@ -7,6 +7,7 @@ import { FiEdit2, FiEdit, FiX } from "react-icons/fi";
|
||||
import VersionActions from "@/components/Hack/VersionActions";
|
||||
import type { PatchesDownloadPermission } from "@/components/Hack/DownloadPermissionSettings";
|
||||
import { updatePatchChangelog, updatePatchVersion, getPatchDownloadUrl, updatePatchDownloadCount } from "@/app/hack/[slug]/actions";
|
||||
import { getOrCreateDeviceId } from "@/utils/deviceId";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { createClient } from "@/utils/supabase/client";
|
||||
import type { Patch } from "@/components/Hack/PatcherVersionManager";
|
||||
@@ -38,12 +39,8 @@ function PublicPatchDownloadButton({ patchId }: { patchId: number }) {
|
||||
window.open(result.url, "_blank");
|
||||
// Best-effort log download for counting
|
||||
try {
|
||||
const key = "deviceId";
|
||||
let deviceId = localStorage.getItem(key);
|
||||
if (!deviceId) {
|
||||
deviceId = crypto.randomUUID();
|
||||
localStorage.setItem(key, deviceId);
|
||||
}
|
||||
const deviceId = getOrCreateDeviceId();
|
||||
if (!deviceId) return;
|
||||
setTimeout(async () => {
|
||||
const deviceIdObscured = deviceId.split("-");
|
||||
const countResult = await updatePatchDownloadCount(patchId, deviceIdObscured);
|
||||
|
||||
35
src/utils/deviceId.ts
Normal file
35
src/utils/deviceId.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
const DEVICE_ID_STORAGE_KEY = "deviceId";
|
||||
|
||||
function createDeviceId(): string | null {
|
||||
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
||||
return crypto.randomUUID();
|
||||
}
|
||||
// Insecure-context local dev only. Must stay five hyphen-separated segments.
|
||||
if (process.env.NODE_ENV === "development") {
|
||||
return `dev-${Date.now()}-0-0-0`;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function isDevFallbackId(id: string): boolean {
|
||||
return id.startsWith("dev-");
|
||||
}
|
||||
|
||||
export function getOrCreateDeviceId(): string | null {
|
||||
const existing = localStorage.getItem(DEVICE_ID_STORAGE_KEY);
|
||||
const isStaleDevFallback =
|
||||
!!existing && isDevFallbackId(existing) && process.env.NODE_ENV !== "development";
|
||||
|
||||
if (existing && !isStaleDevFallback) return existing;
|
||||
|
||||
const created = createDeviceId();
|
||||
if (created) {
|
||||
localStorage.setItem(DEVICE_ID_STORAGE_KEY, created);
|
||||
return created;
|
||||
}
|
||||
|
||||
if (isStaleDevFallback) {
|
||||
localStorage.removeItem(DEVICE_ID_STORAGE_KEY);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
Reference in New Issue
Block a user