Compare commits

..
Author SHA1 Message Date
Alicia Sykes c1daa4799c Adds gen har, network requests, meta tags 2023-07-30 02:16:08 +01:00
134 changed files with 1517 additions and 7126 deletions

No files matched your search

+120 -691
View File
File diff suppressed because it is too large. Load diff
-1
View File
@@ -1 +0,0 @@
![Screenshot](https://raw.githubusercontent.com/Lissy93/web-check/HEAD/.github/screenshots/web-check-screenshot3.png)
Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 207 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

File renamed without changes.
File renamed without changes.
Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

File renamed without changes.
File renamed without changes.
Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 810 KiB

-37
View File
@@ -1,37 +0,0 @@
# Inserts list of community members into ./README.md
name: 💓 Inserts Contributors & Sponsors
on:
workflow_dispatch: # Manual dispatch
schedule:
- cron: '45 1 * * 0' # At 01:45 on Sunday.
jobs:
# Job #1 - Fetches sponsors and inserts table into readme
insert-sponsors:
runs-on: ubuntu-latest
name: Inserts Sponsors 💓
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Updates readme with sponsors
uses: JamesIves/github-sponsors-readme-action@1.0.5
with:
token: ${{ secrets.BOT_TOKEN || secrets.GITHUB_TOKEN }}
file: .github/README.md
# Job #2 - Fetches contributors and inserts table into readme
insert-contributors:
runs-on: ubuntu-latest
name: Inserts Contributors 💓
steps:
- name: Updates readme with contributors
uses: akhilmhdh/contributors-readme-action@v2.3.4
env:
GITHUB_TOKEN: ${{ secrets.BOT_TOKEN || secrets.GITHUB_TOKEN }}
with:
image_size: 80
readme_path: .github/README.md
columns_per_row: 6
commit_message: 'docs: Updates contributors list'
committer_username: liss-bot
committer_email: liss-bot@d0h.co
+13 -12
View File
@@ -1,5 +1,5 @@
# keys # Keys
.env .env
# dependencies # dependencies
@@ -7,21 +7,22 @@
/.pnp /.pnp
.pnp.js .pnp.js
# logs
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# testing # testing
/coverage /coverage
# production # production
/build /build
# Random AWS and Netlify crap # misc
.netlify
.serverless
.webpack
# OS generated files
.DS_Store .DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Local Netlify folder
.netlify
+7 -17
View File
@@ -1,22 +1,12 @@
FROM node:16-buster-slim FROM node:16-buster-slim AS base
WORKDIR /app
FROM base AS builder
COPY . .
RUN apt-get update && \ RUN apt-get update && \
apt-get install -y chromium traceroute && \ apt-get install -y chromium traceroute && \
chmod 755 /usr/bin/chromium && \ chmod 755 /usr/bin/chromium && \
rm -rf /var/lib/apt/lists/* rm -rf /var/lib/apt/lists/*
RUN npm install --force
WORKDIR /app EXPOSE 8888
COPY package.json yarn.lock ./
RUN yarn install
COPY . .
RUN yarn build
EXPOSE ${PORT:-3000}
ENV CHROME_PATH='/usr/bin/chromium' ENV CHROME_PATH='/usr/bin/chromium'
CMD ["npm", "run", "serve"]
CMD ["yarn", "serve"]
-51
View File
@@ -1,51 +0,0 @@
const path = require('path');
const nodeExternals = require('webpack-node-externals');
module.exports = {
target: 'node',
mode: 'production',
entry: {
'carbon': './api/carbon.js',
'cookies': './api/cookies.js',
'dns-server': './api/dns-server.js',
'dns': './api/dns.js',
'dnssec': './api/dnssec.js',
'features': './api/features.js',
'get-ip': './api/get-ip.js',
'headers': './api/headers.js',
'hsts': './api/hsts.js',
'linked-pages': './api/linked-pages.js',
'mail-config': './api/mail-config.js',
'ports': './api/ports.js',
'quality': './api/quality.js',
'redirects': './api/redirects.js',
'robots-txt': './api/robots-txt.js',
'screenshot': './api/screenshot.js',
'security-txt': './api/security-txt.js',
'sitemap': './api/sitemap.js',
'social-tags': './api/social-tags.js',
'ssl': './api/ssl.js',
'status': './api/status.js',
'tech-stack': './api/tech-stack.js',
'trace-route': './api/trace-route.js',
'txt-records': './api/txt-records.js',
'whois': './api/whois.js',
},
externals: [nodeExternals()],
output: {
filename: '[name].js',
path: path.resolve(__dirname, '.webpack'),
libraryTarget: 'commonjs2'
},
module: {
rules: [
{
test: /\.js$/,
use: {
loader: 'babel-loader'
},
exclude: /node_modules/,
}
]
}
};
-38
View File
@@ -1,38 +0,0 @@
const normalizeUrl = (url) => {
return url.startsWith('http') ? url : `https://${url}`;
};
const commonMiddleware = (handler) => {
return async (event, context, callback) => {
const queryParams = event.queryStringParameters || event.query || {};
const rawUrl = queryParams.url;
if (!rawUrl) {
callback(null, {
statusCode: 500,
body: JSON.stringify({ error: 'No URL specified' }),
});
}
const url = normalizeUrl(rawUrl);
try {
const response = await handler(url, event, context);
if (response.body && response.statusCode) {
callback(null, response);
} else {
callback(null, {
statusCode: 200,
body: typeof response === 'object' ? JSON.stringify(response) : response,
});
}
} catch (error) {
callback(null, {
statusCode: 500,
body: JSON.stringify({ error: error.message }),
});
}
};
};
module.exports = commonMiddleware;
-83
View File
@@ -1,83 +0,0 @@
const axios = require('axios');
const middleware = require('./_common/middleware');
const convertTimestampToDate = (timestamp) => {
const [year, month, day, hour, minute, second] = [
timestamp.slice(0, 4),
timestamp.slice(4, 6) - 1,
timestamp.slice(6, 8),
timestamp.slice(8, 10),
timestamp.slice(10, 12),
timestamp.slice(12, 14),
].map(num => parseInt(num, 10));
return new Date(year, month, day, hour, minute, second);
}
const countPageChanges = (results) => {
let prevDigest = null;
return results.reduce((acc, curr) => {
if (curr[2] !== prevDigest) {
prevDigest = curr[2];
return acc + 1;
}
return acc;
}, -1);
}
const getAveragePageSize = (scans) => {
const totalSize = scans.map(scan => parseInt(scan[3], 10)).reduce((sum, size) => sum + size, 0);
return Math.round(totalSize / scans.length);
};
const getScanFrequency = (firstScan, lastScan, totalScans, changeCount) => {
const formatToTwoDecimal = num => parseFloat(num.toFixed(2));
const dayFactor = (lastScan - firstScan) / (1000 * 60 * 60 * 24);
const daysBetweenScans = formatToTwoDecimal(dayFactor / totalScans);
const daysBetweenChanges = formatToTwoDecimal(dayFactor / changeCount);
const scansPerDay = formatToTwoDecimal((totalScans - 1) / dayFactor);
const changesPerDay = formatToTwoDecimal(changeCount / dayFactor);
return {
daysBetweenScans,
daysBetweenChanges,
scansPerDay,
changesPerDay,
};
};
const getWaybackData = async (url) => {
const cdxUrl = `https://web.archive.org/cdx/search/cdx?url=${url}&output=json&fl=timestamp,statuscode,digest,length,offset`;
try {
const { data } = await axios.get(cdxUrl);
// Check there's data
if (!data || !Array.isArray(data) || data.length <= 1) {
return { skipped: 'Site has never before been archived via the Wayback Machine' };
}
// Remove the header row
data.shift();
// Process and return the results
const firstScan = convertTimestampToDate(data[0][0]);
const lastScan = convertTimestampToDate(data[data.length - 1][0]);
const totalScans = data.length;
const changeCount = countPageChanges(data);
return {
firstScan,
lastScan,
totalScans,
changeCount,
averagePageSize: getAveragePageSize(data),
scanFrequency: getScanFrequency(firstScan, lastScan, totalScans, changeCount),
scans: data,
scanUrl: url,
};
} catch (err) {
return { error: `Error fetching Wayback data: ${err.message}` };
}
};
exports.handler = middleware(getWaybackData);
-105
View File
@@ -1,105 +0,0 @@
const dns = require('dns');
const { URL } = require('url');
const middleware = require('./_common/middleware');
const DNS_SERVERS = [
{ name: 'AdGuard', ip: '176.103.130.130' },
{ name: 'AdGuard Family', ip: '176.103.130.132' },
{ name: 'CleanBrowsing Adult', ip: '185.228.168.10' },
{ name: 'CleanBrowsing Family', ip: '185.228.168.168' },
{ name: 'CleanBrowsing Security', ip: '185.228.168.9' },
{ name: 'CloudFlare', ip: '1.1.1.1' },
{ name: 'CloudFlare Family', ip: '1.1.1.3' },
{ name: 'Comodo Secure', ip: '8.26.56.26' },
{ name: 'Google DNS', ip: '8.8.8.8' },
{ name: 'Neustar Family', ip: '156.154.70.3' },
{ name: 'Neustar Protection', ip: '156.154.70.2' },
{ name: 'Norton Family', ip: '199.85.126.20' },
{ name: 'OpenDNS', ip: '208.67.222.222' },
{ name: 'OpenDNS Family', ip: '208.67.222.123' },
{ name: 'Quad9', ip: '9.9.9.9' },
{ name: 'Yandex Family', ip: '77.88.8.7' },
{ name: 'Yandex Safe', ip: '77.88.8.88' },
];
const knownBlockIPs = [
'146.112.61.106', // OpenDNS
'185.228.168.10', // CleanBrowsing
'8.26.56.26', // Comodo
'9.9.9.9', // Quad9
'208.69.38.170', // Some OpenDNS IPs
'208.69.39.170', // Some OpenDNS IPs
'208.67.222.222', // OpenDNS
'208.67.222.123', // OpenDNS FamilyShield
'199.85.126.10', // Norton
'199.85.126.20', // Norton Family
'156.154.70.22', // Neustar
'77.88.8.7', // Yandex
'77.88.8.8', // Yandex
'::1', // Localhost IPv6
'2a02:6b8::feed:0ff', // Yandex DNS
'2a02:6b8::feed:bad', // Yandex Safe
'2a02:6b8::feed:a11', // Yandex Family
'2620:119:35::35', // OpenDNS
'2620:119:53::53', // OpenDNS FamilyShield
'2606:4700:4700::1111', // Cloudflare
'2606:4700:4700::1001', // Cloudflare
'2001:4860:4860::8888', // Google DNS
'2a0d:2a00:1::', // AdGuard
'2a0d:2a00:2::' // AdGuard Family
];
const isDomainBlocked = async (domain, serverIP) => {
return new Promise((resolve) => {
dns.resolve4(domain, { server: serverIP }, (err, addresses) => {
if (!err) {
if (addresses.some(addr => knownBlockIPs.includes(addr))) {
resolve(true);
return;
}
resolve(false);
return;
}
dns.resolve6(domain, { server: serverIP }, (err6, addresses6) => {
if (!err6) {
if (addresses6.some(addr => knownBlockIPs.includes(addr))) {
resolve(true);
return;
}
resolve(false);
return;
}
if (err6.code === 'ENOTFOUND' || err6.code === 'SERVFAIL') {
resolve(true);
} else {
resolve(false);
}
});
});
});
};
const checkDomainAgainstDnsServers = async (domain) => {
let results = [];
for (let server of DNS_SERVERS) {
const isBlocked = await isDomainBlocked(domain, server.ip);
results.push({
server: server.name,
serverIp: server.ip,
isBlocked,
});
}
return results;
};
exports.handler = middleware(async (url) => {
const domain = new URL(url).hostname;
const results = await checkDomainAgainstDnsServers(domain);
return {
statusCode: 200,
body: JSON.stringify({ blocklists: results })
};
});
+11 -5
View File
@@ -1,7 +1,8 @@
const https = require('https'); const https = require('https');
const middleware = require('./_common/middleware');
exports.handler = middleware(async (url, event, context) => { exports.handler = async function(event, context) {
const siteURL = event.queryStringParameters.url;
const errorResponse = (message, statusCode = 500) => { const errorResponse = (message, statusCode = 500) => {
return { return {
statusCode: statusCode, statusCode: statusCode,
@@ -15,9 +16,15 @@ exports.handler = middleware(async (url, 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(url, res => { const req = https.request(siteURL, res => {
const headers = res.headers; const headers = res.headers;
const hstsHeader = headers['strict-transport-security']; const hstsHeader = headers['strict-transport-security'];
@@ -53,5 +60,4 @@ exports.handler = middleware(async (url, event, context) => {
req.end(); req.end();
}); });
}); };
+7 -6
View File
@@ -1,5 +1,4 @@
const net = require('net'); const net = require('net');
const middleware = require('./_common/middleware');
// A list of commonly used ports. // A list of commonly used ports.
const PORTS = [ const PORTS = [
@@ -13,7 +12,7 @@ async function checkPort(port, domain) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const socket = new net.Socket(); const socket = new net.Socket();
socket.setTimeout(1500); socket.setTimeout(1500); // you may want to adjust the timeout
socket.once('connect', () => { socket.once('connect', () => {
socket.destroy(); socket.destroy();
@@ -34,8 +33,12 @@ async function checkPort(port, domain) {
}); });
} }
const handler = async (url, event, context) => { exports.handler = async (event, context) => {
const domain = url.replace(/(^\w+:|^)\/\//, ''); const domain = event.queryStringParameters.url;
if (!domain) {
return errorResponse('Missing domain parameter.');
}
const delay = ms => new Promise(res => setTimeout(res, ms)); const delay = ms => new Promise(res => setTimeout(res, ms));
const timeout = delay(9000); const timeout = delay(9000);
@@ -85,5 +88,3 @@ const errorResponse = (message, statusCode = 444) => {
body: JSON.stringify({ error: message }), body: JSON.stringify({ error: message }),
}; };
}; };
exports.handler = middleware(handler);
+60
View File
@@ -0,0 +1,60 @@
const axios = require('axios');
const cheerio = require('cheerio');
const urlLib = require('url');
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();
$('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);
}
});
// 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]);
if (internalLinks.length === 0 && externalLinks.length === 0) {
return {
statusCode: 400,
body: JSON.stringify({
skipped: 'No internal or external links found. '
+ 'This may be due to the website being dynamically rendered, using a client-side framework (like React), and without SSR enabled. '
+ 'That would mean that the static HTML returned from the HTTP request doesn\'t contain any meaningful content for Web-Check to analyze. '
+ 'You can rectify this by using a headless browser to render the page instead.',
}),
};
}
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' }),
};
}
};
-57
View File
@@ -1,57 +0,0 @@
const axios = require('axios');
const puppeteer = require('puppeteer');
const middleware = require('./_common/middleware');
const getPuppeteerCookies = async (url) => {
const browser = await puppeteer.launch({
headless: 'new',
args: ['--no-sandbox', '--disable-setuid-sandbox'],
});
try {
const page = await browser.newPage();
const navigationPromise = page.goto(url, { waitUntil: 'networkidle2' });
const timeoutPromise = new Promise((_, reject) =>
setTimeout(() => reject(new Error('Puppeteer took too long!')), 3000)
);
await Promise.race([navigationPromise, timeoutPromise]);
return await page.cookies();
} finally {
await browser.close();
}
};
const handler = async (url) => {
let headerCookies = null;
let clientCookies = null;
try {
const response = await axios.get(url, {
withCredentials: true,
maxRedirects: 5,
});
headerCookies = response.headers['set-cookie'];
} catch (error) {
if (error.response) {
return { error: `Request failed with status ${error.response.status}: ${error.message}` };
} else if (error.request) {
return { error: `No response received: ${error.message}` };
} else {
return { error: `Error setting up request: ${error.message}` };
}
}
try {
clientCookies = await getPuppeteerCookies(url);
} catch (_) {
clientCookies = null;
}
if (!headerCookies && (!clientCookies || clientCookies.length === 0)) {
return { skipped: 'No cookies' };
}
return { headerCookies, clientCookies };
};
exports.handler = middleware(handler);
+23 -6
View File
@@ -1,7 +1,16 @@
const https = require('https'); const https = require('https');
const commonMiddleware = require('./_common/middleware'); // Make sure this path is correct
const fetchDNSRecords = async (domain, event, context) => { exports.handler = async function(event, context) {
let { url } = event.queryStringParameters;
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 = {};
@@ -39,14 +48,22 @@ const fetchDNSRecords = async (domain, 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) {
throw new Error(`Error fetching ${type} record: ${error.message}`); // This will be caught and handled by the commonMiddleware return errorResponse(`Error fetching ${type} record: ${error.message}`);
} }
} }
return records; return {
statusCode: 200,
body: JSON.stringify(records),
};
}; };
exports.handler = commonMiddleware(fetchDNSRecords); const errorResponse = (message, statusCode = 444) => {
return {
statusCode: statusCode,
body: JSON.stringify({ error: message }),
};
};
+15 -11
View File
@@ -1,11 +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');
const handler = async (url) => { exports.handler = async (event) => {
const domain = event.queryStringParameters.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);
@@ -22,7 +22,6 @@ const handler = async (url) => {
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,15 +29,20 @@ const handler = async (url) => {
// } catch (error) { // } catch (error) {
// console.error(error); // console.error(error);
// } // }
return { return {
domain, statusCode: 200,
dns: results, body: JSON.stringify({
// dohMozillaSupport, domain,
dns: results,
// dohMozillaSupport,
}),
}; };
} catch (error) { } catch (error) {
throw new Error(`An error occurred while resolving DNS. ${error.message}`); // This will be caught and handled by the commonMiddleware return {
statusCode: 500,
body: JSON.stringify({
error: `An error occurred while resolving DNS. ${error.message}`,
}),
};
} }
}; };
exports.handler = commonMiddleware(handler);
+33
View File
@@ -0,0 +1,33 @@
const dns = require('dns');
/* Lambda function to fetch the IP address of a given URL */
exports.handler = function (event, context, callback) {
const addressParam = event.queryStringParameters.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 errorResponse = (message, statusCode = 444) => {
return {
statusCode: statusCode,
body: JSON.stringify({ error: message }),
};
};
-105
View File
@@ -1,105 +0,0 @@
const axios = require('axios');
const middleware = require('./_common/middleware');
const hasWaf = (waf) => {
return {
hasWaf: true, waf,
}
};
const handler = async (url) => {
const fullUrl = url.startsWith('http') ? url : `http://${url}`;
try {
const response = await axios.get(fullUrl);
const headers = response.headers;
if (headers['server'] && headers['server'].includes('cloudflare')) {
return hasWaf('Cloudflare');
}
if (headers['x-powered-by'] && headers['x-powered-by'].includes('AWS Lambda')) {
return hasWaf('AWS WAF');
}
if (headers['server'] && headers['server'].includes('AkamaiGHost')) {
return hasWaf('Akamai');
}
if (headers['server'] && headers['server'].includes('Sucuri')) {
return hasWaf('Sucuri');
}
if (headers['server'] && headers['server'].includes('BarracudaWAF')) {
return hasWaf('Barracuda WAF');
}
if (headers['server'] && (headers['server'].includes('F5 BIG-IP') || headers['server'].includes('BIG-IP'))) {
return hasWaf('F5 BIG-IP');
}
if (headers['x-sucuri-id'] || headers['x-sucuri-cache']) {
return hasWaf('Sucuri CloudProxy WAF');
}
if (headers['server'] && headers['server'].includes('FortiWeb')) {
return hasWaf('Fortinet FortiWeb WAF');
}
if (headers['server'] && headers['server'].includes('Imperva')) {
return hasWaf('Imperva SecureSphere WAF');
}
if (headers['x-protected-by'] && headers['x-protected-by'].includes('Sqreen')) {
return hasWaf('Sqreen');
}
if (headers['x-waf-event-info']) {
return hasWaf('Reblaze WAF');
}
if (headers['set-cookie'] && headers['set-cookie'].includes('_citrix_ns_id')) {
return hasWaf('Citrix NetScaler');
}
if (headers['x-denied-reason'] || headers['x-wzws-requested-method']) {
return hasWaf('WangZhanBao WAF');
}
if (headers['x-webcoment']) {
return hasWaf('Webcoment Firewall');
}
if (headers['server'] && headers['server'].includes('Yundun')) {
return hasWaf('Yundun WAF');
}
if (headers['x-yd-waf-info'] || headers['x-yd-info']) {
return hasWaf('Yundun WAF');
}
if (headers['server'] && headers['server'].includes('Safe3WAF')) {
return hasWaf('Safe3 Web Application Firewall');
}
if (headers['server'] && headers['server'].includes('NAXSI')) {
return hasWaf('NAXSI WAF');
}
if (headers['x-datapower-transactionid']) {
return hasWaf('IBM WebSphere DataPower');
}
return {
hasWaf: false,
}
} catch (error) {
return {
statusCode: 500,
body: JSON.stringify({ error: error.message }),
};
}
};
exports.handler = middleware(handler);
+35
View File
@@ -0,0 +1,35 @@
exports.handler = async (event) => {
const { url } = event.queryStringParameters;
const redirects = [url];
try {
const got = await import('got');
await got.default(url, {
followRedirect: true,
maxRedirects: 12,
hooks: {
beforeRedirect: [
(options, response) => {
redirects.push(response.headers.location);
},
],
},
});
return {
statusCode: 200,
body: JSON.stringify({
redirects: redirects,
}),
};
} catch (error) {
return errorResponse(`Error: ${error.message}`);
}
};
const errorResponse = (message, statusCode = 444) => {
return {
statusCode: statusCode,
body: JSON.stringify({ error: message }),
};
};
+54
View File
@@ -0,0 +1,54 @@
const puppeteer = require('puppeteer-core');
const chromium = require('chrome-aws-lambda');
exports.handler = async (event, context) => {
let browser = null;
let result = null;
let code = 200;
try {
const url = event.queryStringParameters.url;
browser = await chromium.puppeteer.launch({
args: chromium.args,
defaultViewport: chromium.defaultViewport,
executablePath: await chromium.executablePath,
headless: chromium.headless,
});
const page = await browser.newPage();
const requests = [];
// Capture requests
page.on('request', request => {
requests.push({
url: request.url(),
method: request.method(),
headers: request.headers(),
});
});
await page.goto(url, {
waitUntil: 'networkidle0', // wait until all requests are finished
});
result = requests;
} catch (error) {
code = 500;
result = {
error: 'Failed to create HAR file',
details: error.toString(),
};
} finally {
if (browser !== null) {
await browser.close();
}
}
return {
statusCode: code,
body: JSON.stringify(result),
};
};
+17 -6
View File
@@ -1,7 +1,14 @@
const https = require('https'); const https = require('https');
const middleware = require('./_common/middleware');
const handler = async (url) => { exports.handler = async (event, context) => {
const { url } = event.queryStringParameters;
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,10 +49,14 @@ const handler = async (url) => {
} }
carbonData.scanUrl = url; carbonData.scanUrl = url;
return carbonData; return {
statusCode: 200,
body: JSON.stringify(carbonData),
};
} catch (error) { } catch (error) {
throw new Error(`Error: ${error.message}`); return {
statusCode: 500,
body: JSON.stringify({ error: `Error: ${error.message}` }),
};
} }
}; };
exports.handler = middleware(handler);
+26
View File
@@ -0,0 +1,26 @@
const axios = require('axios');
exports.handler = async function(event, context) {
const { url } = event.queryStringParameters;
if (!url) {
return {
statusCode: 400,
body: JSON.stringify({ message: 'url query string parameter is required' }),
};
}
try {
const response = await axios.get(url, {withCredentials: true});
const cookies = response.headers['set-cookie'];
return {
statusCode: 200,
body: JSON.stringify({ cookies }),
};
} catch (error) {
return {
statusCode: 500,
body: JSON.stringify({ error: error.message }),
};
}
};
+20 -15
View File
@@ -1,9 +1,8 @@
const dns = require('dns'); const dns = require('dns');
const util = require('util'); const util = require('util');
const middleware = require('./_common/middleware');
const handler = async (url) => { exports.handler = async function(event, context) {
let hostname = url; let hostname = event.queryStringParameters.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://')) {
@@ -36,19 +35,25 @@ const handler = async (url) => {
]); ]);
return { return {
A: a, statusCode: 200,
AAAA: aaaa, body: JSON.stringify({
MX: mx, A: a,
TXT: txt, AAAA: aaaa,
NS: ns, MX: mx,
CNAME: cname, TXT: txt,
SOA: soa, NS: ns,
SRV: srv, CNAME: cname,
PTR: ptr SOA: soa,
SRV: srv,
PTR: ptr
})
}; };
} catch (error) { } catch (error) {
throw new Error(error.message); return {
statusCode: 500,
body: JSON.stringify({
error: error.message
})
};
} }
}; };
exports.handler = middleware(handler);
+31
View File
@@ -0,0 +1,31 @@
const axios = require('axios');
exports.handler = async function(event, context) {
const { url } = event.queryStringParameters;
if (!url) {
return {
statusCode: 400,
body: JSON.stringify({ error: 'url query string parameter is required' }),
};
}
try {
const response = await axios.get(url, {
validateStatus: function (status) {
return status >= 200 && status < 600; // Resolve only if the status code is less than 600
},
});
return {
statusCode: 200,
body: JSON.stringify(response.headers),
};
} catch (error) {
console.log(error);
return {
statusCode: 500,
body: JSON.stringify({ error: error.message }),
};
}
};
-21
View File
@@ -1,21 +0,0 @@
const dns = require('dns');
const middleware = require('./_common/middleware');
const lookupAsync = (address) => {
return new Promise((resolve, reject) => {
dns.lookup(address, (err, ip, family) => {
if (err) {
reject(err);
} else {
resolve({ ip, family });
}
});
});
};
const handler = async (url) => {
const address = url.replaceAll('https://', '').replaceAll('http://', '');
return await lookupAsync(address);
};
exports.handler = middleware(handler);
+12 -14
View File
@@ -1,11 +1,9 @@
const dns = require('dns').promises; const dns = require('dns').promises;
const middleware = require('./_common/middleware');
const handler = async (url, event, context) => { exports.handler = async (event) => {
const url = new URL(event.queryStringParameters.url);
try { try {
const parsedUrl = new URL(url); const txtRecords = await dns.resolveTxt(url.hostname);
const txtRecords = await dns.resolveTxt(parsedUrl.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) => {
@@ -18,15 +16,15 @@ const handler = async (url, event, context) => {
return { ...acc, ...recordObject }; return { ...acc, ...recordObject };
}, {}); }, {});
return readableTxtRecords; return {
statusCode: 200,
body: JSON.stringify(readableTxtRecords),
};
} catch (error) { } catch (error) {
if (error.code === 'ERR_INVALID_URL') { console.error('Error:', error);
throw new Error(`Invalid URL ${error}`); return {
} else { statusCode: 500,
throw error; body: JSON.stringify({ error: error.message }),
} };
} }
}; };
exports.handler = middleware(handler);
-18
View File
@@ -1,18 +0,0 @@
const axios = require('axios');
const middleware = require('./_common/middleware');
const handler = async (url, event, context) => {
try {
const response = await axios.get(url, {
validateStatus: function (status) {
return status >= 200 && status < 600; // Resolve only if the status code is less than 600
},
});
return response.headers;
} catch (error) {
throw new Error(error.message);
}
};
exports.handler = middleware(handler);
-25
View File
@@ -1,25 +0,0 @@
const axios = require('axios');
const middleware = require('./_common/middleware');
const handler = async (url) => {
const fullUrl = url.startsWith('http') ? url : `http://${url}`;
try {
const response = await axios.get(fullUrl);
const headers = response.headers;
return {
strictTransportPolicy: headers['strict-transport-policy'] ? true : false,
xFrameOptions: headers['x-frame-options'] ? true : false,
xContentTypeOptions: headers['x-content-type-options'] ? true : false,
xXSSProtection: headers['x-xss-protection'] ? true : false,
contentSecurityPolicy: headers['content-security-policy'] ? true : false,
}
} catch (error) {
return {
statusCode: 500,
body: JSON.stringify({ error: error.message }),
};
}
};
exports.handler = middleware(handler);
-70
View File
@@ -1,70 +0,0 @@
const axios = require('axios');
const unzipper = require('unzipper');
const csv = require('csv-parser');
const fs = require('fs');
const middleware = require('./_common/middleware');
// Should also work with the following sources:
// https://www.domcop.com/files/top/top10milliondomains.csv.zip
// https://tranco-list.eu/top-1m.csv.zip
// https://www.domcop.com/files/top/top10milliondomains.csv.zip
// https://radar.cloudflare.com/charts/LargerTopDomainsTable/attachment?id=525&top=1000000
// https://statvoo.com/dl/top-1million-sites.csv.zip
const FILE_URL = 'https://s3-us-west-1.amazonaws.com/umbrella-static/top-1m.csv.zip';
const TEMP_FILE_PATH = '/tmp/top-1m.csv';
const handler = async (url) => {
let domain = null;
try {
domain = new URL(url).hostname;
} catch (e) {
throw new Error('Invalid URL');
}
// Download and unzip the file if not in cache
if (!fs.existsSync(TEMP_FILE_PATH)) {
const response = await axios({
method: 'GET',
url: FILE_URL,
responseType: 'stream'
});
await new Promise((resolve, reject) => {
response.data
.pipe(unzipper.Extract({ path: '/tmp' }))
.on('close', resolve)
.on('error', reject);
});
}
// Parse the CSV and find the rank
return new Promise((resolve, reject) => {
const csvStream = fs.createReadStream(TEMP_FILE_PATH)
.pipe(csv({
headers: ['rank', 'domain'],
}))
.on('data', (row) => {
if (row.domain === domain) {
csvStream.destroy();
resolve({
domain: domain,
rank: row.rank,
isFound: true,
});
}
})
.on('end', () => {
resolve({
skipped: `Skipping, as ${domain} is not present in the Umbrella top 1M list.`,
domain: domain,
isFound: false,
});
})
.on('error', reject);
});
};
exports.handler = middleware(handler);
+40
View File
@@ -0,0 +1,40 @@
const axios = require('axios');
exports.handler = function(event, context, callback) {
const { url } = event.queryStringParameters;
if (!url) {
callback(null, {
statusCode: 400,
body: JSON.stringify({ error: 'URL param is required'}),
});
}
const apiKey = process.env.GOOGLE_CLOUD_API_KEY;
if (!apiKey) {
callback(null, {
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}`;
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'}),
});
}
);
};
-48
View File
@@ -1,48 +0,0 @@
const axios = require('axios');
const cheerio = require('cheerio');
const urlLib = require('url');
const commonMiddleware = require('./_common/middleware');
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();
// 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);
}
});
// 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]);
// If there were no links, then mark as skipped and show reasons
if (internalLinks.length === 0 && externalLinks.length === 0) {
return {
statusCode: 400,
body: JSON.stringify({
skipped: 'No internal or external links found. '
+ 'This may be due to the website being dynamically rendered, using a client-side framework (like React), and without SSR enabled. '
+ 'That would mean that the static HTML returned from the HTTP request doesn\'t contain any meaningful content for Web-Check to analyze. '
+ 'You can rectify this by using a headless browser to render the page instead.',
}),
};
}
return { internal: internalLinks, external: externalLinks };
};
exports.handler = commonMiddleware(handler);
+12 -8
View File
@@ -1,11 +1,11 @@
const commonMiddleware = require('./_common/middleware');
const dns = require('dns').promises; const dns = require('dns').promises;
const URL = require('url-parse'); const URL = require('url-parse');
const handler = async (url, event, context) => { exports.handler = async (event, context) => {
try { try {
const domain = new URL(url).hostname || new URL(url).pathname; let domain = event.queryStringParameters.url;
const parsedUrl = new URL(domain);
domain = parsedUrl.hostname || parsedUrl.pathname;
// Get MX records // Get MX records
const mxRecords = await dns.resolveMx(domain); const mxRecords = await dns.resolveMx(domain);
@@ -56,13 +56,19 @@ const handler = async (url, event, context) => {
} }
return { return {
statusCode: 200,
body: JSON.stringify({
mxRecords, mxRecords,
txtRecords: emailTxtRecords, txtRecords: emailTxtRecords,
mailServices, mailServices,
}; }),
};
} catch (error) { } catch (error) {
if (error.code === 'ENOTFOUND' || error.code === 'ENODATA') { if (error.code === 'ENOTFOUND' || error.code === 'ENODATA') {
return { skipped: 'No mail server in use on this domain' }; return {
statusCode: 200,
body: JSON.stringify({ skipped: 'No mail server in use on this domain' }),
};
} else { } else {
return { return {
statusCode: 500, statusCode: 500,
@@ -71,5 +77,3 @@ const handler = async (url, event, context) => {
} }
} }
}; };
module.exports.handler = commonMiddleware(handler);
+58
View File
@@ -0,0 +1,58 @@
const axios = require('axios');
const cheerio = require('cheerio');
exports.handler = async (event) => {
let url;
try {
// Add https:// prefix if not present
url = new URL(event.queryStringParameters.url);
if (!url.protocol) {
url = new URL('https://' + event.queryStringParameters.url);
}
} catch (error) {
// Return error if URL is not valid
return {
statusCode: 400,
body: JSON.stringify({
error: 'Invalid URL provided.',
}),
};
}
try {
// Fetch the page
const response = await axios.get(url.toString());
// Parse the page body with cheerio
const $ = cheerio.load(response.data);
// Extract meta tags
const metaTags = {};
$('head meta').each((index, element) => {
const name = $(element).attr('name');
const property = $(element).attr('property');
const content = $(element).attr('content');
if (name) {
metaTags[name] = content;
} else if (property) {
metaTags[property] = content;
}
});
// Return meta tags
return {
statusCode: 200,
body: JSON.stringify(metaTags),
};
} catch (error) {
// Return error if there's a problem fetching or parsing the page
return {
statusCode: 500,
body: JSON.stringify({
error: error.message,
}),
};
}
};
+58
View File
@@ -0,0 +1,58 @@
const puppeteer = require('puppeteer-core');
const chromium = require('chrome-aws-lambda');
exports.handler = async (event, context) => {
const urlParam = event.queryStringParameters.url;
if (!urlParam) {
return {
statusCode: 400,
body: JSON.stringify({ error: 'Missing url parameter' })
};
}
let url;
try {
url = new URL(urlParam.includes('://') ? urlParam : 'https://' + urlParam);
} catch (error) {
return {
statusCode: 500,
body: JSON.stringify({ error: 'Invalid URL format' }),
};
}
// Launch the browser and open a new page
const browser = await puppeteer.launch({
args: chromium.args,
defaultViewport: { width: 800, height: 600 },
executablePath: process.env.CHROME_PATH || await chromium.executablePath,
headless: chromium.headless,
ignoreHTTPSErrors: true,
ignoreDefaultArgs: ['--disable-extensions'],
});
const page = await browser.newPage();
// To store network activity
let networkActivity = [];
// Register an event listener for network requests
page.on('request', (request) => {
networkActivity.push({
url: request.url(),
method: request.method(),
headers: request.headers(),
postData: request.postData(),
});
});
// Navigate to the page and wait for it to load
await page.goto(url, { waitUntil: 'networkidle2' });
// Close the browser
await browser.close();
// Return network activity
return {
statusCode: 200,
body: JSON.stringify(networkActivity),
};
};
-22
View File
@@ -1,22 +0,0 @@
const axios = require('axios');
const middleware = require('./_common/middleware');
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) {
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);
return response.data;
};
exports.handler = middleware(handler);
-24
View File
@@ -1,24 +0,0 @@
const axios = require('axios');
const middleware = require('./_common/middleware');
const handler = async (url) => {
const domain = url ? new URL(url).hostname : null;
if (!domain) throw new Error('Invalid URL');
try {
const auth = process.env.TRANCO_API_KEY ? // Auth is optional.
{ auth: { username: process.env.TRANCO_USERNAME, password: process.env.TRANCO_API_KEY } }
: {};
const response = await axios.get(
`https://tranco-list.eu/api/ranks/domain/${domain}`, { timeout: 2000 }, auth,
);
if (!response.data || !response.data.ranks || response.data.ranks.length === 0) {
return { skipped: `Skipping, as ${domain} isn't ranked in the top 100 million sites yet.`};
}
return response.data;
} catch (error) {
return { error: `Unable to fetch rank, ${error.message}` };
}
};
exports.handler = middleware(handler);
+45
View File
@@ -0,0 +1,45 @@
const axios = require('axios');
exports.handler = async function(event, context) {
const siteURL = event.queryStringParameters.url;
if (!siteURL) {
return {
statusCode: 400,
body: JSON.stringify({ error: 'Missing url query parameter' }),
};
}
let parsedURL;
try {
parsedURL = new URL(siteURL);
} catch (error) {
return {
statusCode: 400,
body: JSON.stringify({ error: 'Invalid url query parameter' }),
};
}
const robotsURL = `${parsedURL.protocol}//${parsedURL.hostname}/robots.txt`;
try {
const response = await axios.get(robotsURL);
if (response.status === 200) {
return {
statusCode: 200,
body: response.data,
};
} else {
return {
statusCode: response.status,
body: JSON.stringify({ error: 'Failed to fetch robots.txt', statusCode: response.status }),
};
}
} catch (error) {
return {
statusCode: 500,
body: JSON.stringify({ error: `Error fetching robots.txt: ${error.message}` }),
};
}
};
-27
View File
@@ -1,27 +0,0 @@
const handler = async (url) => {
const redirects = [url];
const got = await import('got');
try {
await got.default(url, {
followRedirect: true,
maxRedirects: 12,
hooks: {
beforeRedirect: [
(options, response) => {
redirects.push(response.headers.location);
},
],
},
});
return {
redirects: redirects,
};
} catch (error) {
throw new Error(`Error: ${error.message}`);
}
};
const middleware = require('./_common/middleware');
exports.handler = middleware(handler);
-70
View File
@@ -1,70 +0,0 @@
const axios = require('axios');
const middleware = require('./_common/middleware');
const parseRobotsTxt = (content) => {
const lines = content.split('\n');
const rules = [];
lines.forEach(line => {
line = line.trim(); // This removes trailing and leading whitespaces
let match = line.match(/^(Allow|Disallow):\s*(\S*)$/i);
if (match) {
const rule = {
lbl: match[1],
val: match[2],
};
rules.push(rule);
} else {
match = line.match(/^(User-agent):\s*(\S*)$/i);
if (match) {
const rule = {
lbl: match[1],
val: match[2],
};
rules.push(rule);
}
}
});
return { robots: rules };
}
const handler = async function(url) {
let parsedURL;
try {
parsedURL = new URL(url);
} catch (error) {
return {
statusCode: 400,
body: JSON.stringify({ error: 'Invalid url query parameter' }),
};
}
const robotsURL = `${parsedURL.protocol}//${parsedURL.hostname}/robots.txt`;
try {
const response = await axios.get(robotsURL);
if (response.status === 200) {
const parsedData = parseRobotsTxt(response.data);
if (!parsedData.robots || parsedData.robots.length === 0) {
return { skipped: 'No robots.txt file present, unable to continue' };
}
return parsedData;
} else {
return {
statusCode: response.status,
body: JSON.stringify({ error: 'Failed to fetch robots.txt', statusCode: response.status }),
};
}
} catch (error) {
return {
statusCode: 500,
body: JSON.stringify({ error: `Error fetching robots.txt: ${error.message}` }),
};
}
};
exports.handler = middleware(handler);
+27 -8
View File
@@ -1,11 +1,16 @@
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');
const screenshotHandler = async (targetUrl) => { exports.handler = async (event, context, callback) => {
let browser = null;
let targetUrl = event.queryStringParameters.url;
if (!targetUrl) { if (!targetUrl) {
throw new Error('URL is missing from queryStringParameters'); callback(null, {
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://')) {
@@ -15,10 +20,13 @@ const screenshotHandler = async (targetUrl) => {
try { try {
new URL(targetUrl); new URL(targetUrl);
} catch (error) { } catch (error) {
throw new Error('URL provided is invalid'); callback(null, {
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,
@@ -32,7 +40,9 @@ const screenshotHandler = async (targetUrl) => {
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(() => {
@@ -47,15 +57,24 @@ const screenshotHandler = async (targetUrl) => {
}); });
const screenshotBuffer = await page.screenshot(); const screenshotBuffer = await page.screenshot();
const base64Screenshot = screenshotBuffer.toString('base64'); const base64Screenshot = screenshotBuffer.toString('base64');
return { image: base64Screenshot }; const response = {
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);
+32 -13
View File
@@ -1,6 +1,5 @@
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',
@@ -38,39 +37,59 @@ const isPgpSigned = (result) => {
return false; return false;
}; };
const securityTxtHandler = async (urlParam) => { exports.handler = async (event, context) => {
const urlParam = event.queryStringParameters.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) {
throw new Error('Invalid URL format'); return {
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 { isPresent: false }; if (result && result.includes('<html')) return {
statusCode: 200,
body: JSON.stringify({ isPresent: false }),
};
if (result) { if (result) {
return { return {
isPresent: true, statusCode: 200,
foundIn: path, body: JSON.stringify({
content: result, isPresent: true,
isPgpSigned: isPgpSigned(result), foundIn: path,
fields: parseResult(result), content: result,
isPgpSigned: isPgpSigned(result),
fields: parseResult(result),
}),
}; };
} }
} catch (error) { } catch (error) {
throw new Error(error.message); return {
statusCode: 500,
body: JSON.stringify({ error: error.message }),
};
} }
} }
return { isPresent: false }; return {
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);
+19 -8
View File
@@ -1,10 +1,14 @@
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');
const checkURLHandler = async (url) => { exports.handler = async function(event, context) {
const { url } = event.queryStringParameters;
if (!url) { if (!url) {
throw new Error('You must provide a URL query parameter!'); return {
statusCode: 400,
body: JSON.stringify({ error: 'You must provide a URL query parameter!' }),
};
} }
let dnsLookupTime; let dnsLookupTime;
@@ -39,7 +43,10 @@ const checkURLHandler = async (url) => {
}); });
if (responseCode < 200 || responseCode >= 400) { if (responseCode < 200 || responseCode >= 400) {
throw new Error(`Received non-success response code: ${responseCode}`); return {
statusCode: 200,
body: JSON.stringify({ error: `Received non-success response code: ${responseCode}` }),
};
} }
performance.mark('B'); performance.mark('B');
@@ -47,12 +54,16 @@ const checkURLHandler = async (url) => {
let responseTime = performance.now() - startTime; let responseTime = performance.now() - startTime;
obs.disconnect(); obs.disconnect();
return { isUp: true, dnsLookupTime, responseTime, responseCode }; return {
statusCode: 200,
body: JSON.stringify({ isUp: true, dnsLookupTime, responseTime, responseCode }),
};
} catch (error) { } catch (error) {
obs.disconnect(); obs.disconnect();
throw error; return {
statusCode: 200,
body: JSON.stringify({ error: `Error during operation: ${error.message}` }),
};
} }
}; };
exports.handler = middleware(checkURLHandler);
+16 -8
View File
@@ -1,15 +1,22 @@
const https = require('https'); const https = require('https');
const middleware = require('./_common/middleware');
const builtWithHandler = async (url) => { exports.handler = async function (event, context) {
const { url } = event.queryStringParameters;
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) {
throw new Error('URL query parameter is required'); return errorResponse('URL query parameter is required', 400);
} }
if (!apiKey) { if (!apiKey) {
throw new Error('Missing BuiltWith API key in environment variables'); return errorResponse('Missing BuiltWith API key in environment variables', 500);
} }
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)}`;
@@ -39,10 +46,11 @@ const builtWithHandler = async (url) => {
req.end(); req.end();
}); });
return response; return {
statusCode: 200,
body: response,
};
} catch (error) { } catch (error) {
throw new Error(`Error making request: ${error.message}`); return errorResponse(`Error making request: ${error.message}`);
} }
}; };
exports.handler = middleware(builtWithHandler);
+2 -5
View File
@@ -1,9 +1,8 @@
const commonMiddleware = require('./_common/middleware');
const axios = require('axios'); const axios = require('axios');
const xml2js = require('xml2js'); const xml2js = require('xml2js');
const handler = async (url) => { exports.handler = async (event) => {
const url = event.queryStringParameters.url;
let sitemapUrl = `${url}/sitemap.xml`; let sitemapUrl = `${url}/sitemap.xml`;
try { try {
@@ -60,5 +59,3 @@ const handler = async (url) => {
} }
} }
}; };
exports.handler = commonMiddleware(handler);
+2 -5
View File
@@ -1,9 +1,8 @@
const commonMiddleware = require('./_common/middleware');
const axios = require('axios'); const axios = require('axios');
const cheerio = require('cheerio'); const cheerio = require('cheerio');
const handler = async (url) => { exports.handler = async (event, context) => {
let url = event.queryStringParameters.url;
// Check if url includes protocol // Check if url includes protocol
if (!url.startsWith('http://') && !url.startsWith('https://')) { if (!url.startsWith('http://') && !url.startsWith('https://')) {
@@ -67,5 +66,3 @@ const handler = async (url) => {
}; };
} }
}; };
exports.handler = commonMiddleware(handler);
+50
View File
@@ -0,0 +1,50 @@
const https = require('https');
exports.handler = async function (event, context) {
const { url } = event.queryStringParameters;
const errorResponse = (message, statusCode = 500) => {
return {
statusCode: statusCode,
body: JSON.stringify({ error: message }),
};
};
if (!url) {
return errorResponse('URL query parameter is required', 400);
}
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}`));
} else {
let cert = res.socket.getPeerCertificate(true);
if (!cert || Object.keys(cert).length === 0) {
resolve(errorResponse("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),
});
}
}
});
req.on('error', error => {
resolve(errorResponse(`Error fetching site certificate: ${error.message}`));
});
req.end();
});
return response;
} catch (error) {
return errorResponse(`Unexpected error occurred: ${error.message}`);
}
};
-43
View File
@@ -1,43 +0,0 @@
const tls = require('tls');
const middleware = require('./_common/middleware');
const fetchSiteCertificateHandler = async (urlString) => {
try {
const parsedUrl = new URL(urlString);
const options = {
host: parsedUrl.hostname,
port: parsedUrl.port || 443,
servername: parsedUrl.hostname,
rejectUnauthorized: false,
};
return new Promise((resolve, reject) => {
const socket = tls.connect(options, () => {
if (!socket.authorized) {
return reject(new Error(`SSL handshake not authorized. Reason: ${socket.authorizationError}`));
}
const cert = socket.getPeerCertificate();
if (!cert || Object.keys(cert).length === 0) {
return reject(new Error(`
No certificate presented by the server.\n
The server is possibly not using SNI (Server Name Indication) to identify itself, and you are connecting to a hostname-aliased IP address.
Or it may be due to an invalid SSL certificate, or an incomplete SSL handshake at the time the cert is being read.`));
}
const { raw, issuerCertificate, ...certWithoutRaw } = cert;
resolve(certWithoutRaw);
socket.end();
});
socket.on('error', (error) => {
reject(new Error(`Error fetching site certificate: ${error.message}`));
});
});
} catch (error) {
throw new Error(error.message);
}
};
exports.handler = middleware(fetchSiteCertificateHandler);
+59 -20
View File
@@ -1,30 +1,69 @@
const Wappalyzer = require('wappalyzer'); const Wappalyzer = require('wappalyzer');
const middleware = require('./_common/middleware');
const analyzeSiteTechnologies = async (url) => { const analyze = 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.queryStringParameters.url) {
return {
statusCode: 400,
body: JSON.stringify({ error: 'Missing url parameter' }),
};
}
// Get URL from param
let url = event.queryStringParameters.url;
if (!/^https?:\/\//i.test(url)) {
url = 'http://' + url;
}
try { try {
await wappalyzer.init(); return analyze(url).then(
const headers = {}; (results) => {
const storage = { if (!results.technologies || results.technologies.length === 0) {
local: {}, return {
session: {}, statusCode: 200,
}; body: JSON.stringify({ error: 'Unable to find any technologies for site' }),
const site = await wappalyzer.open(url, headers, storage); };
const results = await site.analyze(); }
return {
if (!results.technologies || results.technologies.length === 0) { statusCode: 200,
throw new Error('Unable to find any technologies for site'); body: JSON.stringify(results),
} }
return results; }
)
.catch((error) => {
return {
statusCode: 500,
body: JSON.stringify({ error: error.message }),
};
});
} catch (error) { } catch (error) {
throw new Error(error.message); return {
} finally { statusCode: 500,
await wappalyzer.destroy(); body: JSON.stringify({ error: error.message }),
};
} }
}; };
exports.handler = middleware(analyzeSiteTechnologies);
-95
View File
@@ -1,95 +0,0 @@
const axios = require('axios');
const xml2js = require('xml2js');
const middleware = require('./_common/middleware');
const getGoogleSafeBrowsingResult = async (url) => {
try {
const apiKey = process.env.GOOGLE_CLOUD_API_KEY;
const apiEndpoint = `https://safebrowsing.googleapis.com/v4/threatMatches:find?key=${apiKey}`;
const requestBody = {
threatInfo: {
threatTypes: [
'MALWARE', 'SOCIAL_ENGINEERING', 'UNWANTED_SOFTWARE', 'POTENTIALLY_HARMFUL_APPLICATION', 'API_ABUSE'
],
platformTypes: ["ANY_PLATFORM"],
threatEntryTypes: ["URL"],
threatEntries: [{ url }]
}
};
const response = await axios.post(apiEndpoint, requestBody);
if (response.data && response.data.matches) {
return {
unsafe: true,
details: response.data.matches
};
} else {
return { unsafe: false };
}
} catch (error) {
return { error: `Request failed: ${error.message}` };
}
};
const getUrlHausResult = async (url) => {
let domain = new URL(url).hostname;
return await axios({
method: 'post',
url: 'https://urlhaus-api.abuse.ch/v1/host/',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
data: `host=${domain}`
})
.then((x) => x.data)
.catch((e) => ({ error: `Request to URLHaus failed, ${e.message}`}));
};
const getPhishTankResult = async (url) => {
try {
const encodedUrl = Buffer.from(url).toString('base64');
const endpoint = `https://checkurl.phishtank.com/checkurl/?url=${encodedUrl}`;
const headers = {
'User-Agent': 'phishtank/web-check',
};
const response = await axios.post(endpoint, null, { headers, timeout: 3000 });
const parsed = await xml2js.parseStringPromise(response.data, { explicitArray: false });
return parsed.response.results;
} catch (error) {
return { error: `Request to PhishTank failed: ${error.message}` };
}
}
const getCloudmersiveResult = async (url) => {
try {
const endpoint = 'https://api.cloudmersive.com/virus/scan/website';
const headers = {
'Content-Type': 'application/x-www-form-urlencoded',
'Apikey': process.env.CLOUDMERSIVE_API_KEY,
};
const data = `Url=${encodeURIComponent(url)}`;
const response = await axios.post(endpoint, data, { headers });
return response.data;
} catch (error) {
return { error: `Request to Cloudmersive failed: ${error.message}` };
}
};
const handler = async (url) => {
try {
const urlHaus = await getUrlHausResult(url);
const phishTank = await getPhishTankResult(url);
const cloudmersive = await getCloudmersiveResult(url);
const safeBrowsing = await getGoogleSafeBrowsingResult(url);
if (urlHaus.error && phishTank.error && cloudmersive.error && safeBrowsing.error) {
throw new Error(`All requests failed - ${urlHaus.error} ${phishTank.error} ${cloudmersive.error} ${safeBrowsing.error}`);
}
return JSON.stringify({ urlHaus, phishTank, cloudmersive, safeBrowsing });
} catch (error) {
throw new Error(error.message);
}
};
exports.handler = middleware(handler);
-28
View File
@@ -1,28 +0,0 @@
const axios = require('axios');
const middleware = require('./_common/middleware');
const MOZILLA_TLS_OBSERVATORY_API = 'https://tls-observatory.services.mozilla.com/api/v1';
const handler = async (url) => {
try {
const domain = new URL(url).hostname;
const scanResponse = await axios.post(`${MOZILLA_TLS_OBSERVATORY_API}/scan?target=${domain}`);
const scanId = scanResponse.data.scan_id;
if (typeof scanId !== 'number') {
return {
statusCode: 500,
body: JSON.stringify({ error: 'Failed to get scan_id from TLS Observatory' }),
};
}
const resultResponse = await axios.get(`${MOZILLA_TLS_OBSERVATORY_API}/results?id=${scanId}`);
return {
statusCode: 200,
body: JSON.stringify(resultResponse.data),
};
} catch (error) {
return { error: error.message };
}
};
exports.handler = middleware(handler);
+46 -22
View File
@@ -1,31 +1,55 @@
const traceroute = require('traceroute'); const traceroute = require('traceroute');
const url = require('url'); const url = require('url');
const middleware = require('./_common/middleware');
const executeTraceroute = async (urlString, context) => { exports.handler = async function(event, context) {
// Parse the URL and get the hostname const urlString = event.queryStringParameters.url;
const urlObject = url.parse(urlString);
const host = urlObject.hostname;
if (!host) { try {
throw new Error('Invalid URL provided'); if (!urlString) {
} throw new Error('URL parameter is missing!');
}
// Traceroute with callback // Parse the URL and get the hostname
const result = await new Promise((resolve, reject) => { const urlObject = url.parse(urlString);
traceroute.trace(host, (err, hops) => { const host = urlObject.hostname;
if (err || !hops) {
reject(err || new Error('No hops found')); if (!host) {
} else { throw new Error('Invalid URL provided');
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 {
message: "Traceroute completed!", statusCode: 200,
result, 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,
}),
};
}
}; };
exports.handler = middleware(executeTraceroute);
+57 -64
View File
@@ -1,7 +1,14 @@
const net = require('net'); const net = require('net');
const psl = require('psl'); const psl = require('psl');
const axios = require('axios'); // 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 = '';
@@ -15,7 +22,55 @@ const getBaseDomain = (url) => {
return protocol + parsed.domain; return protocol + parsed.domain;
}; };
exports.handler = async function(event, context) {
let url = event.queryStringParameters.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'};
} }
@@ -45,65 +100,3 @@ const parseWhoisData = (data) => {
return parsedData; return parsedData;
}; };
const fetchFromInternic = async (hostname) => {
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);
});
});
};
const fetchFromMyAPI = async (hostname) => {
try {
const response = await axios.post('https://whois-api-zeta.vercel.app/', {
domain: hostname
});
return response.data;
} catch (error) {
console.error('Error fetching data from your API:', error.message);
return null;
}
};
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}`);
}
const [internicData, whoisData] = await Promise.all([
fetchFromInternic(hostname),
fetchFromMyAPI(hostname)
]);
return {
internicData,
whoisData
};
};
exports.handler = middleware(fetchWhoisData);
+1 -1
View File
@@ -4,5 +4,5 @@ services:
container_name: Web-Check container_name: Web-Check
image: lissy93/web-check image: lissy93/web-check
ports: ports:
- 3000:3000 - 8888:8888
restart: unless-stopped restart: unless-stopped
+4 -18
View File
@@ -16,7 +16,7 @@
}, },
"scripts": { "scripts": {
"dev": "netlify dev", "dev": "netlify dev",
"serve": "node server", "serve": "netlify serve --offline",
"start": "react-scripts start", "start": "react-scripts start",
"build": "react-scripts build", "build": "react-scripts build",
"test": "react-scripts test", "test": "react-scripts test",
@@ -35,14 +35,9 @@
"@types/react-router-dom": "^5.3.3", "@types/react-router-dom": "^5.3.3",
"@types/react-simple-maps": "^3.0.0", "@types/react-simple-maps": "^3.0.0",
"@types/styled-components": "^5.1.26", "@types/styled-components": "^5.1.26",
"aws-serverless-express": "^3.4.0",
"axios": "^1.4.0", "axios": "^1.4.0",
"cheerio": "^1.0.0-rc.12", "cheerio": "^1.0.0-rc.12",
"chrome-aws-lambda": "^10.1.0", "chrome-aws-lambda": "^10.1.0",
"chromium": "^3.0.3",
"connect-history-api-fallback": "^2.0.0",
"csv-parser": "^3.0.0",
"dotenv": "^16.3.1",
"flatted": "^3.2.7", "flatted": "^3.2.7",
"follow-redirects": "^1.15.2", "follow-redirects": "^1.15.2",
"got": "^13.0.0", "got": "^13.0.0",
@@ -51,7 +46,7 @@
"perf_hooks": "^0.0.1", "perf_hooks": "^0.0.1",
"psl": "^1.9.0", "psl": "^1.9.0",
"puppeteer": "^20.9.0", "puppeteer": "^20.9.0",
"puppeteer-core": "^21.0.3", "puppeteer-core": "^20.9.0",
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-masonry-css": "^1.0.16", "react-masonry-css": "^1.0.16",
@@ -59,14 +54,12 @@
"react-scripts": "5.0.1", "react-scripts": "5.0.1",
"react-simple-maps": "^3.0.0", "react-simple-maps": "^3.0.0",
"react-toastify": "^9.1.3", "react-toastify": "^9.1.3",
"recharts": "^2.7.3",
"styled-components": "^6.0.5", "styled-components": "^6.0.5",
"traceroute": "^1.0.0", "traceroute": "^1.0.0",
"typescript": "^5.1.6", "typescript": "^5.1.6",
"unzipper": "^0.10.14", "wappalyzer": "^6.10.63",
"wappalyzer": "^6.10.65",
"web-vitals": "^3.4.0", "web-vitals": "^3.4.0",
"xml2js": "^0.6.2" "xml2js": "^0.6.0"
}, },
"eslintConfig": { "eslintConfig": {
"extends": [ "extends": [
@@ -89,12 +82,5 @@
"compilerOptions": { "compilerOptions": {
"allowJs": true, "allowJs": true,
"outDir": "./dist" "outDir": "./dist"
},
"devDependencies": {
"serverless-domain-manager": "^7.1.1",
"serverless-offline": "^12.0.4",
"serverless-webpack": "^5.13.0",
"webpack": "^5.88.2",
"webpack-node-externals": "^3.0.0"
} }
} }
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 273 KiB

+2 -16
View File
@@ -7,29 +7,15 @@
<meta name="theme-color" content="#9fef00" /> <meta name="theme-color" content="#9fef00" />
<meta <meta
name="description" name="description"
content="All-in-one OSINT tool, for quickly checking a websites data" content="Web site created using create-react-app"
/> />
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" /> <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" /> <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<title>Web Check</title> <title>Web Check</title>
<script defer data-domain="web-check.as93.net" src="https://no-track.as93.net/js/script.js"></script> <script defer data-domain="web-check.as93.net" src="https://no-track.as93.net/js/script.js"></script>
<!-- OpenGraph Social Tags -->
<meta property="og:title" content="Web Check">
<meta property="og:description" content="All-in-one Website OSINT Scanner">
<meta property="og:image" content="/banner.png">
<meta property="og:url" content="https://web-check.as93.net">
<meta name="twitter:card" content="summary_large_image">
</head> </head>
<body> <body>
<noscript> <noscript>All-in-one OSINT tool, for quickly checking a websites data</noscript>
<b>Welcome to Web-Check, the free and open source tool for viewing all available information about a website.</b><br />
Get started by entering a URL, and clicking the "Scan" button, or view the code and docs
on <a href="https://github.com/lissy93/web-check">GitHub</a>.<br />
<small>Licensed under MIT, ©️ <a href="https://aliciasykes.com">Alicia Sykes</a> 2023.</small>
<br /><br />
JavaScript is required to continue, please enable it in your browser.
</noscript>
<div id="root"></div> <div id="root"></div>
</body> </body>
</html> </html>
Loaded 100 of 134 files, more files were not shown because too many files have changed in this diff. Show more