import { Buffer } from 'node:buffer'; const randomInt = (min: number, max: number) => Math.floor(Math.random() * (max - min + 1)) + min; const randomFloat = (min: number, max: number, decimals = 15) => parseFloat((Math.random() * (max - min) + min).toFixed(decimals)); const randomChoice = (arr: T[]): T => arr[Math.floor(Math.random() * arr.length)]; const BASE_URL = 'https://eu-west-1.faceassure.com'; function generateId(id: string, sub: string, sessionId: string, delimiter = '|') { let s = 0; for (let a = '' + id + delimiter + sub + delimiter + sessionId, i = 0; i < a.length; i++) { s = (s << 5) - s + a.charCodeAt(i); s &= s; } return '' + s; } function generateUserAgent() { const agents = [ 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1', 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Mobile/15E148 Safari/604.1', 'Mozilla/5.0 (Android 13; Mobile; rv:109.0) Gecko/109.0 Firefox/117.0', 'Mozilla/5.0 (Linux; Android 13; SM-G991B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Mobile Safari/537.36' ]; return agents[Math.floor(Math.random() * agents.length)]; } function parseUserAgent(userAgent: string) { const isIOS = /iPhone|iPad/.test(userAgent); const isAndroid = /Android/.test(userAgent); const isSafari = /Safari/.test(userAgent) && !/Chrome/.test(userAgent); const isChrome = /Chrome/.test(userAgent); const isFirefox = /Firefox/.test(userAgent); return { browser: { name: isSafari ? 'Safari' : isChrome ? 'Chrome' : isFirefox ? 'Firefox' : 'Safari', version: isIOS ? '17.0' : '117.0' }, device: { type: 'mobile', vendor: isIOS ? 'Apple' : 'Samsung', model: isIOS ? 'iPhone' : 'Galaxy' }, os: { name: isIOS ? 'iOS' : isAndroid ? 'Android' : 'iOS', version: isIOS ? '17.0' : '13' }, engine: { name: isSafari || isIOS ? 'WebKit' : 'Blink' }, cpu: { architecture: '64' } }; } function getRandomLocation() { const locations = [ { country: 'United States', state: 'California', timezone: 'America/Los_Angeles', lang: 'en-US,en;q=0.9' }, { country: 'United States', state: 'New York', timezone: 'America/New_York', lang: 'en-US,en;q=0.9' }, { country: 'Canada', state: 'Ontario', timezone: 'America/Toronto', lang: 'en-CA,en;q=0.9,fr;q=0.8' }, { country: 'Australia', state: 'New South Wales', timezone: 'Australia/Sydney', lang: 'en-AU,en;q=0.9' }, { country: 'Germany', state: 'Berlin', timezone: 'Europe/Berlin', lang: 'de-DE,de;q=0.9,en;q=0.8' }, { country: 'France', state: 'Île-de-France', timezone: 'Europe/Paris', lang: 'fr-FR,fr;q=0.9,en;q=0.8' }, { country: 'Netherlands', state: 'North Holland', timezone: 'Europe/Amsterdam', lang: 'nl-NL,nl;q=0.9,en;q=0.8' }, { country: 'Sweden', state: 'Stockholm', timezone: 'Europe/Stockholm', lang: 'sv-SE,sv;q=0.9,en;q=0.8' }, { country: 'Norway', state: 'Oslo', timezone: 'Europe/Oslo', lang: 'nb-NO,nb;q=0.9,en;q=0.8' } ]; return locations[Math.floor(Math.random() * locations.length)]; } function generateMediaMetadata(sub: string, sessionId: string) { const randomHex = () => Array.from({ length: 32 }, () => Math.floor(Math.random() * 16) .toString(16) .toUpperCase() ).join(''); const specs = [ { width: 4032, height: 3024, frameRate: 60, zoom: 10, aspectRatio: 4032 / 3024 }, { width: 3840, height: 2160, frameRate: 60, zoom: 8, aspectRatio: 3840 / 2160 }, { width: 1920, height: 1080, frameRate: 120, zoom: 5, aspectRatio: 1920 / 1080 }, { width: 2560, height: 1440, frameRate: 60, zoom: 6, aspectRatio: 2560 / 1440 } ]; const spec = randomChoice(specs); const deviceId = generateId(randomHex(), sub, sessionId, '-'); return [ { mediaKind: 'audioinput', mediaLabel: randomChoice(['', 'Built-in Microphone', 'Default']), mediaId: randomHex(), mediaCapabilities: {} }, { mediaKind: 'videoinput', mediaLabel: 'Front Camera', mediaId: deviceId, mediaCapabilities: { aspectRatio: { max: spec.aspectRatio, min: randomFloat(0.0003, 0.001, 15) }, backgroundBlur: [false], deviceId: deviceId, facingMode: ['user'], focusDistance: { min: randomFloat(0.1, 0.3) }, frameRate: { max: spec.frameRate, min: 1 }, groupId: randomHex(), height: { max: spec.height, min: 1 }, powerEfficient: [false, true], whiteBalanceMode: randomChoice([ ['manual', 'continuous'], ['auto', 'manual'], ['continuous'] ]), width: { max: spec.width, min: 1 }, zoom: { max: spec.zoom, min: 1 } } } ]; } const AMAP_MAP: Record = { 0: [0, 2], 1: [2, 4], 2: [4, 8], 3: [8, 13], 4: [13, 18], 5: [18, 21], 6: [21, 25], 7: [25, 28], 8: [28, 32], 9: [32, 36], 10: [36, 40], 11: [40, 45], 12: [45, 50], 13: [50, 60], 14: [60, 70], 15: [70, 120] }; function amap(e: number) { const n = AMAP_MAP[~~e]; const r = e % 1; return n[0] + r * (n[1] - n[0]); } function removeOutliersWithZscore(arr: number[]) { const r = arr.reduce(function (e, t) { return e + t; }, 0) / arr.length; const a = arr.reduce(function (e, t) { return e + Math.pow(t - r, 2); }, 0) / arr.length; const s = Math.sqrt(a); return arr.filter(function (e) { return Math.abs((e - r) / s) <= 1; }); } function calculateSpeedAndIntervals(measurements: number[], timestamps: number[]) { const intervals = []; const speeds = []; for (let i = 1; i < measurements.length; i++) { const distance = Math.abs(measurements[i] - measurements[i - 1]); const timeInterval = (timestamps[i] - timestamps[i - 1]) / 1000; intervals.push(timeInterval); if (timeInterval > 0) { const speed = distance / timeInterval; speeds.push(speed); } else { speeds.push(0); } } return { intervals, speeds }; } async function encryptPayload(nonce: string, payload: any) { const getKey = async (nonce: string, timestamp: string, transactionId: string) => { const data = nonce + timestamp + transactionId; const dataEncoded = new TextEncoder().encode(data); const key = await crypto.subtle.importKey( 'raw', dataEncoded, { name: 'HKDF' }, false, ['deriveBits'] ); const derived = await crypto.subtle.deriveBits( { name: 'HKDF', hash: 'SHA-256', salt: new Uint8Array(0), info: new TextEncoder().encode('payload-encryption') }, key, 32 * 8 ); return await crypto.subtle.importKey( 'raw', derived, { name: 'AES-GCM' }, false, ['encrypt'] ); }; const timestamp = new Date().toISOString(); const key = await getKey(nonce, timestamp, payload.transaction_id); const iv = crypto.getRandomValues(new Uint8Array(12)); const encryptedBuffer = await crypto.subtle.encrypt( { name: 'AES-GCM', iv: iv }, key, new TextEncoder().encode(JSON.stringify(payload)) ); const rawBuffer = Buffer.from(encryptedBuffer); const encryptedPayloadBuf = rawBuffer.subarray(0, rawBuffer.length - 16); const authTagBuf = rawBuffer.subarray(rawBuffer.length - 16); return { encrypted_payload: encryptedPayloadBuf.toString('base64'), iv: Buffer.from(iv).toString('base64'), auth_tag: authTagBuf.toString('base64'), timestamp }; } const qrCodeUrl = Deno.args[0]; async function verify(qrCodeUrlStr: string) { const userAgent = generateUserAgent(); const parsedUserAgent = parseUserAgent(userAgent); const location = getRandomLocation(); const commonHeaders = { 'User-Agent': userAgent, accept: '*/*', 'accept-language': location.lang, 'access-control-allow-origin': '*', priority: 'u=1, i', 'sec-fetch-dest': 'empty', 'sec-fetch-mode': 'cors', 'sec-fetch-site': 'cross-site' }; const qrCodeUrl = new URL(qrCodeUrlStr); const shortlinkId = qrCodeUrl.searchParams.get('sl'); if (!shortlinkId) throw `shortlink id not found in qr code url`; const res = await fetch(`${BASE_URL}/shortlinks/${shortlinkId}`, { headers: commonHeaders }); if (!res.ok) `failed to get shortlink (status=${res.status}, body=${JSON.stringify(await res.text())})`; const data = await res.json(); const originalUrl = new URL(data.Item.original_url.S.replace('#', '')); const token = originalUrl.searchParams.get('token'); if (!token) throw `token not found in original url`; const parts = token.split('.'); if (parts.length !== 3) throw `token is an invalid jwt `; const jwtPayload = JSON.parse(atob(parts[1].replace(/-/g, '+').replace(/_/g, '/'))); const sessionRes = await fetch(`${BASE_URL}/age-services/d-privately-age-services`, { method: 'POST', headers: { 'Content-Type': 'application/json', ...commonHeaders }, body: JSON.stringify({ request_type: 'generate_new_session', transaction_id: jwtPayload.jti, api_key: null, api_secret: null, token, longURL: null, userAgent: userAgent }) }); if (!sessionRes.ok) throw `failed to generate new session (status=${sessionRes.status}, body=${JSON.stringify(await sessionRes.text())})`; const sessionData = await sessionRes.json(); const generateBoundingBox = () => { const topLeft = [randomFloat(140, 160), randomFloat(250, 270)]; const width = randomFloat(170, 190); const height = randomFloat(220, 240); return { topLeft, bottomRight: [topLeft[0] + width, topLeft[1] + height], width, height }; }; const generateTimeline = (maxTime: number) => { const entries = []; for (let i = 0; i < randomInt(2, 5); i++) { const start = randomInt(1, maxTime - 100); const end = start + randomInt(50, 500); if (end < maxTime) entries.push([start, end]); } return entries; }; const generateStateTimelines = (completionTime: number) => { const states = [ 'TIME_UNTIL_CLICK_START', 'GET_READY', 'NO_FACE', 'LOOK_STRAIGHT', 'TURN_LEFT', 'CENTRE_FACE', 'KEEP_YOUR_MOUTH_OPEN', 'CLOSE_YOUR_MOUTH', 'SLOWLY_COME_CLOSER_TO_THE_CAMERA', 'SLOWLY_DISTANCE_YOURSELF_FROM_THE_CAMERA', 'TOO_DARK' ]; const noState = [ 'VIDEO_PROCESSING', 'STAY_STILL', 'TURN_RIGHT', 'ALIGN_YOUR_FACE_WITH_THE_CAMERA_UP', 'ALIGN_YOUR_FACE_WITH_THE_CAMERA_DOWN', 'SLIGHTLY_TILT_YOUR_HEAD_LEFT', 'SLIGHTLY_TILT_YOUR_HEAD_RIGHT', 'OPEN_YOUR_MOUTH' ]; const timelines: Record = {}; states.forEach((state) => (timelines[state] = generateTimeline(completionTime))); noState.forEach((state) => { timelines[state] = []; }); return timelines; }; const baseAge = randomFloat(25.2, 26.0); const minAge = baseAge - randomFloat(0.1, 0.5); const maxAge = baseAge + randomFloat(0.1, 0.5); const averageAge = (minAge + maxAge) / 2; const currentTime = Date.now() / 1000; const completionTime = randomInt(8000, 15000); const raws = Array.from({ length: 10 }, () => randomFloat(6.005, 7.007)); const primaryOutputs = removeOutliersWithZscore(raws.map((r) => amap(r))); const outputs = removeOutliersWithZscore(primaryOutputs); const gestureMeasurementTime = Date.now(); const recordedMeasurements: number[] = Array.from({ length: 5 }, () => randomFloat(0.1, 0.8, 17)); const recordedTimestamps: number[] = [ randomInt(500, Math.min(completionTime, 1000)) - gestureMeasurementTime, randomInt(700, Math.min(completionTime, 1000)) - gestureMeasurementTime, randomInt(1000, Math.min(completionTime, 1400)) - gestureMeasurementTime, randomInt(1400, Math.min(completionTime, 1600)) - gestureMeasurementTime, randomInt(1600, Math.min(completionTime, 1800)) - gestureMeasurementTime ]; const { speeds: recordedSpeeds, intervals: recordedIntervals } = calculateSpeedAndIntervals( recordedMeasurements, recordedTimestamps ); const failedMeasurements: number[] = Array.from({ length: 5 }, () => randomFloat(0.1, 0.8, 17)); const failedTimestamps: number[] = [ randomInt(500, Math.min(completionTime, 1000)) - gestureMeasurementTime, randomInt(700, Math.min(completionTime, 1000)) - gestureMeasurementTime, randomInt(1000, Math.min(completionTime, 1400)) - gestureMeasurementTime, randomInt(1400, Math.min(completionTime, 1600)) - gestureMeasurementTime ]; const { speeds: failedOpennessSpeeds, intervals: failedOpennessIntervals } = calculateSpeedAndIntervals(failedMeasurements, failedTimestamps); const stateTimelines = generateStateTimelines(completionTime); const stateCompletionTimes: Record = {}; for (const [key, timeline] of Object.entries(stateTimelines)) { if (timeline.length < 1) continue; let completionTime = 0; for (const time of timeline) { completionTime += time.reduce((accumulator, currentValue) => accumulator + currentValue, 0); } stateCompletionTimes[key] = completionTime; } const mediaMetadata = generateMediaMetadata(jwtPayload.sub, sessionData.session_id); const ageCheckSession = generateId( mediaMetadata.find((m) => m.mediaKind === 'videoinput')!.mediaId, jwtPayload.sub, sessionData.session_id ); let payload = { request_type: 'complete_transaction', transaction_id: sessionData.transaction_id, api_key: sessionData.session_id, api_secret: sessionData.session_password, remote_pld: {}, browser_response_data: { age: 'yes', age_confidence: 1, genuineness: Array.from({ length: 5 }, () => randomFloat(0.4, 0.98)), product: 'age', modality: 'image', unverifiedPayload: { iss: 'https://api.privately.swiss', sub: jwtPayload.sub, aud: 'https://api.k-id.com', exp: jwtPayload.exp, nbf: jwtPayload.nbf, iat: jwtPayload.iat, jti: jwtPayload.jti, age: jwtPayload.age, liv: true, rlt: { minAge, maxAge, score: 0, gate: 16 }, rsn: 'complete_transaction', rtf: 'interval', rtb: 'callback', vid: jwtPayload.vid, ver: 'v1.10.22', ufi: [] }, ageCheckSession: ageCheckSession, miscellaneous: { recordedOpennessStreak: recordedMeasurements, recordedSpeeds, recordedIntervals, failedOpennessReadings: [failedMeasurements], failedOpennessSpeeds: [failedOpennessSpeeds], failedOpennessIntervals: [failedOpennessIntervals], numberOfGestureRetries: 1, antiSpoofConfidences: [], fp_scores: [], laplacian_blur_scores: Array.from({ length: 300 }, () => randomFloat(10, 300, 15)), laplacian_min_score: randomFloat(10, 50), laplacian_max_score: randomFloat(300, 350), laplacian_avg_score: randomFloat(50, 100), glare_ratios: Array.from({ length: 300 }, () => 0), allScreenDetectionDetails: { beforeClickingStart: { screenDetectionConfidence: [], screenFaceOverlap: [], screenBoundingBoxes: [], alternativeScore: [] }, positioning: { screenDetectionConfidence: Array.from({ length: 2 }, () => randomFloat(0.01, 0.03)), screenFaceOverlap: [0, 0], screenBoundingBoxes: [[], []], alternativeScore: Array.from({ length: 2 }, () => randomFloat(0.2, 0.9)) }, liveness: { screenDetectionConfidence: Array.from({ length: 2 }, () => randomFloat(0.01, 0.03)), screenFaceOverlap: [0, 0], screenBoundingBoxes: [[], []], alternativeScore: Array.from({ length: 2 }, () => randomFloat(0.2, 0.9)) }, distancing: { screenDetectionConfidence: Array.from({ length: 2 }, () => randomFloat(0.01, 0.03)), screenFaceOverlap: [0, 0], screenBoundingBoxes: [Array.from({ length: 2 }, generateBoundingBox)], alternativeScore: Array.from({ length: 2 }, () => randomFloat(0.2, 0.9)) }, closing: { screenDetectionConfidence: Array.from({ length: 2 }, () => randomFloat(0.01, 0.03)), screenFaceOverlap: [0, 0], screenBoundingBoxes: [Array.from({ length: 2 }, generateBoundingBox)], alternativeScore: Array.from({ length: 2 }, () => randomFloat(0.2, 0.9)) }, postChallenge: { screenDetectionConfidence: Array.from({ length: 2 }, () => randomFloat(0.01, 0.03)), screenFaceOverlap: [0, 0], screenBoundingBoxes: [[], []], alternativeScore: Array.from({ length: 2 }, () => randomFloat(0.2, 0.9)) } }, plScores: [], screenDetectionExecutionTimes: { beforeClickingStart: [], positioning: Array.from({ length: 2 }, () => randomFloat(5000, 6000)), liveness: Array.from({ length: 2 }, () => randomFloat(4000, 5000)), distancing: Array.from({ length: 2 }, () => randomFloat(3000, 4000)), closing: Array.from({ length: 2 }, () => randomFloat(2000, 3000)), postChallenge: Array.from({ length: 2 }, () => randomFloat(500, 1500)) }, landmarkDetectionExecutionTimes: { beforeClickingStart: [], positioning: Array.from({ length: 200 }, () => randomFloat(50, 150)), liveness: Array.from({ length: 50 }, () => randomFloat(50, 110)), distancing: Array.from({ length: 5 }, () => randomFloat(50, 110)), closing: Array.from({ length: 20 }, () => randomFloat(50, 110)), postChallenge: Array.from({ length: 7 }, () => randomFloat(50, 110)) }, screenAttackMeasure: 0, screenAttackBoundingBox: {}, subclient: jwtPayload.sub, verificationID: jwtPayload.vid, version: 'v1.10.22', sdk_path: './face-capture-v1.10.22.js', model_version: 'v.2025.0', cropper_version: 'v.0.0.3', start_time_stamp: currentTime + Number(Math.random().toFixed(3)), end_time_stamp: currentTime + completionTime + Number(Math.random().toFixed(3)), device_timezone: location.timezone, referring_page: `https://d3ogqhtsivkon3.cloudfront.net/?token=${token}&shi=false&from_qr_scan=true`, parent_page: `https://d3ogqhtsivkon3.cloudfront.net/dynamic_index.html?sl=${jwtPayload.jti}®ion=eu-central-1`, face_confidence_limit: 0.975, multipleFacesDetected: false, targetGate: 18, targetConfidence: 0.9, averageAge, selecedLivenessStyle: 'open', selectedMediaLabel: 'Front Camera', rawImageWidth: 480, rawImageHeight: 640, boundingBoxesInPixels: Array.from({ length: randomInt(5, 10) }, generateBoundingBox), latestReportedState: 'AGE_CHECK_COMPLETE', challengeType: 'distance-open', authenticationCharacteristics: { session_id: sessionData.session_id, session_password: sessionData.session_password, token }, deviceCharacteristics: { deviceBrowserModel: userAgent, isMobile: parsedUserAgent.device.type === 'mobile', browserName: parsedUserAgent.browser.name?.toLowerCase() || 'safari', isDeviceBrowserCompatible: true, deviceConnectionSpeedKbps: randomFloat(20000, 500000), deviceRegion: { country: location.country, state: location.state }, mediaMetadata: mediaMetadata, platformDetails: { name: parsedUserAgent.browser.name || 'Safari', version: parsedUserAgent.browser.version || '15.0', layout: parsedUserAgent.engine.name || 'WebKit', os: { architecture: parseInt(parsedUserAgent.cpu.architecture) || 64, family: parsedUserAgent.os.name || 'iOS', version: parsedUserAgent.os.version || '15.0' }, description: `${parsedUserAgent.browser.name || 'Safari'} ${ parsedUserAgent.browser.version || '15.0' } on ${parsedUserAgent.device.vendor || 'Apple'} ${parsedUserAgent.device.model || 'iPhone'} (${parsedUserAgent.os.name || 'iOS'} ${ parsedUserAgent.os.version || '15.0' })`, product: parsedUserAgent.device.model || 'iPhone', manufacturer: parsedUserAgent.device.vendor || 'Apple' }, userTriedLandscapeMode: 0, txFinishedInLandscapeMode: false }, initializationCharacteristics: { cropperInitTime: randomInt(150, 250), coreInitTime: randomInt(800, 1000), pageLoadTime: randomInt(250, 350) + Number(Math.random().toFixed(randomInt(7, 13))), from_qr_scan: false, blendShapesAvailable: true }, executionCharacteristics: { experimentSetup: { experimentType: 'passive-liveness-override', experimentProbability: 1, deviceCoverage: 'all', deviceInfo: { name: parsedUserAgent.browser.name || 'Safari', version: parsedUserAgent.browser.version || '15.0', layout: parsedUserAgent.engine.name || 'WebKit', os: { architecture: parseInt(parsedUserAgent.cpu.architecture) || 64, family: parsedUserAgent.os.name || 'iOS', version: parsedUserAgent.os.version || '15.0' }, description: `${parsedUserAgent.browser.name || 'Safari'} ${ parsedUserAgent.browser.version || '15.0' } on ${parsedUserAgent.device.vendor || 'Apple'} ${parsedUserAgent.device.model || 'iPhone'} (${parsedUserAgent.os.name || 'iOS'} ${ parsedUserAgent.os.version || '15.0' })`, product: parsedUserAgent.device.model || 'iPhone', manufacturer: parsedUserAgent.device.vendor || 'Apple' }, txMode: 'experiment', timestamp: new Date().getTime() }, experimentConfigResult: { success: true, txMode: 'experiment', experimentType: 'passive-liveness-override' }, isCameraPermissionGranted: true, completionTime, deferredComputationStartedAt: randomInt(10000, 14000) + Number(Math.random().toFixed(randomInt(1, 3))), instructionCompletionTime: randomInt(10000, 14000), initialAdjustmentTime: randomInt(10000, 14000), completionState: 'COMPLETE', unfinishedInstructions: Object.fromEntries( [ 'NO_FACE', 'VIDEO_PROCESSING', 'STAY_STILL', 'LOOK_STRAIGHT', 'GET_READY', 'TURN_LEFT', 'TURN_RIGHT', 'ALIGN_YOUR_FACE_WITH_THE_CAMERA_UP', 'ALIGN_YOUR_FACE_WITH_THE_CAMERA_DOWN', 'SLIGHTLY_TILT_YOUR_HEAD_LEFT', 'SLIGHTLY_TILT_YOUR_HEAD_RIGHT', 'CENTRE_FACE', 'OPEN_YOUR_MOUTH', 'KEEP_YOUR_MOUTH_OPEN', 'CLOSE_YOUR_MOUTH', 'SLOWLY_COME_CLOSER_TO_THE_CAMERA', 'SLOWLY_DISTANCE_YOURSELF_FROM_THE_CAMERA', 'TOO_DARK' ].map((k) => [k, false]) ), stateCompletionTimes, stateTimelines, nonNeutralExpressionTimelines: Object.fromEntries( [ 'browDownLeft', 'browDownRight', 'mouthSmileLeft', 'mouthSmileRight', 'mouthPucker', 'mouthDimpleLeft', 'mouthDimpleRight', 'mouthPressLeft', 'mouthPressRight', 'mouthShrugLower', 'mouthShrugUpper', 'eyeBlinkLeft', 'eyeBlinkRight', 'mouthFrownLeft', 'mouthFrownRight' ].map((k) => [k, {}]) ), handAnalysis: { faceHandSizeComparisons: [] }, predictions: { outputs, primaryOutputs, raws, secondaryOutputs: [], secondaryRaws: [], age: 'yes', horizontal_estimates: Array.from({ length: 6 }, () => randomFloat(3.1, 3.2)), vertical_estimates: Array.from({ length: 6 }, () => randomFloat(-1.6, -1.5)), horizontalratiotocenter_estimates: Array.from({ length: 6 }, () => randomFloat(1.01, 1.03) ), zy_estimates: Array.from({ length: 6 }, () => randomFloat(0.42, 0.44)), driftfromcenterx_estimates: Array.from({ length: 6 }, () => randomFloat(0.005, 0.007)), driftfromcentery_estimates: Array.from({ length: 6 }, () => randomFloat(-0.35, -0.37)), xScaledShiftAmt: 11.5, yScaledShiftAmt: -2 } }, errorCharacteristics: { systemErrors: [], userErrors: {} } } } }; const encryptionData = await encryptPayload(sessionData.nonce, payload); payload = Object.assign(payload, encryptionData); const completeRes = await fetch(`${BASE_URL}/age-services/d-privately-age-services`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'User-Agent': userAgent, accept: '*/*', 'accept-language': location.lang, 'access-control-allow-origin': '*', priority: 'u=1, i', 'sec-fetch-dest': 'empty', 'sec-fetch-mode': 'cors', 'sec-fetch-site': 'cross-site' }, body: JSON.stringify(payload) }); if (!completeRes.ok) throw `failed to complete transaction (status=${completeRes.status}, body=${JSON.stringify(await completeRes.text())})`; console.log('tx completed', payload.transaction_id); } await verify(qrCodeUrl);