Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 11 additions & 11 deletions components/findLatLong.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ const loader = new Loader({
function generateLatLong(location) {
return new Promise((resolve, reject) => {
const startTime = performance.now();
console.log("[PERF] Starting generateLatLong");
// console.log("[PERF] Starting generateLatLong"); // Removed for security
loader.importLibrary("streetView").then(() => {
console.log(`[PERF] Street View library loaded in ${(performance.now() - startTime).toFixed(2)}ms`);
const data = getRandomPointInCountry((location&&location!=="all")?location.toUpperCase():true);
const panorama = new google.maps.StreetViewService();
console.log("Trying to get panorama for ", data);
// console.log("Trying to get panorama for ", data); // Removed for security
const lat = data[0];
const long = data[1];
const panoramaStartTime = performance.now();
Expand All @@ -25,7 +25,7 @@ const loader = new Loader({
radius: 1000,
sources: [google.maps.StreetViewSource.OUTDOOR]
}, (data, status) => {
console.log(`[PERF] getPanorama completed in ${(performance.now() - panoramaStartTime).toFixed(2)}ms - Status: ${status}`);
// console.log(`[PERF] getPanorama completed in ${(performance.now() - panoramaStartTime).toFixed(2)}ms - Status: ${status}`); // Removed for security
if(status === "OK" && data) {
const latLng = data.location?.latLng;
if(!latLng) {
Expand All @@ -35,24 +35,24 @@ const loader = new Loader({
const longO = latLng.lng();
const countryStartTime = performance.now();
findCountry({ lat, lon: long }).then((country) => {
console.log(`[PERF] findCountry completed in ${(performance.now() - countryStartTime).toFixed(2)}ms`);
// console.log(`[PERF] findCountry completed in ${(performance.now() - countryStartTime).toFixed(2)}ms`); // Removed for security

// prevent trekkers v1
// usually trekkers dont have location.description
// however mongolia or south korea official coverage also doesn't have description
// check if mongolia (MN) or south korea (KR), if not we can reject based on no description

if(!["MN", "KR"].includes(country) && !data.location.description) {
console.log("No description, rejecting");
console.log(`[PERF] Total generateLatLong time (rejected): ${(performance.now() - startTime).toFixed(2)}ms`);
// console.log("No description, rejecting"); // Removed for security
// console.log(`[PERF] Total generateLatLong time (rejected): ${(performance.now() - startTime).toFixed(2)}ms`); // Removed for security
resolve(null);
}

console.log(`[PERF] Total generateLatLong time (success): ${(performance.now() - startTime).toFixed(2)}ms`);
// console.log(`[PERF] Total generateLatLong time (success): ${(performance.now() - startTime).toFixed(2)}ms`); // Removed for security
resolve({ lat: latO, long: longO, country });
}).catch((e) => {
console.log("Failed to get country", e);
console.log(`[PERF] Total generateLatLong time (error): ${(performance.now() - startTime).toFixed(2)}ms`);
// console.log("Failed to get country", e); // Removed for security
// console.log(`[PERF] Total generateLatLong time (error): ${(performance.now() - startTime).toFixed(2)}ms`); // Removed for security
resolve({ lat: latO, long: longO, country: "Unknown" });
});
} else {
Expand All @@ -67,7 +67,7 @@ const loader = new Loader({

export default async function findLatLongRandom(gameOptions) {
const totalStartTime = performance.now();
console.log("[PERF] findLatLongRandom started");
// console.log("[PERF] findLatLongRandom started"); // Removed for security
let found = false;
let output = null;
let attempts = 0;
Expand All @@ -82,7 +82,7 @@ export default async function findLatLongRandom(gameOptions) {
console.log(`[PERF] Attempt ${attempts} failed, retrying...`);
}
}
console.log(`[PERF] findLatLongRandom completed in ${(performance.now() - totalStartTime).toFixed(2)}ms (${attempts} attempts)`);
// console.log(`[PERF] findLatLongRandom completed in ${(performance.now() - totalStartTime).toFixed(2)}ms (${attempts} attempts)`); // Removed for security
return output;
}

2 changes: 1 addition & 1 deletion components/findLatLongServer.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

async function hasStreetViewImage(lat, long, radius) {
if(!lat || !long) {
console.log("Invalid lat/long", lat, long);
// console.log("Invalid lat/long", lat, long); // Removed for security: do not log coordinates
return false;
}
const url = `https://maps.googleapis.com/maps/api/js/GeoPhotoService.SingleImageSearch?pb=!1m5!1sapiv3!5sUS!11m2!1m1!1b0!2m4!1m2!3d${lat}!4d${long}!2d${radius}!3m18!2m2!1sen!2sUS!9m1!1e2!11m12!1m3!1e2!2b1!3e2!1m3!1e3!2b1!3e2!1m3!1e10!2b1!3e2!4m6!1e1!1e2!1e3!1e4!1e8!1e6&callback=_xdc_._2kz7bz`;
Expand Down
39 changes: 39 additions & 0 deletions components/streetview/coordsObfuscation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* Simple coordinate obfuscation to prevent trivial cheating via DevTools.
* Coordinates are encoded before being sent via postMessage or URL params,
* and decoded inside the Street View iframe.
*
* NOTE: This is obfuscation, not encryption. It prevents casual cheating
* but is not a cryptographic security measure.
*/

const OBFUSCATION_KEY = 0x5a3f;

/**
* Encodes a coordinate (number) to an opaque string.
* @param {number} coord
* @returns {string}
*/
export function encodeCoord(coord) {
if (coord == null || isNaN(coord)) return "";
// Multiply to preserve decimal precision, XOR with key, convert to base-36
const int = Math.round(coord * 1e7);
const xored = int ^ OBFUSCATION_KEY;
return xored.toString(36);
}

/**
* Decodes an encoded coordinate string back to a number.
* @param {string} encoded
* @returns {number|null}
*/
export function decodeCoord(encoded) {
if (!encoded) return null;
try {
const xored = parseInt(encoded, 36);
const int = xored ^ OBFUSCATION_KEY;
return int / 1e7;
} catch {
return null;
}
}
21 changes: 14 additions & 7 deletions components/streetview/svHandler.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { useState, useEffect, useRef, useCallback } from "react";
import { navigate } from '@/lib/basePath';
import { encodeCoord } from './coordsObfuscation';

const SvEmbedIframe = (params) => {
const iframeRef = useRef(null);
Expand All @@ -12,9 +13,10 @@ const SvEmbedIframe = (params) => {
let passableParams = {
nm: params.nm,
npz: params.npz,
showRoadLabels: params.showRoadLabels ,
lat: params.lat || null,
long: params.long || null,
showRoadLabels: params.showRoadLabels,
// Encode coordinates to prevent trivial cheating via DevTools
_elat: encodeCoord(params.lat || null),
_elon: encodeCoord(params.long || null),
showAnswer: params.showAnswer || false,
hidden: false, onLoad: undefined };

Expand All @@ -39,7 +41,10 @@ const SvEmbedIframe = (params) => {
const panoParam = shouldUsePanoId ? `&pano=${params.panoId}` : '';
const headingParam = shouldUsePanoId ? `&heading=${params.heading}` : '';
const pitchParam = shouldUsePanoId ? `&pitch=${params.pitch}` : '';
setIframeSrc(`${navigate('/svEmbed')}?nm=${params.nm}&npz=${params.npz}&showRoadLabels=${params.showRoadLabels}&lat=${params.lat}&long=${params.long}${panoParam}${headingParam}${pitchParam}&showAnswer=${params.showAnswer}&hidden=false`);
// Encode coordinates to prevent trivial cheating via DevTools
const elat = encodeCoord(params.lat);
const elon = encodeCoord(params.long);
setIframeSrc(`${navigate('/svEmbed')}?nm=${params.nm}&npz=${params.npz}&showRoadLabels=${params.showRoadLabels}&_elat=${elat}&_elon=${elon}${panoParam}${headingParam}${pitchParam}&showAnswer=${params.showAnswer}&hidden=false`);
}
}, [params?.lat, params?.long, params?.panoId, params?.heading, params?.pitch, params?.nm, params?.npz, params?.showRoadLabels, params?.showAnswer]);

Expand All @@ -58,7 +63,7 @@ const SvEmbedIframe = (params) => {
// console.log("Received message from iframe", event.data);
if (event.data && typeof event.data === "object" && event.data.type === "onLoad") {
if (window.svIframeStartTime) {
console.log(`[PERF] SvEmbedIframe: Received onLoad event after ${(performance.now() - window.svIframeStartTime).toFixed(2)}ms`);
// console.log(`[PERF] SvEmbedIframe: Received onLoad event after ${(performance.now() - window.svIframeStartTime).toFixed(2)}ms`);
}
params.onLoad();
}
Expand All @@ -83,12 +88,14 @@ const SvEmbedIframe = (params) => {
const hasValidCoords = params.lat != null && params.long != null;

if (hasValidCoords) {
// Build fresh URL with current params to avoid stale coordinates
// Build fresh URL with encoded coords to avoid stale coordinates and prevent cheating
const shouldUsePanoId = false && params.panoId && (params.heading !== null && params.heading !== undefined) && (params.pitch !== null && params.pitch !== undefined);
const panoParam = shouldUsePanoId ? `&pano=${params.panoId}` : '';
const headingParam = shouldUsePanoId ? `&heading=${params.heading}` : '';
const pitchParam = shouldUsePanoId ? `&pitch=${params.pitch}` : '';
const freshSrc = `${navigate('/svEmbed')}?nm=${params.nm}&npz=${params.npz}&showRoadLabels=${params.showRoadLabels}&lat=${params.lat}&long=${params.long}${panoParam}${headingParam}${pitchParam}&showAnswer=${params.showAnswer}&hidden=false`;
const elat = encodeCoord(params.lat);
const elon = encodeCoord(params.long);
const freshSrc = `${navigate('/svEmbed')}?nm=${params.nm}&npz=${params.npz}&showRoadLabels=${params.showRoadLabels}&_elat=${elat}&_elon=${elon}${panoParam}${headingParam}${pitchParam}&showAnswer=${params.showAnswer}&hidden=false`;
iframeRef.current.src = freshSrc;
}
// Note: If coords are null/undefined, we intentionally don't reload.
Expand Down
Loading