{"version":3,"file":"static/js/630.89d9f30d.chunk.js","mappings":"mBACO,MAAMA,EAAU,IAAIC,YAOpB,SAASC,EAAOC,GACnB,MAAO,IAAI,IAAIC,WAAWD,IACrBE,KAAKC,GAAMA,EAAEC,SAAS,IAAIC,SAAS,EAAG,OACtCC,KAAK,GACd,CAQOC,eAAeC,EAAKC,EAAWC,GAClC,OAAOC,OAAOC,OAAOC,OAAOJ,EAAUK,cAA+B,kBAATJ,EAAoBb,EAAQkB,OAAOL,GAAQ,IAAIT,WAAWS,GAC1H,CAQOH,eAAeS,EAAQP,EAAWC,GACrC,OAAOX,QAAaS,EAAKC,EAAWC,GACxC,CCwHO,SAASO,EAAeC,EAAWC,GAAmD,IAA7CV,EAASW,UAAAC,OAAA,QAAAC,IAAAF,UAAA,GAAAA,UAAA,GAAG,UAAWG,EAAGH,UAAAC,OAAA,QAAAC,IAAAF,UAAA,GAAAA,UAAA,GAAG,IAAKI,EAAKJ,UAAAC,OAAA,QAAAC,IAAAF,UAAA,GAAAA,UAAA,GAAG,EACtF,MAAMK,EAAa,IAAIC,gBACjBC,EAAYC,KAAKC,MAgBvB,MAAO,CACHC,QAhBOvB,WACP,IAAK,IAAIwB,EAAIP,EAAOO,GAAKR,EAAKQ,GAAK,EAAG,CAClC,GAAIN,EAAWO,OAAOC,QAClB,OAAO,KAGX,SADgBjB,EAAQP,EAAWU,EAAOY,KAChCb,EACN,MAAO,CACHgB,OAAQH,EACRI,KAAMP,KAAKC,MAAQF,EAG/B,CACA,OAAO,IAAI,EAGFS,GACTX,aAER,CC3KA,IAAIA,EAEJY,UAAY9B,UAER,MAAM,KAAE+B,EAAI,QAAEC,GAAYC,EAAQ9B,KAEX,IAAD+B,EAAtB,GAAa,UAATH,EAEU,QAAVG,EAAAhB,SAAU,IAAAgB,GAAVA,EAAYC,QAEZjB,OAAaH,OAIZ,GAAa,SAATgB,EAAiB,CAEtB,MAAM,UAAE7B,EAAS,UAAES,EAAS,IAAEK,EAAG,KAAEJ,EAAI,MAAEK,GAAUe,GAAW,CAAC,EAEzDI,EAAS1B,EAAeC,EAAWC,EAAMV,EAAWc,EAAKC,GAE/DC,EAAakB,EAAOlB,WAEpBkB,EAAOb,QAAQc,MAAMC,IAGrBC,YAAYD,EAAW,IAAKA,EAAUE,QAAQ,GAASF,EAAS,GAIpE,E","sources":["../node_modules/altcha-lib/dist/helpers.js","../node_modules/altcha-lib/dist/index.js","shared/Altcha/ChallengeWorker.js"],"sourcesContent":["// Create a TextEncoder instance to convert strings to UTF-8 byte arrays.\nexport const encoder = new TextEncoder();\n/**\n * Converts an ArrayBuffer or Uint8Array to a hexadecimal string.\n *\n * @param ab - The ArrayBuffer or Uint8Array to convert.\n * @returns The hexadecimal string representation of the input.\n */\nexport function ab2hex(ab) {\n    return [...new Uint8Array(ab)]\n        .map((x) => x.toString(16).padStart(2, '0'))\n        .join('');\n}\n/**\n * Generates a cryptographic hash using the specified algorithm.\n *\n * @param algorithm - The cryptographic hash algorithm to use (e.g., 'SHA-256').\n * @param data - The data to hash, either as a string or ArrayBuffer.\n * @returns A Promise that resolves to the computed hash as an ArrayBuffer.\n */\nexport async function hash(algorithm, data) {\n    return crypto.subtle.digest(algorithm.toUpperCase(), typeof data === 'string' ? encoder.encode(data) : new Uint8Array(data));\n}\n/**\n * Generates a cryptographic hash using the specified algorithm and returns it as a hexadecimal string.\n *\n * @param algorithm - The cryptographic hash algorithm to use (e.g., 'SHA-256').\n * @param data - The data to hash, either as a string or ArrayBuffer.\n * @returns A Promise that resolves to the computed hash as a hexadecimal string.\n */\nexport async function hashHex(algorithm, data) {\n    return ab2hex(await hash(algorithm, data));\n}\n/**\n * Generates an HMAC using the specified algorithm and secret key.\n *\n * @param algorithm - The cryptographic hash algorithm to use for HMAC (e.g., 'SHA-256').\n * @param data - The data to sign, either as a string or ArrayBuffer.\n * @param secret - The secret key to use for HMAC.\n * @returns A Promise that resolves to the computed HMAC as an ArrayBuffer.\n */\nexport async function hmac(algorithm, data, secret) {\n    const key = await crypto.subtle.importKey('raw', encoder.encode(secret), {\n        name: 'HMAC',\n        hash: algorithm,\n    }, false, ['sign', 'verify']);\n    return crypto.subtle.sign('HMAC', key, typeof data === 'string' ? encoder.encode(data) : new Uint8Array(data));\n}\n/**\n * Generates an HMAC using the specified algorithm and secret key, and returns it as a hexadecimal string.\n *\n * @param algorithm - The cryptographic hash algorithm to use for HMAC (e.g., 'SHA-256').\n * @param data - The data to sign, either as a string or ArrayBuffer.\n * @param secret - The secret key to use for HMAC.\n * @returns A Promise that resolves to the computed HMAC as a hexadecimal string.\n */\nexport async function hmacHex(algorithm, data, secret) {\n    return ab2hex(await hmac(algorithm, data, secret));\n}\n/**\n * Generates a random sequence of bytes of the specified length.\n *\n * @param length - The number of random bytes to generate.\n * @returns A Uint8Array containing the random bytes.\n */\nexport function randomBytes(length) {\n    const ab = new Uint8Array(length);\n    crypto.getRandomValues(ab);\n    return ab;\n}\n/**\n * Generates a random integer between 1 and the specified maximum value (inclusive).\n *\n * @param max - The maximum value for the random integer.\n * @returns A random integer between 1 and the specified max value.\n */\nexport function randomInt(max) {\n    const ab = new Uint32Array(1);\n    crypto.getRandomValues(ab);\n    const randomNumber = ab[0] / (0xffffffff + 1);\n    return Math.floor(randomNumber * max + 1);\n}\n","import { ab2hex, hash, hashHex, hmacHex, randomBytes, randomInt, } from './helpers.js';\nconst DEFAULT_MAX_NUMBER = 1e6;\nconst DEFAULT_SALT_LEN = 12;\nconst DEFAULT_ALG = 'SHA-256';\n/**\n * Creates a challenge for the client to solve.\n *\n * @param {ChallengeOptions} options - Options for creating the challenge.\n * @returns {Promise<Challenge>} The created challenge.\n */\nexport async function createChallenge(options) {\n    const algorithm = options.algorithm || DEFAULT_ALG;\n    const maxnumber = options.maxnumber || options.maxNumber || DEFAULT_MAX_NUMBER;\n    const saltLength = options.saltLength || DEFAULT_SALT_LEN;\n    const params = new URLSearchParams(options.params);\n    if (options.expires) {\n        params.set('expires', String(Math.floor(options.expires.getTime() / 1000)));\n    }\n    let salt = options.salt || ab2hex(randomBytes(saltLength));\n    // params.size doesn't work with Node 16\n    if (Object.keys(Object.fromEntries(params)).length) {\n        salt = salt + '?' + params.toString();\n    }\n    const number = options.number === undefined ? randomInt(maxnumber) : options.number;\n    const challenge = await hashHex(algorithm, salt + number);\n    return {\n        algorithm,\n        challenge,\n        maxnumber,\n        salt,\n        signature: await hmacHex(algorithm, challenge, options.hmacKey),\n    };\n}\n/**\n * Extracts parameters from the payload.\n *\n * @param {string | Payload | Challenge} payload - The payload from which to extract parameters.\n * @returns {Record<string, string>} The extracted parameters.\n */\nexport function extractParams(payload) {\n    if (typeof payload === 'string') {\n        payload = JSON.parse(atob(payload));\n    }\n    return Object.fromEntries(new URLSearchParams(payload?.salt?.split('?')?.[1] || ''));\n}\n/**\n * Verifies the solution provided by the client.\n *\n * @param {string | Payload} payload - The payload to verify.\n * @param {string} hmacKey - The HMAC key used for verification.\n * @param {boolean} [checkExpires=true] - Whether to check if the challenge has expired.\n * @returns {Promise<boolean>} Whether the solution is valid.\n */\nexport async function verifySolution(payload, hmacKey, checkExpires = true) {\n    if (typeof payload === 'string') {\n        try {\n            payload = JSON.parse(atob(payload));\n        }\n        catch {\n            return false;\n        }\n    }\n    const params = extractParams(payload);\n    const expires = params.expires || params.expire;\n    if (checkExpires && expires) {\n        const date = new Date(parseInt(expires, 10) * 1000);\n        if (Number.isNaN(date.getTime()) || date.getTime() < Date.now()) {\n            return false;\n        }\n    }\n    const check = await createChallenge({\n        algorithm: payload.algorithm,\n        hmacKey,\n        number: payload.number,\n        salt: payload.salt,\n    });\n    return (check.challenge === payload.challenge &&\n        check.signature === payload.signature);\n}\n/**\n * Verifies the hash of form fields.\n *\n * @param {FormData | Record<string, unknown>} formData - The form data to verify.\n * @param {string[]} fields - The fields to include in the hash.\n * @param {string} fieldsHash - The expected hash of the fields.\n * @param {string} [algorithm=DEFAULT_ALG] - The hash algorithm to use.\n * @returns {Promise<boolean>} Whether the fields hash is valid.\n */\nexport async function verifyFieldsHash(formData, fields, fieldsHash, algorithm = DEFAULT_ALG) {\n    const data = formData instanceof FormData ? Object.fromEntries(formData) : formData;\n    const lines = [];\n    for (const field of fields) {\n        lines.push(String(data[field] || ''));\n    }\n    return (await hashHex(algorithm, lines.join('\\n'))) === fieldsHash;\n}\n/**\n * Verifies the server's signature.\n *\n * @param {string | ServerSignaturePayload} payload - The payload to verify.\n * @param {string} hmacKey - The HMAC key used for verification.\n * @returns {Promise<{verificationData: ServerSignatureVerificationData | null, verified: boolean}>} The verification result.\n */\nexport async function verifyServerSignature(payload, hmacKey) {\n    if (typeof payload === 'string') {\n        try {\n            payload = JSON.parse(atob(payload));\n        }\n        catch {\n            return {\n                verificationData: null,\n                verified: false,\n            };\n        }\n    }\n    const signature = await hmacHex(payload.algorithm, await hash(payload.algorithm, payload.verificationData), hmacKey);\n    let verificationData = null;\n    try {\n        const params = new URLSearchParams(payload.verificationData);\n        verificationData = {\n            ...Object.fromEntries(params),\n            expire: parseInt(params.get('expire') || '0', 10),\n            fields: params.get('fields')?.split(','),\n            reasons: params.get('reasons')?.split(','),\n            score: params.get('score')\n                ? parseFloat(params.get('score') || '0')\n                : undefined,\n            time: parseInt(params.get('time') || '0', 10),\n            verified: params.get('verified') === 'true',\n        };\n    }\n    catch {\n        // noop\n    }\n    return {\n        verificationData,\n        verified: payload.verified === true &&\n            verificationData?.verified === true &&\n            verificationData.expire > Math.floor(Date.now() / 1000) &&\n            payload.signature === signature,\n    };\n}\n/**\n * Solves a challenge by brute force.\n *\n * @param {string} challenge - The challenge to solve.\n * @param {string} salt - The salt used in the challenge.\n * @param {string} [algorithm='SHA-256'] - The hash algorithm used.\n * @param {number} [max=1e6] - The maximum number to try.\n * @param {number} [start=0] - The starting number.\n * @returns {{promise: Promise<Solution | null>, controller: AbortController}} The solution promise and abort controller.\n */\nexport function solveChallenge(challenge, salt, algorithm = 'SHA-256', max = 1e6, start = 0) {\n    const controller = new AbortController();\n    const startTime = Date.now();\n    const fn = async () => {\n        for (let n = start; n <= max; n += 1) {\n            if (controller.signal.aborted) {\n                return null;\n            }\n            const t = await hashHex(algorithm, salt + n);\n            if (t === challenge) {\n                return {\n                    number: n,\n                    took: Date.now() - startTime,\n                };\n            }\n        }\n        return null;\n    };\n    return {\n        promise: fn(),\n        controller,\n    };\n}\n/**\n * Solves a challenge using web workers for parallel computation.\n *\n * @param {string | URL | (() => Worker)} workerScript - The worker script or function to create a worker.\n * @param {number} concurrency - The number of workers to use.\n * @param {string} challenge - The challenge to solve.\n * @param {string} salt - The salt used in the challenge.\n * @param {string} [algorithm='SHA-256'] - The hash algorithm used.\n * @param {number} [max=1e6] - The maximum number to try.\n * @param {number} [startNumber=0] - The starting number.\n * @returns {Promise<Solution | null>} The solution, or null if not found.\n */\nexport async function solveChallengeWorkers(workerScript, concurrency, challenge, salt, algorithm = 'SHA-256', max = 1e6, startNumber = 0) {\n    const workers = [];\n    concurrency = Math.max(1, Math.min(16, concurrency));\n    for (let i = 0; i < concurrency; i++) {\n        if (typeof workerScript === 'function') {\n            workers.push(workerScript());\n        }\n        else {\n            workers.push(new Worker(workerScript, {\n                type: 'module',\n            }));\n        }\n    }\n    const step = Math.ceil(max / concurrency);\n    const solutions = await Promise.all(workers.map((worker, i) => {\n        const start = startNumber + i * step;\n        return new Promise((resolve) => {\n            worker.addEventListener('message', (message) => {\n                if (message.data) {\n                    for (const w of workers) {\n                        if (w !== worker) {\n                            w.postMessage({ type: 'abort' });\n                        }\n                    }\n                }\n                resolve(message.data);\n            });\n            worker.postMessage({\n                payload: {\n                    algorithm,\n                    challenge,\n                    max: start + step,\n                    salt,\n                    start,\n                },\n                type: 'work',\n            });\n        });\n    }));\n    for (const worker of workers) {\n        worker.terminate();\n    }\n    return solutions.find((solution) => !!solution) || null;\n}\nexport default {\n    createChallenge,\n    extractParams,\n    solveChallenge,\n    solveChallengeWorkers,\n    verifyFieldsHash,\n    verifyServerSignature,\n    verifySolution,\n};\n","import { solveChallenge } from \"altcha-lib\";\r\n\r\n\r\nlet controller = undefined;\r\n\r\nonmessage = async (message) => {\r\n\r\n    const { type, payload } = message.data;\r\n\r\n    if (type === 'abort') {\r\n\r\n        controller?.abort();\r\n\r\n        controller = undefined;\r\n\r\n    }\r\n\r\n    else if (type === 'work') {\r\n\r\n        const { algorithm, challenge, max, salt, start } = payload || {};\r\n\r\n        const result = solveChallenge(challenge, salt, algorithm, max, start);\r\n\r\n        controller = result.controller;\r\n\r\n        result.promise.then((solution) => {\r\n\r\n            \r\n        postMessage(solution ? { ...solution, worker: true } : solution);\r\n\r\n        });\r\n\r\n    }\r\n\r\n};\r\n "],"names":["encoder","TextEncoder","ab2hex","ab","Uint8Array","map","x","toString","padStart","join","async","hash","algorithm","data","crypto","subtle","digest","toUpperCase","encode","hashHex","solveChallenge","challenge","salt","arguments","length","undefined","max","start","controller","AbortController","startTime","Date","now","promise","n","signal","aborted","number","took","fn","onmessage","type","payload","message","_controller","abort","result","then","solution","postMessage","worker"],"sourceRoot":""}