Updates all API endpoints to use common middleware

This commit is contained in:
Alicia Sykes 2023-08-09 22:33:36 +01:00
parent 85af5f9327
commit d2a56eb526
21 changed files with 264 additions and 550 deletions

View File

@ -1,8 +1,7 @@
const https = require('https'); const https = require('https');
const middleware = require('./_common/middleware');
exports.handler = async function(event, context) { exports.handler = middleware(async (url, event, context) => {
const siteURL = (event.queryStringParameters || event.query).url;
const errorResponse = (message, statusCode = 500) => { const errorResponse = (message, statusCode = 500) => {
return { return {
statusCode: statusCode, 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) => { return new Promise((resolve, reject) => {
const req = https.request(siteURL, res => { const req = https.request(url, res => {
const headers = res.headers; const headers = res.headers;
const hstsHeader = headers['strict-transport-security']; const hstsHeader = headers['strict-transport-security'];
@ -60,4 +53,5 @@ exports.handler = async function(event, context) {
req.end(); req.end();
}); });
}; });

View File

@ -1,48 +1,35 @@
const axios = require('axios'); const axios = require('axios');
const cheerio = require('cheerio'); const cheerio = require('cheerio');
const urlLib = require('url'); const urlLib = require('url');
const commonMiddleware = require('./_common/middleware');
exports.handler = async (event, context) => { const handler = async (url) => {
let url = event.queryStringParameters.url; const response = await axios.get(url);
const html = response.data;
const $ = cheerio.load(html);
const internalLinksMap = new Map();
const externalLinksMap = new Map();
// Check if url includes protocol // Get all links on the page
if (!url.startsWith('http://') && !url.startsWith('https://')) { $('a[href]').each((i, link) => {
url = 'http://' + url; const href = $(link).attr('href');
} const absoluteUrl = urlLib.resolve(url, href);
try { // Check if absolute / relative, append to appropriate map or increment occurrence count
const response = await axios.get(url); if (absoluteUrl.startsWith(url)) {
const html = response.data; const count = internalLinksMap.get(absoluteUrl) || 0;
const $ = cheerio.load(html); internalLinksMap.set(absoluteUrl, count + 1);
const internalLinksMap = new Map(); } else if (href.startsWith('http://') || href.startsWith('https://')) {
const externalLinksMap = new Map(); const count = externalLinksMap.get(absoluteUrl) || 0;
externalLinksMap.set(absoluteUrl, count + 1);
}
});
$('a[href]').each((i, link) => { // Sort by most occurrences, remove supplicates, and convert to array
const href = $(link).attr('href'); const internalLinks = [...internalLinksMap.entries()].sort((a, b) => b[1] - a[1]).map(entry => entry[0]);
const absoluteUrl = urlLib.resolve(url, href); const externalLinks = [...externalLinksMap.entries()].sort((a, b) => b[1] - a[1]).map(entry => entry[0]);
if (absoluteUrl.startsWith(url)) { return { internal: internalLinks, external: externalLinks };
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]);
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' }),
};
}
}; };
exports.handler = commonMiddleware(handler);

View File

@ -1,16 +1,7 @@
const https = require('https'); const https = require('https');
const commonMiddleware = require('./_common/middleware'); // Make sure this path is correct
exports.handler = async function(event, context) { const fetchDNSRecords = async (domain, 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 dnsTypes = ['DNSKEY', 'DS', 'RRSIG']; const dnsTypes = ['DNSKEY', 'DS', 'RRSIG'];
const records = {}; const records = {};
@ -48,22 +39,14 @@ exports.handler = async function(event, context) {
if (dnsResponse.Answer) { if (dnsResponse.Answer) {
records[type] = { isFound: true, answer: dnsResponse.Answer, response: dnsResponse.Answer }; records[type] = { isFound: true, answer: dnsResponse.Answer, response: dnsResponse.Answer };
} else { } else {
records[type] = { isFound: false, answer: null, response: dnsResponse}; records[type] = { isFound: false, answer: null, response: dnsResponse };
} }
} catch (error) { } 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 { return records;
statusCode: 200,
body: JSON.stringify(records),
};
}; };
const errorResponse = (message, statusCode = 444) => { exports.handler = commonMiddleware(fetchDNSRecords);
return {
statusCode: statusCode,
body: JSON.stringify({ error: message }),
};
};

View File

@ -1,12 +1,11 @@
const dns = require('dns'); const dns = require('dns');
const dnsPromises = dns.promises; const dnsPromises = dns.promises;
// const https = require('https');
const axios = require('axios'); const axios = require('axios');
const commonMiddleware = require('./_common/middleware');
exports.handler = async (event) => { const handler = async (url) => {
const url = (event.queryStringParameters || event.query).url;
const domain = url.replace(/^(?:https?:\/\/)?/i, "");
try { try {
const domain = url.replace(/^(?:https?:\/\/)?/i, "");
const addresses = await dnsPromises.resolve4(domain); const addresses = await dnsPromises.resolve4(domain);
const results = await Promise.all(addresses.map(async (address) => { const results = await Promise.all(addresses.map(async (address) => {
const hostname = await dnsPromises.reverse(address).catch(() => null); const hostname = await dnsPromises.reverse(address).catch(() => null);
@ -23,6 +22,7 @@ exports.handler = async (event) => {
dohDirectSupports, dohDirectSupports,
}; };
})); }));
// let dohMozillaSupport = false; // let dohMozillaSupport = false;
// try { // try {
// const mozillaList = await axios.get('https://firefox.settings.services.mozilla.com/v1/buckets/security-state/collections/onecrl/records'); // 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) { // } catch (error) {
// console.error(error); // console.error(error);
// } // }
return { return {
statusCode: 200, domain,
body: JSON.stringify({ dns: results,
domain, // dohMozillaSupport,
dns: results,
// dohMozillaSupport,
}),
}; };
} catch (error) { } catch (error) {
return { throw new Error(`An error occurred while resolving DNS. ${error.message}`); // This will be caught and handled by the commonMiddleware
statusCode: 500,
body: JSON.stringify({
error: `An error occurred while resolving DNS. ${error.message}`,
}),
};
} }
}; };
exports.handler = commonMiddleware(handler);

View File

@ -1,33 +1,21 @@
const dns = require('dns'); const dns = require('dns');
const middleware = require('./_common/middleware');
/* Lambda function to fetch the IP address of a given URL */ const lookupAsync = (address) => {
exports.handler = function (event, context, callback) { return new Promise((resolve, reject) => {
const addressParam = (event.queryStringParameters || event.query).url; dns.lookup(address, (err, ip, family) => {
if (err) {
if (!addressParam) { reject(err);
callback(null, errorResponse('Address parameter is missing.')); } else {
return; resolve({ ip, family });
} }
});
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 errorResponse = (message, statusCode = 444) => { const handler = async (url) => {
return { const address = url.replaceAll('https://', '').replaceAll('http://', '');
statusCode: statusCode, return await lookupAsync(address);
body: JSON.stringify({ error: message }),
};
}; };
exports.handler = middleware(handler);

View File

@ -1,9 +1,8 @@
exports.handler = async (event) => { const handler = async (url) => {
const url = (event.queryStringParameters || event.query).url;
const redirects = [url]; const redirects = [url];
const got = await import('got');
try { try {
const got = await import('got');
await got.default(url, { await got.default(url, {
followRedirect: true, followRedirect: true,
maxRedirects: 12, maxRedirects: 12,
@ -17,19 +16,12 @@ exports.handler = async (event) => {
}); });
return { return {
statusCode: 200, redirects: redirects,
body: JSON.stringify({
redirects: redirects,
}),
}; };
} catch (error) { } catch (error) {
return errorResponse(`Error: ${error.message}`); throw new Error(`Error: ${error.message}`);
} }
}; };
const errorResponse = (message, statusCode = 444) => { const middleware = require('./_common/middleware');
return { exports.handler = middleware(handler);
statusCode: statusCode,
body: JSON.stringify({ error: message }),
};
};

View File

@ -1,14 +1,7 @@
const https = require('https'); const https = require('https');
const middleware = require('./_common/middleware');
exports.handler = async (event, context) => { const handler = async (url) => {
const url = (event.queryStringParameters || event.query).url;
if (!url) {
return {
statusCode: 400,
body: JSON.stringify({ error: 'url query parameter is required' }),
};
}
// First, get the size of the website's HTML // First, get the size of the website's HTML
const getHtmlSize = (url) => new Promise((resolve, reject) => { const getHtmlSize = (url) => new Promise((resolve, reject) => {
@ -42,14 +35,10 @@ exports.handler = async (event, context) => {
}); });
carbonData.scanUrl = url; carbonData.scanUrl = url;
return { return carbonData;
statusCode: 200,
body: JSON.stringify(carbonData),
};
} catch (error) { } catch (error) {
return { throw new Error(`Error: ${error.message}`);
statusCode: 500,
body: JSON.stringify({ error: `Error: ${error.message}` }),
};
} }
}; };
exports.handler = middleware(handler);

View File

@ -1,26 +1,14 @@
const axios = require('axios'); const axios = require('axios');
const middleware = require('./_common/middleware');
exports.handler = async function(event, context) { const handler = async (url, event, context) => {
const url = (event.queryStringParameters || event.query).url;
if (!url) {
return {
statusCode: 400,
body: JSON.stringify({ message: 'url query string parameter is required' }),
};
}
try { try {
const response = await axios.get(url, {withCredentials: true}); const response = await axios.get(url, {withCredentials: true});
const cookies = response.headers['set-cookie']; const cookies = response.headers['set-cookie'];
return { return { cookies };
statusCode: 200,
body: JSON.stringify({ cookies }),
};
} catch (error) { } catch (error) {
return { throw new Error(error.message);
statusCode: 500,
body: JSON.stringify({ error: error.message }),
};
} }
}; };
exports.handler = middleware(handler);

View File

@ -1,8 +1,9 @@
const dns = require('dns'); const dns = require('dns');
const util = require('util'); const util = require('util');
const middleware = require('./_common/middleware');
exports.handler = async function(event, context) { const handler = async (url) => {
let hostname = (event.queryStringParameters || event.query).url; let hostname = url;
// Handle URLs by extracting hostname // Handle URLs by extracting hostname
if (hostname.startsWith('http://') || hostname.startsWith('https://')) { if (hostname.startsWith('http://') || hostname.startsWith('https://')) {
@ -35,25 +36,19 @@ exports.handler = async function(event, context) {
]); ]);
return { return {
statusCode: 200, A: a,
body: JSON.stringify({ AAAA: aaaa,
A: a, MX: mx,
AAAA: aaaa, TXT: txt,
MX: mx, NS: ns,
TXT: txt, CNAME: cname,
NS: ns, SOA: soa,
CNAME: cname, SRV: srv,
SOA: soa, PTR: ptr
SRV: srv,
PTR: ptr
})
}; };
} catch (error) { } catch (error) {
return { throw new Error(error.message);
statusCode: 500,
body: JSON.stringify({
error: error.message
})
};
} }
}; };
exports.handler = middleware(handler);

View File

@ -1,15 +1,7 @@
const axios = require('axios'); const axios = require('axios');
const middleware = require('./_common/middleware');
exports.handler = async function(event, context) { const handler = async (url, event, context) => {
const url = (event.queryStringParameters || event.query).url;
if (!url) {
return {
statusCode: 400,
body: JSON.stringify({ error: 'url query string parameter is required' }),
};
}
try { try {
const response = await axios.get(url, { const response = await axios.get(url, {
validateStatus: function (status) { validateStatus: function (status) {
@ -17,15 +9,10 @@ exports.handler = async function(event, context) {
}, },
}); });
return { return response.headers;
statusCode: 200,
body: JSON.stringify(response.headers),
};
} catch (error) { } catch (error) {
console.log(error); throw new Error(error.message);
return {
statusCode: 500,
body: JSON.stringify({ error: error.message }),
};
} }
}; };
exports.handler = middleware(handler);

View File

@ -1,17 +1,11 @@
const dns = require('dns').promises; const dns = require('dns').promises;
const middleware = require('./_common/middleware');
exports.handler = async (event) => { const handler = async (url, event, context) => {
let url = (event.queryStringParameters || event.query).url;
try { try {
url = new URL(url); const parsedUrl = new URL(url);
} catch (error) {
return { const txtRecords = await dns.resolveTxt(parsedUrl.hostname);
statusCode: 400,
body: JSON.stringify({ error: `Invalid URL ${error}` }),
};
}
try {
const txtRecords = await dns.resolveTxt(url.hostname);
// Parsing and formatting TXT records into a single object // Parsing and formatting TXT records into a single object
const readableTxtRecords = txtRecords.reduce((acc, recordArray) => { const readableTxtRecords = txtRecords.reduce((acc, recordArray) => {
@ -24,15 +18,15 @@ exports.handler = async (event) => {
return { ...acc, ...recordObject }; return { ...acc, ...recordObject };
}, {}); }, {});
return { return readableTxtRecords;
statusCode: 200,
body: JSON.stringify(readableTxtRecords),
};
} catch (error) { } catch (error) {
console.error('Error:', error); if (error.code === 'ERR_INVALID_URL') {
return { throw new Error(`Invalid URL ${error}`);
statusCode: 500, } else {
body: JSON.stringify({ error: error.message }), throw error;
}; }
} }
}; };
exports.handler = middleware(handler);

View File

@ -1,40 +1,22 @@
const axios = require('axios'); const axios = require('axios');
const middleware = require('./_common/middleware');
exports.handler = function(event, context, callback) { const handler = async (url, event, context) => {
const url = (event.queryStringParameters || event.query).url;
if (!url) {
callback(null, {
statusCode: 400,
body: JSON.stringify({ error: 'URL param is required'}),
});
}
const apiKey = process.env.GOOGLE_CLOUD_API_KEY; const apiKey = process.env.GOOGLE_CLOUD_API_KEY;
if (!url) {
throw new Error('URL param is required');
}
if (!apiKey) { if (!apiKey) {
callback(null, { throw new Error('API key (GOOGLE_CLOUD_API_KEY) not set');
statusCode: 500,
body: JSON.stringify({ 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 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}`;
axios.get(endpoint) const response = await axios.get(endpoint);
.then(
(response) => { return response.data;
callback(null, {
statusCode: 200,
body: JSON.stringify(response.data),
});
}
).catch(
() => {
callback(null, {
statusCode: 500,
body: JSON.stringify({ error: 'Error running Lighthouse'}),
});
}
);
}; };
exports.handler = middleware(handler);

View File

@ -1,16 +1,11 @@
const puppeteer = require('puppeteer-core'); const puppeteer = require('puppeteer-core');
const chromium = require('chrome-aws-lambda'); const chromium = require('chrome-aws-lambda');
const middleware = require('./_common/middleware');
exports.handler = async (event, context, callback) => { const screenshotHandler = async (targetUrl) => {
let browser = null;
let targetUrl = (event.queryStringParameters || event.query).url;
if (!targetUrl) { if (!targetUrl) {
callback(null, { throw new Error('URL is missing from queryStringParameters');
statusCode: 400,
body: JSON.stringify({ error: 'URL is missing from queryStringParameters' }),
});
return;
} }
if (!targetUrl.startsWith('http://') && !targetUrl.startsWith('https://')) { if (!targetUrl.startsWith('http://') && !targetUrl.startsWith('https://')) {
@ -20,13 +15,10 @@ exports.handler = async (event, context, callback) => {
try { try {
new URL(targetUrl); new URL(targetUrl);
} catch (error) { } catch (error) {
callback(null, { throw new Error('URL provided is invalid');
statusCode: 400,
body: JSON.stringify({ error: 'URL provided is invalid' }),
});
return;
} }
let browser = null;
try { try {
browser = await puppeteer.launch({ browser = await puppeteer.launch({
args: chromium.args, args: chromium.args,
@ -40,9 +32,7 @@ exports.handler = async (event, context, callback) => {
let page = await browser.newPage(); let page = await browser.newPage();
await page.emulateMediaFeatures([{ name: 'prefers-color-scheme', value: 'dark' }]); await page.emulateMediaFeatures([{ name: 'prefers-color-scheme', value: 'dark' }]);
page.setDefaultNavigationTimeout(8000); page.setDefaultNavigationTimeout(8000);
await page.goto(targetUrl, { waitUntil: 'domcontentloaded' }); await page.goto(targetUrl, { waitUntil: 'domcontentloaded' });
await page.evaluate(() => { await page.evaluate(() => {
@ -57,24 +47,15 @@ exports.handler = async (event, context, callback) => {
}); });
const screenshotBuffer = await page.screenshot(); const screenshotBuffer = await page.screenshot();
const base64Screenshot = screenshotBuffer.toString('base64'); const base64Screenshot = screenshotBuffer.toString('base64');
const response = { return { image: base64Screenshot };
statusCode: 200,
body: JSON.stringify({ image: base64Screenshot }),
};
callback(null, response);
} catch (error) {
console.log(error);
callback(null, {
statusCode: 500,
body: JSON.stringify({ error: `An error occurred: ${error.message}` }),
});
} finally { } finally {
if (browser !== null) { if (browser !== null) {
await browser.close(); await browser.close();
} }
} }
}; };
exports.handler = middleware(screenshotHandler);

View File

@ -1,5 +1,6 @@
const { https } = require('follow-redirects'); const { https } = require('follow-redirects');
const { URL } = require('url'); const { URL } = require('url');
const middleware = require('./_common/middleware');
const SECURITY_TXT_PATHS = [ const SECURITY_TXT_PATHS = [
'/security.txt', '/security.txt',
@ -37,59 +38,39 @@ const isPgpSigned = (result) => {
return false; return false;
}; };
exports.handler = async (event, context) => { const securityTxtHandler = async (urlParam) => {
const urlParam = (event.queryStringParameters || event.query).url;
if (!urlParam) {
return {
statusCode: 400,
body: JSON.stringify({ error: 'Missing url parameter' })
};
}
let url; let url;
try { try {
url = new URL(urlParam.includes('://') ? urlParam : 'https://' + urlParam); url = new URL(urlParam.includes('://') ? urlParam : 'https://' + urlParam);
} catch (error) { } catch (error) {
return { throw new Error('Invalid URL format');
statusCode: 500,
body: JSON.stringify({ error: 'Invalid URL format' }),
};
} }
url.pathname = ''; url.pathname = '';
for (let path of SECURITY_TXT_PATHS) { for (let path of SECURITY_TXT_PATHS) {
try { try {
const result = await fetchSecurityTxt(url, path); const result = await fetchSecurityTxt(url, path);
if (result && result.includes('<html')) return { if (result && result.includes('<html')) return { isPresent: false };
statusCode: 200,
body: JSON.stringify({ isPresent: false }),
};
if (result) { if (result) {
return { return {
statusCode: 200, isPresent: true,
body: JSON.stringify({ foundIn: path,
isPresent: true, content: result,
foundIn: path, isPgpSigned: isPgpSigned(result),
content: result, fields: parseResult(result),
isPgpSigned: isPgpSigned(result),
fields: parseResult(result),
}),
}; };
} }
} catch (error) { } catch (error) {
return { throw new Error(error.message);
statusCode: 500,
body: JSON.stringify({ error: error.message }),
};
} }
} }
return { return { isPresent: false };
statusCode: 404,
body: JSON.stringify({ isPresent: false }),
};
}; };
exports.handler = middleware(securityTxtHandler);
async function fetchSecurityTxt(baseURL, path) { async function fetchSecurityTxt(baseURL, path) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const url = new URL(path, baseURL); const url = new URL(path, baseURL);

View File

@ -1,14 +1,10 @@
const https = require('https'); const https = require('https');
const { performance, PerformanceObserver } = require('perf_hooks'); const { performance, PerformanceObserver } = require('perf_hooks');
const middleware = require('./_common/middleware');
exports.handler = async function(event, context) { const checkURLHandler = async (url) => {
const url = (event.queryStringParameters || event.query).url;
if (!url) { if (!url) {
return { throw new Error('You must provide a URL query parameter!');
statusCode: 400,
body: JSON.stringify({ error: 'You must provide a URL query parameter!' }),
};
} }
let dnsLookupTime; let dnsLookupTime;
@ -43,10 +39,7 @@ exports.handler = async function(event, context) {
}); });
if (responseCode < 200 || responseCode >= 400) { if (responseCode < 200 || responseCode >= 400) {
return { throw new Error(`Received non-success response code: ${responseCode}`);
statusCode: 200,
body: JSON.stringify({ error: `Received non-success response code: ${responseCode}` }),
};
} }
performance.mark('B'); performance.mark('B');
@ -54,16 +47,12 @@ exports.handler = async function(event, context) {
let responseTime = performance.now() - startTime; let responseTime = performance.now() - startTime;
obs.disconnect(); obs.disconnect();
return { return { isUp: true, dnsLookupTime, responseTime, responseCode };
statusCode: 200,
body: JSON.stringify({ isUp: true, dnsLookupTime, responseTime, responseCode }),
};
} catch (error) { } catch (error) {
obs.disconnect(); obs.disconnect();
return { throw error;
statusCode: 200,
body: JSON.stringify({ error: `Error during operation: ${error.message}` }),
};
} }
}; };
exports.handler = middleware(checkURLHandler);

View File

@ -1,22 +1,15 @@
const https = require('https'); const https = require('https');
const middleware = require('./_common/middleware');
exports.handler = async function (event, context) { const builtWithHandler = async (url) => {
const url = (event.queryStringParameters || event.query).url;
const apiKey = process.env.BUILT_WITH_API_KEY; const apiKey = process.env.BUILT_WITH_API_KEY;
const errorResponse = (message, statusCode = 500) => {
return {
statusCode: statusCode,
body: JSON.stringify({ error: message }),
};
};
if (!url) { if (!url) {
return errorResponse('URL query parameter is required', 400); throw new Error('URL query parameter is required');
} }
if (!apiKey) { 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)}`; 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(); req.end();
}); });
return { return response;
statusCode: 200,
body: response,
};
} catch (error) { } catch (error) {
return errorResponse(`Error making request: ${error.message}`); throw new Error(`Error making request: ${error.message}`);
} }
}; };
exports.handler = middleware(builtWithHandler);

View File

@ -1,10 +1,8 @@
const axios = require('axios'); const axios = require('axios');
const xml2js = require('xml2js'); const xml2js = require('xml2js');
const middleware = require('./_common/middleware');
exports.handler = async (event) => { const fetchSitemapHandler = async (url) => {
const url = (event.queryStringParameters || event.query).url;
// const baseUrl = event.queryStringParameters.url.replace(/^(?:https?:\/\/)?/i, "");
// const url = baseUrl.startsWith('http') ? baseUrl : `http://${baseUrl}`;
let sitemapUrl; let sitemapUrl;
try { try {
@ -19,24 +17,17 @@ exports.handler = async (event) => {
} }
if (!sitemapUrl) { if (!sitemapUrl) {
return { throw new Error('Sitemap not found in robots.txt');
statusCode: 404,
body: JSON.stringify({ error: 'Sitemap not found in robots.txt' }),
};
} }
// Fetch sitemap // Fetch sitemap
const sitemapRes = await axios.get(sitemapUrl); const sitemapRes = await axios.get(sitemapUrl);
const sitemap = await xml2js.parseStringPromise(sitemapRes.data); const sitemap = await xml2js.parseStringPromise(sitemapRes.data);
return { return sitemap;
statusCode: 200,
body: JSON.stringify(sitemap),
};
} catch (error) { } catch (error) {
return { throw new Error(error.message);
statusCode: 500,
body: JSON.stringify({ error: error.message }),
};
} }
}; };
exports.handler = middleware(fetchSitemapHandler);

View File

@ -1,43 +1,28 @@
const https = require('https'); const https = require('https');
const middleware = require('./_common/middleware');
exports.handler = async function (event, context) { const fetchSiteCertificateHandler = async (url) => {
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);
}
try { try {
const response = await new Promise((resolve, reject) => { const response = await new Promise((resolve, reject) => {
const req = https.request(url, res => { const req = https.request(url, res => {
// Check if the SSL handshake was authorized // Check if the SSL handshake was authorized
if (!res.socket.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 { } else {
let cert = res.socket.getPeerCertificate(true); let cert = res.socket.getPeerCertificate(true);
if (!cert || Object.keys(cert).length === 0) { 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 { } else {
// omit the raw and issuerCertificate fields // omit the raw and issuerCertificate fields
const { raw, issuerCertificate, ...certWithoutRaw } = cert; const { raw, issuerCertificate, ...certWithoutRaw } = cert;
resolve({ resolve(certWithoutRaw);
statusCode: 200,
body: JSON.stringify(certWithoutRaw),
});
} }
} }
}); });
req.on('error', error => { req.on('error', error => {
resolve(errorResponse(`Error fetching site certificate: ${error.message}`)); reject(new Error(`Error fetching site certificate: ${error.message}`));
}); });
req.end(); req.end();
@ -45,6 +30,8 @@ exports.handler = async function (event, context) {
return response; return response;
} catch (error) { } catch (error) {
return errorResponse(`Unexpected error occurred: ${error.message}`); throw new Error(error.message);
} }
}; };
exports.handler = middleware(fetchSiteCertificateHandler);

View File

@ -1,69 +1,30 @@
const Wappalyzer = require('wappalyzer'); const Wappalyzer = require('wappalyzer');
const middleware = require('./_common/middleware');
const analyze = async (url) => { const analyzeSiteTechnologies = async (url) => {
const options = {}; const options = {};
const wappalyzer = new Wappalyzer(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 { try {
return analyze(url).then( await wappalyzer.init();
(results) => { const headers = {};
if (!results.technologies || results.technologies.length === 0) { const storage = {
return { local: {},
statusCode: 200, session: {},
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 }),
}; };
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);

View File

@ -1,55 +1,31 @@
const traceroute = require('traceroute'); const traceroute = require('traceroute');
const url = require('url'); const url = require('url');
const middleware = require('./_common/middleware');
exports.handler = async function(event, context) { const executeTraceroute = async (urlString, context) => {
const urlString = (event.queryStringParameters || event.query).url; // Parse the URL and get the hostname
const urlObject = url.parse(urlString);
const host = urlObject.hostname;
try { if (!host) {
if (!urlString) { throw new Error('Invalid URL provided');
throw new Error('URL parameter is missing!'); }
}
// Parse the URL and get the hostname // Traceroute with callback
const urlObject = url.parse(urlString); const result = await new Promise((resolve, reject) => {
const host = urlObject.hostname; traceroute.trace(host, (err, hops) => {
if (err || !hops) {
if (!host) { reject(err || new Error('No hops found'));
throw new Error('Invalid URL provided'); } else {
} resolve(hops);
// 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'));
} }
}); });
});
return { return {
statusCode: 200, message: "Traceroute completed!",
body: JSON.stringify({ result,
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,
}),
};
}
}; };
exports.handler = middleware(executeTraceroute);

View File

@ -1,14 +1,6 @@
const net = require('net'); const net = require('net');
const psl = require('psl'); const psl = require('psl');
// const { URL } = require('url'); const middleware = require('./_common/middleware');
const errorResponse = (message, statusCode = 444) => {
return {
statusCode: statusCode,
body: JSON.stringify({ error: message }),
};
};
const getBaseDomain = (url) => { const getBaseDomain = (url) => {
let protocol = ''; let protocol = '';
@ -22,55 +14,7 @@ const getBaseDomain = (url) => {
return protocol + parsed.domain; 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) => { const parseWhoisData = (data) => {
if (data.includes('No match for')) { if (data.includes('No match for')) {
return { error: 'No matches found for domain in internic database'}; return { error: 'No matches found for domain in internic database'};
} }
@ -100,3 +44,41 @@ const parseWhoisData = (data) => {
return parsedData; 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);