/* eslint-disable @typescript-eslint/no-explicit-any */ import { v4 as uuidv4 } from "uuid"; import CryptoJS from "crypto-js"; import { ENV } from "../constants/env"; /* ========================= HELPERS (COPY POSTMAN) ========================= */ export function parseQueryParamsManual(url: string) { const result: Record = {}; const queryStartIndex = url.indexOf("?"); if (queryStartIndex === -1 || queryStartIndex === url.length - 1) { return result; } const queryString = url.substring(queryStartIndex + 1); const pairs = queryString.split("&"); for (const pair of pairs) { const parts = pair.split("="); if (parts.length === 2) { const key = decodeURIComponent(parts[0].replace(/\+/g, " ")); const value = decodeURIComponent(parts[1].replace(/\+/g, " ")); result[key] = value; } } return result; } export function sortKeysDeep(obj: any): any { if (Array.isArray(obj)) { return obj.map(sortKeysDeep); } if (obj !== null && typeof obj === "object") { return Object.keys(obj) .sort() .reduce((acc: any, key) => { acc[key] = sortKeysDeep(obj[key]); return acc; }, {}); } return obj; } /* ========================= SIGNATURE ========================= */ export interface SignatureResult { timestamp: number; nonce: string; signature: string; } export function generateSignature(rawBody: any): SignatureResult { const timestamp = Math.floor(Date.now() / 1000); const nonce = uuidv4(); const body = sortKeysDeep(rawBody ?? {}); const payload = JSON.stringify({ timestamp, nonce, body: JSON.stringify(body), // ⚠️ STRINGIFY GANDA (WAJIB) }); const hash = CryptoJS.HmacSHA256(payload, ENV.secretKey); return { timestamp, nonce, signature: CryptoJS.enc.Hex.stringify(hash), }; }