aboutsummaryrefslogtreecommitdiffstats
path: root/src/helpers/fetchSolution.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/helpers/fetchSolution.ts')
-rw-r--r--src/helpers/fetchSolution.ts52
1 files changed, 52 insertions, 0 deletions
diff --git a/src/helpers/fetchSolution.ts b/src/helpers/fetchSolution.ts
new file mode 100644
index 0000000..b43722a
--- /dev/null
+++ b/src/helpers/fetchSolution.ts
@@ -0,0 +1,52 @@
+import { Song } from "../types/song";
+
+const SALT = process.env.HEARDLE_SALT ?? 'changeme';
+const API_URL = process.env.HEARDLE_API_URL ?? 'http://localhost:3001';
+
+function hexToBytes(hex: string): Uint8Array {
+ const bytes = new Uint8Array(hex.length / 2);
+ for (let i = 0; i < hex.length; i += 2) {
+ bytes[i / 2] = parseInt(hex.slice(i, i + 2), 16);
+ }
+ return bytes;
+}
+
+
+async function getDailyKey(): Promise<CryptoKey> {
+ const enc = new TextEncoder();
+ const date = new Date().toISOString().split('T')[0];
+ const keyMaterial = await crypto.subtle.importKey(
+ 'raw',
+ enc.encode(date),
+ 'PBKDF2',
+ false,
+ ['deriveKey'],
+ );
+ return crypto.subtle.deriveKey(
+ { name: 'PBKDF2', salt: enc.encode(SALT), iterations: 100_000, hash: 'SHA-256' },
+ keyMaterial,
+ { name: 'AES-GCM', length: 256 },
+ false,
+ ['decrypt'],
+ );
+}
+
+export async function getDailySolution(): Promise<Song> {
+ const solutionData = await fetch(`${API_URL}/today`);
+ if (!solutionData.ok) {
+ throw new Error(`Failed to fetch solution: ${solutionData.statusText}`);
+ }
+ const { iv, tag, data } = await solutionData.json();
+ const key = await getDailyKey();
+ const ciphertext = hexToBytes(data);
+ const authTag = hexToBytes(tag);
+ const combined = new Uint8Array(ciphertext.length + authTag.length);
+ combined.set(ciphertext);
+ combined.set(authTag, ciphertext.length);
+ const decrypted = await crypto.subtle.decrypt(
+ { name: 'AES-GCM', iv: hexToBytes(iv) },
+ key,
+ combined,
+ );
+ return JSON.parse(new TextDecoder().decode(decrypted)) as Song;
+}
send patches to the email below
yukais@pinapelz.com
include the subject [PATCH repo_name]
pinapelz.com
homepage