diff --git a/api/check-hsts.js b/api/check-hsts.js index 71382cb..9dfed13 100644 --- a/api/check-hsts.js +++ b/api/check-hsts.js @@ -1,8 +1,7 @@ const https = require('https'); +const middleware = require('./_common/middleware'); -exports.handler = async function(event, context) { - const siteURL = (event.queryStringParameters || event.query).url; - +exports.handler = middleware(async (url, event, context) => { const errorResponse = (message, statusCode = 500) => { return { statusCode: statusCode, @@ -16,15 +15,9 @@ exports.handler = async function(event, context) { }; }; - if (!siteURL) { - return { - statusCode: 400, - body: JSON.stringify({ error: 'URL parameter is missing!' }), - }; - } return new Promise((resolve, reject) => { - const req = https.request(siteURL, res => { + const req = https.request(url, res => { const headers = res.headers; const hstsHeader = headers['strict-transport-security']; @@ -60,4 +53,5 @@ exports.handler = async function(event, context) { req.end(); }); -}; +}); + diff --git a/api/content-links.js b/api/content-links.js index 34e4205..45c3f50 100644 --- a/api/content-links.js +++ b/api/content-links.js @@ -1,48 +1,35 @@ const axios = require('axios'); const cheerio = require('cheerio'); const urlLib = require('url'); +const commonMiddleware = require('./_common/middleware'); -exports.handler = async (event, context) => { - let url = event.queryStringParameters.url; - - // Check if url includes protocol - if (!url.startsWith('http://') && !url.startsWith('https://')) { - url = 'http://' + url; - } - - try { - const response = await axios.get(url); - const html = response.data; - const $ = cheerio.load(html); - const internalLinksMap = new Map(); - const externalLinksMap = new Map(); +const handler = async (url) => { + const response = await axios.get(url); + const html = response.data; + const $ = cheerio.load(html); + const internalLinksMap = new Map(); + const externalLinksMap = new Map(); - $('a[href]').each((i, link) => { - const href = $(link).attr('href'); - const absoluteUrl = urlLib.resolve(url, href); - - if (absoluteUrl.startsWith(url)) { - const count = internalLinksMap.get(absoluteUrl) || 0; - internalLinksMap.set(absoluteUrl, count + 1); - } else if (href.startsWith('http://') || href.startsWith('https://')) { - const count = externalLinksMap.get(absoluteUrl) || 0; - externalLinksMap.set(absoluteUrl, count + 1); - } - }); + // Get all links on the page + $('a[href]').each((i, link) => { + const href = $(link).attr('href'); + const absoluteUrl = urlLib.resolve(url, href); + + // Check if absolute / relative, append to appropriate map or increment occurrence count + if (absoluteUrl.startsWith(url)) { + const count = internalLinksMap.get(absoluteUrl) || 0; + internalLinksMap.set(absoluteUrl, count + 1); + } else if (href.startsWith('http://') || href.startsWith('https://')) { + const count = externalLinksMap.get(absoluteUrl) || 0; + externalLinksMap.set(absoluteUrl, count + 1); + } + }); - // Convert maps to sorted arrays - const internalLinks = [...internalLinksMap.entries()].sort((a, b) => b[1] - a[1]).map(entry => entry[0]); - const externalLinks = [...externalLinksMap.entries()].sort((a, b) => b[1] - a[1]).map(entry => entry[0]); + // Sort by most occurrences, remove supplicates, and convert to array + const internalLinks = [...internalLinksMap.entries()].sort((a, b) => b[1] - a[1]).map(entry => entry[0]); + const externalLinks = [...externalLinksMap.entries()].sort((a, b) => b[1] - a[1]).map(entry => entry[0]); - return { - statusCode: 200, - body: JSON.stringify({ internal: internalLinks, external: externalLinks }), - }; - } catch (error) { - console.log(error); - return { - statusCode: 500, - body: JSON.stringify({ error: 'Failed fetching data' }), - }; - } + return { internal: internalLinks, external: externalLinks }; }; + +exports.handler = commonMiddleware(handler); diff --git a/api/dns-sec.js b/api/dns-sec.js index c4cf3f3..5f04044 100644 --- a/api/dns-sec.js +++ b/api/dns-sec.js @@ -1,16 +1,7 @@ const https = require('https'); +const commonMiddleware = require('./_common/middleware'); // Make sure this path is correct -exports.handler = async function(event, context) { - const url = (event.queryStringParameters || event.query).url; - - if (!url) { - return errorResponse('URL query parameter is required.'); - } - - // Extract hostname from URL - const parsedUrl = new URL(url); - const domain = parsedUrl.hostname; - +const fetchDNSRecords = async (domain, event, context) => { const dnsTypes = ['DNSKEY', 'DS', 'RRSIG']; const records = {}; @@ -48,22 +39,14 @@ exports.handler = async function(event, context) { if (dnsResponse.Answer) { records[type] = { isFound: true, answer: dnsResponse.Answer, response: dnsResponse.Answer }; } else { - records[type] = { isFound: false, answer: null, response: dnsResponse}; + records[type] = { isFound: false, answer: null, response: dnsResponse }; } } catch (error) { - return errorResponse(`Error fetching ${type} record: ${error.message}`); + throw new Error(`Error fetching ${type} record: ${error.message}`); // This will be caught and handled by the commonMiddleware } } - return { - statusCode: 200, - body: JSON.stringify(records), - }; + return records; }; -const errorResponse = (message, statusCode = 444) => { - return { - statusCode: statusCode, - body: JSON.stringify({ error: message }), - }; -}; +exports.handler = commonMiddleware(fetchDNSRecords); diff --git a/api/dns-server.js b/api/dns-server.js index 3bcbe3b..5be9385 100644 --- a/api/dns-server.js +++ b/api/dns-server.js @@ -1,12 +1,11 @@ const dns = require('dns'); const dnsPromises = dns.promises; -// const https = require('https'); const axios = require('axios'); +const commonMiddleware = require('./_common/middleware'); -exports.handler = async (event) => { - const url = (event.queryStringParameters || event.query).url; - const domain = url.replace(/^(?:https?:\/\/)?/i, ""); +const handler = async (url) => { try { + const domain = url.replace(/^(?:https?:\/\/)?/i, ""); const addresses = await dnsPromises.resolve4(domain); const results = await Promise.all(addresses.map(async (address) => { const hostname = await dnsPromises.reverse(address).catch(() => null); @@ -23,6 +22,7 @@ exports.handler = async (event) => { dohDirectSupports, }; })); + // let dohMozillaSupport = false; // try { // const mozillaList = await axios.get('https://firefox.settings.services.mozilla.com/v1/buckets/security-state/collections/onecrl/records'); @@ -30,20 +30,15 @@ exports.handler = async (event) => { // } catch (error) { // console.error(error); // } + return { - statusCode: 200, - body: JSON.stringify({ - domain, - dns: results, - // dohMozillaSupport, - }), + domain, + dns: results, + // dohMozillaSupport, }; } catch (error) { - return { - statusCode: 500, - body: JSON.stringify({ - error: `An error occurred while resolving DNS. ${error.message}`, - }), - }; + throw new Error(`An error occurred while resolving DNS. ${error.message}`); // This will be caught and handled by the commonMiddleware } }; + +exports.handler = commonMiddleware(handler); diff --git a/api/find-url-ip.js b/api/find-url-ip.js index 30355c9..8df95bc 100644 --- a/api/find-url-ip.js +++ b/api/find-url-ip.js @@ -1,33 +1,21 @@ const dns = require('dns'); +const middleware = require('./_common/middleware'); -/* Lambda function to fetch the IP address of a given URL */ -exports.handler = function (event, context, callback) { - const addressParam = (event.queryStringParameters || event.query).url; - - if (!addressParam) { - callback(null, errorResponse('Address parameter is missing.')); - return; - } - - const address = decodeURIComponent(addressParam) - .replaceAll('https://', '') - .replaceAll('http://', ''); - - dns.lookup(address, (err, ip, family) => { - if (err) { - callback(null, errorResponse(err.message)); - } else { - callback(null, { - statusCode: 200, - body: JSON.stringify({ ip, family }), - }); - } +const lookupAsync = (address) => { + return new Promise((resolve, reject) => { + dns.lookup(address, (err, ip, family) => { + if (err) { + reject(err); + } else { + resolve({ ip, family }); + } + }); }); }; -const errorResponse = (message, statusCode = 444) => { - return { - statusCode: statusCode, - body: JSON.stringify({ error: message }), - }; +const handler = async (url) => { + const address = url.replaceAll('https://', '').replaceAll('http://', ''); + return await lookupAsync(address); }; + +exports.handler = middleware(handler); diff --git a/api/follow-redirects.js b/api/follow-redirects.js index 42b56db..9f53b02 100644 --- a/api/follow-redirects.js +++ b/api/follow-redirects.js @@ -1,9 +1,8 @@ -exports.handler = async (event) => { - const url = (event.queryStringParameters || event.query).url; +const handler = async (url) => { const redirects = [url]; + const got = await import('got'); try { - const got = await import('got'); await got.default(url, { followRedirect: true, maxRedirects: 12, @@ -17,19 +16,12 @@ exports.handler = async (event) => { }); return { - statusCode: 200, - body: JSON.stringify({ - redirects: redirects, - }), + redirects: redirects, }; } catch (error) { - return errorResponse(`Error: ${error.message}`); + throw new Error(`Error: ${error.message}`); } }; -const errorResponse = (message, statusCode = 444) => { - return { - statusCode: statusCode, - body: JSON.stringify({ error: message }), - }; -}; +const middleware = require('./_common/middleware'); +exports.handler = middleware(handler); diff --git a/api/get-carbon.js b/api/get-carbon.js index d975753..42dd6f8 100644 --- a/api/get-carbon.js +++ b/api/get-carbon.js @@ -1,14 +1,7 @@ const https = require('https'); +const middleware = require('./_common/middleware'); -exports.handler = async (event, context) => { - const url = (event.queryStringParameters || event.query).url; - - if (!url) { - return { - statusCode: 400, - body: JSON.stringify({ error: 'url query parameter is required' }), - }; - } +const handler = async (url) => { // First, get the size of the website's HTML const getHtmlSize = (url) => new Promise((resolve, reject) => { @@ -42,14 +35,10 @@ exports.handler = async (event, context) => { }); carbonData.scanUrl = url; - return { - statusCode: 200, - body: JSON.stringify(carbonData), - }; + return carbonData; } catch (error) { - return { - statusCode: 500, - body: JSON.stringify({ error: `Error: ${error.message}` }), - }; + throw new Error(`Error: ${error.message}`); } }; + +exports.handler = middleware(handler); diff --git a/api/get-cookies.js b/api/get-cookies.js index e2c05f2..f24d68a 100644 --- a/api/get-cookies.js +++ b/api/get-cookies.js @@ -1,26 +1,14 @@ const axios = require('axios'); +const middleware = require('./_common/middleware'); -exports.handler = async function(event, context) { - const url = (event.queryStringParameters || event.query).url; - - if (!url) { - return { - statusCode: 400, - body: JSON.stringify({ message: 'url query string parameter is required' }), - }; - } - +const handler = async (url, event, context) => { try { const response = await axios.get(url, {withCredentials: true}); const cookies = response.headers['set-cookie']; - return { - statusCode: 200, - body: JSON.stringify({ cookies }), - }; + return { cookies }; } catch (error) { - return { - statusCode: 500, - body: JSON.stringify({ error: error.message }), - }; + throw new Error(error.message); } }; + +exports.handler = middleware(handler); diff --git a/api/get-dns.js b/api/get-dns.js index 1be91a2..f7774a9 100644 --- a/api/get-dns.js +++ b/api/get-dns.js @@ -1,8 +1,9 @@ const dns = require('dns'); const util = require('util'); +const middleware = require('./_common/middleware'); -exports.handler = async function(event, context) { - let hostname = (event.queryStringParameters || event.query).url; +const handler = async (url) => { + let hostname = url; // Handle URLs by extracting hostname if (hostname.startsWith('http://') || hostname.startsWith('https://')) { @@ -35,25 +36,19 @@ exports.handler = async function(event, context) { ]); return { - statusCode: 200, - body: JSON.stringify({ - A: a, - AAAA: aaaa, - MX: mx, - TXT: txt, - NS: ns, - CNAME: cname, - SOA: soa, - SRV: srv, - PTR: ptr - }) + A: a, + AAAA: aaaa, + MX: mx, + TXT: txt, + NS: ns, + CNAME: cname, + SOA: soa, + SRV: srv, + PTR: ptr }; } catch (error) { - return { - statusCode: 500, - body: JSON.stringify({ - error: error.message - }) - }; + throw new Error(error.message); } }; + +exports.handler = middleware(handler); diff --git a/api/get-headers.js b/api/get-headers.js index 00cf755..79b4c4a 100644 --- a/api/get-headers.js +++ b/api/get-headers.js @@ -1,15 +1,7 @@ const axios = require('axios'); +const middleware = require('./_common/middleware'); -exports.handler = async function(event, context) { - const url = (event.queryStringParameters || event.query).url; - - if (!url) { - return { - statusCode: 400, - body: JSON.stringify({ error: 'url query string parameter is required' }), - }; - } - +const handler = async (url, event, context) => { try { const response = await axios.get(url, { validateStatus: function (status) { @@ -17,15 +9,10 @@ exports.handler = async function(event, context) { }, }); - return { - statusCode: 200, - body: JSON.stringify(response.headers), - }; + return response.headers; } catch (error) { - console.log(error); - return { - statusCode: 500, - body: JSON.stringify({ error: error.message }), - }; + throw new Error(error.message); } }; + +exports.handler = middleware(handler); diff --git a/api/get-txt.js b/api/get-txt.js index cf3883b..f397bc5 100644 --- a/api/get-txt.js +++ b/api/get-txt.js @@ -1,17 +1,11 @@ const dns = require('dns').promises; +const middleware = require('./_common/middleware'); -exports.handler = async (event) => { - let url = (event.queryStringParameters || event.query).url; +const handler = async (url, event, context) => { try { - url = new URL(url); - } catch (error) { - return { - statusCode: 400, - body: JSON.stringify({ error: `Invalid URL ${error}` }), - }; - } - try { - const txtRecords = await dns.resolveTxt(url.hostname); + const parsedUrl = new URL(url); + + const txtRecords = await dns.resolveTxt(parsedUrl.hostname); // Parsing and formatting TXT records into a single object const readableTxtRecords = txtRecords.reduce((acc, recordArray) => { @@ -24,15 +18,15 @@ exports.handler = async (event) => { return { ...acc, ...recordObject }; }, {}); - return { - statusCode: 200, - body: JSON.stringify(readableTxtRecords), - }; + return readableTxtRecords; + } catch (error) { - console.error('Error:', error); - return { - statusCode: 500, - body: JSON.stringify({ error: error.message }), - }; + if (error.code === 'ERR_INVALID_URL') { + throw new Error(`Invalid URL ${error}`); + } else { + throw error; + } } }; + +exports.handler = middleware(handler); diff --git a/api/lighthouse-report.js b/api/lighthouse-report.js index ab76aff..2c606db 100644 --- a/api/lighthouse-report.js +++ b/api/lighthouse-report.js @@ -1,40 +1,22 @@ const axios = require('axios'); +const middleware = require('./_common/middleware'); -exports.handler = function(event, context, callback) { - const url = (event.queryStringParameters || event.query).url; - - if (!url) { - callback(null, { - statusCode: 400, - body: JSON.stringify({ error: 'URL param is required'}), - }); - } - +const handler = async (url, event, context) => { const apiKey = process.env.GOOGLE_CLOUD_API_KEY; + if (!url) { + throw new Error('URL param is required'); + } + if (!apiKey) { - callback(null, { - statusCode: 500, - body: JSON.stringify({ error: 'API key (GOOGLE_CLOUD_API_KEY) not set'}), - }); + throw new Error('API key (GOOGLE_CLOUD_API_KEY) not set'); } const endpoint = `https://www.googleapis.com/pagespeedonline/v5/runPagespeed?url=${encodeURIComponent(url)}&category=PERFORMANCE&category=ACCESSIBILITY&category=BEST_PRACTICES&category=SEO&category=PWA&strategy=mobile&key=${apiKey}`; + + const response = await axios.get(endpoint); - axios.get(endpoint) - .then( - (response) => { - callback(null, { - statusCode: 200, - body: JSON.stringify(response.data), - }); - } - ).catch( - () => { - callback(null, { - statusCode: 500, - body: JSON.stringify({ error: 'Error running Lighthouse'}), - }); - } - ); + return response.data; }; + +exports.handler = middleware(handler); diff --git a/api/screenshot.js b/api/screenshot.js index 75f1741..49906f0 100644 --- a/api/screenshot.js +++ b/api/screenshot.js @@ -1,16 +1,11 @@ const puppeteer = require('puppeteer-core'); const chromium = require('chrome-aws-lambda'); +const middleware = require('./_common/middleware'); -exports.handler = async (event, context, callback) => { - let browser = null; - let targetUrl = (event.queryStringParameters || event.query).url; +const screenshotHandler = async (targetUrl) => { if (!targetUrl) { - callback(null, { - statusCode: 400, - body: JSON.stringify({ error: 'URL is missing from queryStringParameters' }), - }); - return; + throw new Error('URL is missing from queryStringParameters'); } if (!targetUrl.startsWith('http://') && !targetUrl.startsWith('https://')) { @@ -20,13 +15,10 @@ exports.handler = async (event, context, callback) => { try { new URL(targetUrl); } catch (error) { - callback(null, { - statusCode: 400, - body: JSON.stringify({ error: 'URL provided is invalid' }), - }); - return; + throw new Error('URL provided is invalid'); } + let browser = null; try { browser = await puppeteer.launch({ args: chromium.args, @@ -40,9 +32,7 @@ exports.handler = async (event, context, callback) => { let page = await browser.newPage(); await page.emulateMediaFeatures([{ name: 'prefers-color-scheme', value: 'dark' }]); - page.setDefaultNavigationTimeout(8000); - await page.goto(targetUrl, { waitUntil: 'domcontentloaded' }); await page.evaluate(() => { @@ -57,24 +47,15 @@ exports.handler = async (event, context, callback) => { }); const screenshotBuffer = await page.screenshot(); - const base64Screenshot = screenshotBuffer.toString('base64'); - const response = { - statusCode: 200, - body: JSON.stringify({ image: base64Screenshot }), - }; + return { image: base64Screenshot }; - callback(null, response); - } catch (error) { - console.log(error); - callback(null, { - statusCode: 500, - body: JSON.stringify({ error: `An error occurred: ${error.message}` }), - }); } finally { if (browser !== null) { await browser.close(); } } }; + +exports.handler = middleware(screenshotHandler); diff --git a/api/security-txt.js b/api/security-txt.js index 78ded4c..c2cd59c 100644 --- a/api/security-txt.js +++ b/api/security-txt.js @@ -1,5 +1,6 @@ const { https } = require('follow-redirects'); const { URL } = require('url'); +const middleware = require('./_common/middleware'); const SECURITY_TXT_PATHS = [ '/security.txt', @@ -37,59 +38,39 @@ const isPgpSigned = (result) => { return false; }; -exports.handler = async (event, context) => { - const urlParam = (event.queryStringParameters || event.query).url; - if (!urlParam) { - return { - statusCode: 400, - body: JSON.stringify({ error: 'Missing url parameter' }) - }; - } +const securityTxtHandler = async (urlParam) => { let url; try { url = new URL(urlParam.includes('://') ? urlParam : 'https://' + urlParam); } catch (error) { - return { - statusCode: 500, - body: JSON.stringify({ error: 'Invalid URL format' }), - }; + throw new Error('Invalid URL format'); } url.pathname = ''; for (let path of SECURITY_TXT_PATHS) { try { const result = await fetchSecurityTxt(url, path); - if (result && result.includes(' { const url = new URL(path, baseURL); diff --git a/api/server-status.js b/api/server-status.js index 242df31..ce4f478 100644 --- a/api/server-status.js +++ b/api/server-status.js @@ -1,14 +1,10 @@ const https = require('https'); const { performance, PerformanceObserver } = require('perf_hooks'); +const middleware = require('./_common/middleware'); -exports.handler = async function(event, context) { - const url = (event.queryStringParameters || event.query).url; - +const checkURLHandler = async (url) => { if (!url) { - return { - statusCode: 400, - body: JSON.stringify({ error: 'You must provide a URL query parameter!' }), - }; + throw new Error('You must provide a URL query parameter!'); } let dnsLookupTime; @@ -43,10 +39,7 @@ exports.handler = async function(event, context) { }); if (responseCode < 200 || responseCode >= 400) { - return { - statusCode: 200, - body: JSON.stringify({ error: `Received non-success response code: ${responseCode}` }), - }; + throw new Error(`Received non-success response code: ${responseCode}`); } performance.mark('B'); @@ -54,16 +47,12 @@ exports.handler = async function(event, context) { let responseTime = performance.now() - startTime; obs.disconnect(); - return { - statusCode: 200, - body: JSON.stringify({ isUp: true, dnsLookupTime, responseTime, responseCode }), - }; + return { isUp: true, dnsLookupTime, responseTime, responseCode }; } catch (error) { obs.disconnect(); - return { - statusCode: 200, - body: JSON.stringify({ error: `Error during operation: ${error.message}` }), - }; + throw error; } }; + +exports.handler = middleware(checkURLHandler); diff --git a/api/site-features.js b/api/site-features.js index d9b6486..ced8757 100644 --- a/api/site-features.js +++ b/api/site-features.js @@ -1,22 +1,15 @@ const https = require('https'); +const middleware = require('./_common/middleware'); -exports.handler = async function (event, context) { - const url = (event.queryStringParameters || event.query).url; +const builtWithHandler = async (url) => { const apiKey = process.env.BUILT_WITH_API_KEY; - const errorResponse = (message, statusCode = 500) => { - return { - statusCode: statusCode, - body: JSON.stringify({ error: message }), - }; - }; - if (!url) { - return errorResponse('URL query parameter is required', 400); + throw new Error('URL query parameter is required'); } if (!apiKey) { - return errorResponse('Missing BuiltWith API key in environment variables', 500); + throw new Error('Missing BuiltWith API key in environment variables'); } const apiUrl = `https://api.builtwith.com/free1/api.json?KEY=${apiKey}&LOOKUP=${encodeURIComponent(url)}`; @@ -46,11 +39,10 @@ exports.handler = async function (event, context) { req.end(); }); - return { - statusCode: 200, - body: response, - }; + return response; } catch (error) { - return errorResponse(`Error making request: ${error.message}`); + throw new Error(`Error making request: ${error.message}`); } }; + +exports.handler = middleware(builtWithHandler); diff --git a/api/sitemap.js b/api/sitemap.js index 149835f..f68cce0 100644 --- a/api/sitemap.js +++ b/api/sitemap.js @@ -1,10 +1,8 @@ const axios = require('axios'); const xml2js = require('xml2js'); +const middleware = require('./_common/middleware'); -exports.handler = async (event) => { - const url = (event.queryStringParameters || event.query).url; - // const baseUrl = event.queryStringParameters.url.replace(/^(?:https?:\/\/)?/i, ""); - // const url = baseUrl.startsWith('http') ? baseUrl : `http://${baseUrl}`; +const fetchSitemapHandler = async (url) => { let sitemapUrl; try { @@ -19,24 +17,17 @@ exports.handler = async (event) => { } if (!sitemapUrl) { - return { - statusCode: 404, - body: JSON.stringify({ error: 'Sitemap not found in robots.txt' }), - }; + throw new Error('Sitemap not found in robots.txt'); } // Fetch sitemap const sitemapRes = await axios.get(sitemapUrl); const sitemap = await xml2js.parseStringPromise(sitemapRes.data); - return { - statusCode: 200, - body: JSON.stringify(sitemap), - }; + return sitemap; } catch (error) { - return { - statusCode: 500, - body: JSON.stringify({ error: error.message }), - }; + throw new Error(error.message); } }; + +exports.handler = middleware(fetchSitemapHandler); diff --git a/api/ssl-check.js b/api/ssl-check.js index f87b66a..22d998f 100644 --- a/api/ssl-check.js +++ b/api/ssl-check.js @@ -1,43 +1,28 @@ const https = require('https'); +const middleware = require('./_common/middleware'); -exports.handler = async function (event, context) { - const url = (event.queryStringParameters || event.query).url; - - const errorResponse = (message, statusCode = 500) => { - return { - statusCode: statusCode, - body: JSON.stringify({ error: message }), - }; - }; - - if (!url) { - return errorResponse('URL query parameter is required', 400); - } - +const fetchSiteCertificateHandler = async (url) => { try { const response = await new Promise((resolve, reject) => { const req = https.request(url, res => { - + // Check if the SSL handshake was authorized if (!res.socket.authorized) { - resolve(errorResponse(`SSL handshake not authorized. Reason: ${res.socket.authorizationError}`)); + reject(new Error(`SSL handshake not authorized. Reason: ${res.socket.authorizationError}`)); } else { let cert = res.socket.getPeerCertificate(true); if (!cert || Object.keys(cert).length === 0) { - resolve(errorResponse("No certificate presented by the server.")); + reject(new Error("No certificate presented by the server.")); } else { // omit the raw and issuerCertificate fields const { raw, issuerCertificate, ...certWithoutRaw } = cert; - resolve({ - statusCode: 200, - body: JSON.stringify(certWithoutRaw), - }); + resolve(certWithoutRaw); } } }); req.on('error', error => { - resolve(errorResponse(`Error fetching site certificate: ${error.message}`)); + reject(new Error(`Error fetching site certificate: ${error.message}`)); }); req.end(); @@ -45,6 +30,8 @@ exports.handler = async function (event, context) { return response; } catch (error) { - return errorResponse(`Unexpected error occurred: ${error.message}`); + throw new Error(error.message); } }; + +exports.handler = middleware(fetchSiteCertificateHandler); diff --git a/api/tech-stack.js b/api/tech-stack.js index 596ba52..5820f6d 100644 --- a/api/tech-stack.js +++ b/api/tech-stack.js @@ -1,69 +1,30 @@ const Wappalyzer = require('wappalyzer'); +const middleware = require('./_common/middleware'); -const analyze = async (url) => { - +const analyzeSiteTechnologies = async (url) => { const options = {}; const wappalyzer = new Wappalyzer(options); - return (async function() { - try { - await wappalyzer.init() - const headers = {} - const storage = { - local: {}, - session: {}, - } - const site = await wappalyzer.open(url, headers, storage) - const results = await site.analyze() - return results; - } catch (error) { - return error; - } finally { - await wappalyzer.destroy() - } - })(); -} -exports.handler = async (event, context, callback) => { - // Validate URL parameter - if (!(event.queryStringParameters || event.query).url) { - return { - statusCode: 400, - body: JSON.stringify({ error: 'Missing url parameter' }), - }; - } - - // Get URL from param - let url = (event.queryStringParameters || event.query).url; - if (!/^https?:\/\//i.test(url)) { - url = 'http://' + url; - } - try { - return analyze(url).then( - (results) => { - if (!results.technologies || results.technologies.length === 0) { - return { - statusCode: 200, - body: JSON.stringify({ error: 'Unable to find any technologies for site' }), - }; - } - return { - statusCode: 200, - body: JSON.stringify(results), - } - } - ) - .catch((error) => { - return { - statusCode: 500, - body: JSON.stringify({ error: error.message }), - }; - }); - } catch (error) { - return { - statusCode: 500, - body: JSON.stringify({ error: error.message }), + await wappalyzer.init(); + const headers = {}; + const storage = { + local: {}, + session: {}, }; + const site = await wappalyzer.open(url, headers, storage); + const results = await site.analyze(); + + if (!results.technologies || results.technologies.length === 0) { + throw new Error('Unable to find any technologies for site'); + } + return results; + } catch (error) { + throw new Error(error.message); + } finally { + await wappalyzer.destroy(); } }; + +exports.handler = middleware(analyzeSiteTechnologies); diff --git a/api/trace-route.js b/api/trace-route.js index 8d8525e..8d7b10b 100644 --- a/api/trace-route.js +++ b/api/trace-route.js @@ -1,55 +1,31 @@ const traceroute = require('traceroute'); const url = require('url'); +const middleware = require('./_common/middleware'); -exports.handler = async function(event, context) { - const urlString = (event.queryStringParameters || event.query).url; +const executeTraceroute = async (urlString, context) => { + // Parse the URL and get the hostname + const urlObject = url.parse(urlString); + const host = urlObject.hostname; - try { - if (!urlString) { - throw new Error('URL parameter is missing!'); - } + if (!host) { + throw new Error('Invalid URL provided'); + } - // Parse the URL and get the hostname - const urlObject = url.parse(urlString); - const host = urlObject.hostname; - - if (!host) { - throw new Error('Invalid URL provided'); - } - - // Traceroute with callback - const result = await new Promise((resolve, reject) => { - traceroute.trace(host, (err, hops) => { - if (err || !hops) { - reject(err || new Error('No hops found')); - } else { - resolve(hops); - } - }); - - // Check if remaining time is less than 8.8 seconds, then reject promise - if (context.getRemainingTimeInMillis() < 8800) { - reject(new Error('Lambda is about to timeout')); + // Traceroute with callback + const result = await new Promise((resolve, reject) => { + traceroute.trace(host, (err, hops) => { + if (err || !hops) { + reject(err || new Error('No hops found')); + } else { + resolve(hops); } }); + }); - return { - statusCode: 200, - body: JSON.stringify({ - message: "Traceroute completed!", - result, - }), - }; - } catch (err) { - const message = err.code === 'ENOENT' - ? 'Traceroute command is not installed on the host.' - : err.message; - - return { - statusCode: 500, - body: JSON.stringify({ - error: message, - }), - }; - } + return { + message: "Traceroute completed!", + result, + }; }; + +exports.handler = middleware(executeTraceroute); diff --git a/api/whois-lookup.js b/api/whois-lookup.js index 3b6ba3e..69e5674 100644 --- a/api/whois-lookup.js +++ b/api/whois-lookup.js @@ -1,14 +1,6 @@ const net = require('net'); const psl = require('psl'); -// const { URL } = require('url'); - -const errorResponse = (message, statusCode = 444) => { - return { - statusCode: statusCode, - body: JSON.stringify({ error: message }), - }; -}; - +const middleware = require('./_common/middleware'); const getBaseDomain = (url) => { let protocol = ''; @@ -22,55 +14,7 @@ const getBaseDomain = (url) => { return protocol + parsed.domain; }; - -exports.handler = async function(event, context) { - const url = (event.queryStringParameters || event.query).url; - - if (!url) { - return errorResponse('URL query parameter is required.', 400); - } - - if (!url.startsWith('http://') && !url.startsWith('https://')) { - url = 'http://' + url; - } - - let hostname; - try { - hostname = getBaseDomain(new URL(url).hostname); - } catch (error) { - return errorResponse(`Unable to parse URL: ${error}`, 400); - } - - return new Promise((resolve, reject) => { - const client = net.createConnection({ port: 43, host: 'whois.internic.net' }, () => { - client.write(hostname + '\r\n'); - }); - - let data = ''; - client.on('data', (chunk) => { - data += chunk; - }); - - client.on('end', () => { - try { - const parsedData = parseWhoisData(data); - resolve({ - statusCode: 200, - body: JSON.stringify(parsedData), - }); - } catch (error) { - resolve(errorResponse(error.message)); - } - }); - - client.on('error', (err) => { - resolve(errorResponse(err.message, 500)); - }); - }); -}; - const parseWhoisData = (data) => { - if (data.includes('No match for')) { return { error: 'No matches found for domain in internic database'}; } @@ -100,3 +44,41 @@ const parseWhoisData = (data) => { return parsedData; }; +const fetchWhoisData = async (url) => { + if (!url.startsWith('http://') && !url.startsWith('https://')) { + url = 'http://' + url; + } + + let hostname; + try { + hostname = getBaseDomain(new URL(url).hostname); + } catch (error) { + throw new Error(`Unable to parse URL: ${error}`); + } + + return new Promise((resolve, reject) => { + const client = net.createConnection({ port: 43, host: 'whois.internic.net' }, () => { + client.write(hostname + '\r\n'); + }); + + let data = ''; + client.on('data', (chunk) => { + data += chunk; + }); + + client.on('end', () => { + try { + const parsedData = parseWhoisData(data); + resolve(parsedData); + } catch (error) { + reject(error); + } + }); + + client.on('error', (err) => { + reject(err); + }); + }); +}; + +exports.handler = middleware(fetchWhoisData);