Fish-Pish / src /utils /urlResolver.ts
Rachit-Tw's picture
Upload 23 files
aa92a04 verified
Raw
History Blame Contribute Delete
1.97 kB
import axios from 'axios';
/**
* Unwraps known link shims (Gmail, Outlook, etc.) and follows redirects
* to find the final destination URL.
*/
export async function resolveUrl(url: string): Promise<string> {
let currentUrl = url;
try {
const parsedUrl = new URL(url);
// 1. Unwrap known shims
// Google/Gmail Shim
if (/google\.[a-z.]*$/.test(parsedUrl.hostname) &&
parsedUrl.pathname === '/url' &&
parsedUrl.searchParams.has('q')) {
currentUrl = parsedUrl.searchParams.get('q') || currentUrl;
}
// Outlook Safelinks
if (parsedUrl.hostname.includes('safelinks.protection.outlook.com') &&
parsedUrl.searchParams.has('url')) {
currentUrl = parsedUrl.searchParams.get('url') || currentUrl;
}
// LinkedIn Shim
if (parsedUrl.hostname === 'lnkd.in' || (parsedUrl.hostname === 'www.linkedin.com' && parsedUrl.pathname.startsWith('/Check/'))) {
// These are harder to unwrap without following
}
// 2. Follow redirects (optional, but good for bit.ly etc.)
// We only follow if it's a known shortener or if we want to be thorough.
const shorteners = ['bit.ly', 't.co', 'goo.gl', 'tinyurl.com', 'is.gd', 'buff.ly', 'adf.ly', 'lnkd.in'];
const isShortener = shorteners.some(s => parsedUrl.hostname.includes(s));
if (isShortener) {
const response = await axios.head(currentUrl, {
maxRedirects: 5,
validateStatus: (status) => status >= 200 && status < 400
});
if (response.request.res.responseUrl) {
currentUrl = response.request.res.responseUrl;
}
}
return currentUrl;
} catch (error) {
console.error('Error resolving URL:', error);
return url; // Return original if error
}
}