Skip to content

Commit c6452a8

Browse files
author
Lalit Sharma
committed
feat: add functions to simplify Google Maps URLs and handle consent page redirects
1 parent 246179b commit c6452a8

1 file changed

Lines changed: 85 additions & 9 deletions

File tree

apps/mobile/src/utils/sharedMapLink.ts

Lines changed: 85 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,35 @@ function isGoogleConsentHost(hostname: string): boolean {
6767
return normalizeHost(hostname) === "consent.google.com";
6868
}
6969

70+
function extractPlaceIdFromDataParam(dataParam: string): string | null {
71+
// Extract place ID from Google Maps data parameter
72+
// Format: data=!4m2!3m1!1s<PLACE_ID>!...
73+
const match = dataParam.match(/!1s([0-9a-fx:]+)/i);
74+
return match?.[1] ?? null;
75+
}
76+
77+
function simplifyGoogleMapsUrl(mapsUrl: string): string | null {
78+
try {
79+
const parsed = new URL(mapsUrl);
80+
if (!parsed.hostname.includes("google.com")) return null;
81+
82+
// Try to extract place ID from data parameter
83+
const dataParam = parsed.pathname.match(/\/data=([^/]+)/)?.[1];
84+
if (dataParam) {
85+
const placeId = extractPlaceIdFromDataParam(decodeURIComponent(dataParam));
86+
if (placeId) {
87+
// Construct minimal URL with just place ID
88+
return `https://www.google.com/maps/search/?api=1&query=${encodeURIComponent(placeId)}&query_place_id=${encodeURIComponent(placeId)}`;
89+
}
90+
}
91+
92+
// Fallback: strip query params and keep just the path
93+
return `https://www.google.com${parsed.pathname}`;
94+
} catch {
95+
return null;
96+
}
97+
}
98+
7099
function providerFromHost(hostname: string): ParsedSharedMapLink["provider"] | null {
71100
const host = normalizeHost(hostname);
72101
if (host === "maps.apple.com") return "apple";
@@ -324,15 +353,49 @@ async function fetchMapPageText(
324353

325354
// Check if we got redirected to a consent page
326355
const responseUrl = typeof response.url === "string" ? parseUrl(response.url) : null;
327-
if (responseUrl && isGoogleConsentHost(responseUrl.hostname) && maxConsentRedirects > 0) {
356+
if (responseUrl && isGoogleConsentHost(responseUrl.hostname)) {
328357
console.info("[share.debug] fetch_hit_consent_page", { url, responseUrl: response.url });
329-
// Extract the real Maps URL from the consent page
330-
const extractedUrl =
331-
typeof response.url === "string" ? extractUrlFromGoogleConsent(response.url) : null;
332-
if (extractedUrl) {
333-
console.info("[share.debug] fetch_extracted_from_consent", extractedUrl);
334-
// Recursively fetch the extracted URL, but limit redirects to prevent infinite loops
335-
return await fetchMapPageText(extractedUrl, options, maxConsentRedirects - 1);
358+
359+
if (maxConsentRedirects > 0) {
360+
// Extract the real Maps URL from the consent page
361+
const extractedUrl =
362+
typeof response.url === "string" ? extractUrlFromGoogleConsent(response.url) : null;
363+
if (extractedUrl) {
364+
console.info("[share.debug] fetch_extracted_from_consent", extractedUrl);
365+
// Recursively fetch the extracted URL, but limit redirects to prevent infinite loops
366+
return await fetchMapPageText(extractedUrl, options, maxConsentRedirects - 1);
367+
}
368+
} else {
369+
// Out of retries, try one last thing: simplify the URL
370+
console.info("[share.debug] fetch_consent_retries_exhausted_trying_simplified");
371+
const simplifiedUrl = simplifyGoogleMapsUrl(url);
372+
if (simplifiedUrl && simplifiedUrl !== url) {
373+
console.info("[share.debug] fetch_trying_simplified_url", simplifiedUrl);
374+
try {
375+
const simpleResponse = await withTimeout(
376+
fetchImpl(simplifiedUrl, {
377+
method: "GET",
378+
redirect: "follow",
379+
}),
380+
timeoutMs,
381+
);
382+
if (typeof simpleResponse.text === "function") {
383+
const simpleText = await withTimeout(
384+
Promise.resolve(simpleResponse.text()),
385+
timeoutMs,
386+
);
387+
console.info("[share.debug] fetch_simplified_result_length", simpleText?.length ?? 0);
388+
// Check if we still hit consent
389+
const simpleUrl =
390+
typeof simpleResponse.url === "string" ? parseUrl(simpleResponse.url) : null;
391+
if (simpleUrl && !isGoogleConsentHost(simpleUrl.hostname)) {
392+
return simpleText;
393+
}
394+
}
395+
} catch (err) {
396+
console.info("[share.debug] fetch_simplified_failed", err);
397+
}
398+
}
336399
}
337400
}
338401

@@ -379,7 +442,20 @@ function extractUrlFromGoogleConsent(consentUrl: string): string | null {
379442
const decodedUrl = decodeURIComponent(continueParam);
380443
const continueUrlParsed = new URL(decodedUrl);
381444
if (isSupportedMapHost(continueUrlParsed)) {
382-
return decodedUrl;
445+
// Strip tracking parameters that might trigger consent loops
446+
const paramsToRemove = [
447+
"utm_source",
448+
"utm_medium",
449+
"utm_campaign",
450+
"entry",
451+
"coh",
452+
"g_ep",
453+
"skid",
454+
];
455+
for (const param of paramsToRemove) {
456+
continueUrlParsed.searchParams.delete(param);
457+
}
458+
return continueUrlParsed.toString();
383459
}
384460
} catch {
385461
// If continue param isn't a valid URL, return null

0 commit comments

Comments
 (0)