Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 8 additions & 10 deletions api/carbon.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,23 @@ const log = createLogger('carbon');
const TIMEOUT = 8000;
const MAX_BYTES = 10 * 1024 * 1024;

// Sustainable Web Design model v3 constants, matches websitecarbon.com formula
const KWH_PER_GB = 0.81;
// Sustainable Web Design model v4 constants, matches websitecarbon.com formula
const KWH_PER_GB = 0.3;
const FIRST_VISIT = 0.25;
const RETURN_VISIT = 0.75;
const RETURN_DATA_PCT = 0.02;
const GRID_INTENSITY = 442;
const GRID_INTENSITY = 494;
const RENEWABLE_INTENSITY = 50;
const LITRES_PER_GRAM = 0.5562;

// Reference median grams CO2 per visit, drawn from websitecarbon's published average.
// Used to estimate a percentile rank since we lack their measured-sites dataset
const REFERENCE_MEDIAN_GRAMS = 0.8;
// Median CO2 for an HTML-only fetch at HTTP Archive's ~30 KB median
const REFERENCE_MEDIAN_GRAMS = 0.001;

// Approximate percentile via log2 distance from the reference median.
// 1 doubling above median drops 25 points; clamp to [1, 99]
// Percentile rank via log2 distance from the median, clamped to [1, 95]
const estimateCleanerThan = (grams) => {
if (!grams || grams <= 0) return 0;
const pct = 50 - 25 * Math.log2(grams / REFERENCE_MEDIAN_GRAMS);
return Math.max(1, Math.min(99, Math.round(pct)));
const pct = 50 - 15 * Math.log2(grams / REFERENCE_MEDIAN_GRAMS);
return Math.max(1, Math.min(95, Math.round(pct)));
};

// Stream the response, cap at MAX_BYTES so huge pages can't blow memory or time
Expand Down
19 changes: 12 additions & 7 deletions api/rank.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,24 @@ import { parseTarget } from './_common/parse-target.js';
import { upstreamError } from './_common/upstream.js';

const rankHandler = async (url) => {
const { hostname: domain } = parseTarget(url);
const { hostname } = parseTarget(url);
const { TRANCO_USERNAME, TRANCO_API_KEY } = process.env;
const auth = TRANCO_API_KEY
? { auth: { username: TRANCO_USERNAME, password: TRANCO_API_KEY } }
: {};
const fallback = hostname.startsWith('www.') ? hostname.slice(4) : `www.${hostname}`;
// Tranco indexes only one variant per site, so try as-is, then toggle www
const lookup = (domain) => httpGet(`https://tranco-list.eu/api/ranks/domain/${domain}`, auth);
try {
const response = await httpGet(`https://tranco-list.eu/api/ranks/domain/${domain}`, auth);
if (!response.data?.ranks?.length) {
return {
skipped: `${domain} isn't ranked in the top 1 million sites yet`,
};
const first = await lookup(hostname);
if (first.data?.ranks?.length) return first.data;
try {
const second = await lookup(fallback);
if (second.data?.ranks?.length) return second.data;
} catch {
// Ignore fallback failures (e.g. rate limit) and accept the empty first result
}
return response.data;
return { skipped: `${hostname} isn't ranked in the top 1 million sites yet` };
} catch (error) {
return upstreamError(error, 'Tranco rank lookup');
}
Expand Down
11 changes: 8 additions & 3 deletions api/subdomains.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,15 @@ const subdomainsHandler = async (url) => {
params: { q: `%.${domain}`, output: 'json' },
headers: { Accept: 'application/json' },
});
const rows = Array.isArray(res.data) ? res.data : [];
const all = collectSubdomains(rows, domain);
if (!Array.isArray(res.data)) {
return { error: 'Certificate Transparency lookup returned unexpected data, please retry' };
}
const all = collectSubdomains(res.data, domain);
if (!all.length) {
return { skipped: `No subdomains found for ${domain} in Certificate Transparency logs` };
return {
skipped: `No subdomains found for ${domain} in Certificate Transparency logs`,
retryable: true,
};
}
return {
domain,
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
"typecheck": "astro check",
"lint": "eslint --config .config/eslint.config.js .",
"format:check": "prettier --check --ignore-unknown '!yarn.lock' '!**/*.md' .",
"format:fix": "prettier --write --ignore-unknown '!yarn.lock' '!**/*.md' ."
"format:fix": "prettier --write --ignore-unknown '!yarn.lock' '!**/*.md' .",
"hold-my-beer": "yarn format:fix && yarn lint && yarn typecheck"
},
"dependencies": {
"@astrojs/check": "^0.9.9",
Expand Down
Binary file modified public/android-chrome-192x192.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified public/android-chrome-512x512.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified public/apple-touch-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified public/favicon-16x16.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified public/favicon-32x32.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
45 changes: 35 additions & 10 deletions public/manifest.json
Original file line number Diff line number Diff line change
@@ -1,20 +1,45 @@
{
"name": "Web Check",
"short_name": "Web Check",
"name": "Lissy93/Web-Check",
"description": "Web Check is the all-in-one OSINT and security tool, for revealing the inner workings of any website",
"id": "/",
"start_url": "/",
"scope": "/",
"display": "standalone",
"theme_color": "#d6fb41",
"background_color": "#111211",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
"src": "/favicon.svg",
"type": "image/svg+xml",
"sizes": "any"
},
{
"src": "/favicon-16x16.png",
"type": "image/png",
"sizes": "16x16"
},
{
"src": "/favicon-32x32.png",
"type": "image/png",
"sizes": "32x32"
},
{
"src": "apple-touch-icon.png",
"src": "/apple-touch-icon.png",
"type": "image/png",
"sizes": "180x180"
},
{
"src": "/android-chrome-192x192.png",
"type": "image/png",
"sizes": "192x192",
"purpose": "any"
},
{
"src": "/android-chrome-512x512.png",
"type": "image/png",
"sizes": "512x512",
"purpose": "any"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#9fef00",
"background_color": "#141d2b"
]
}
2 changes: 1 addition & 1 deletion src/client/components/Form/Nav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const Nav = (props: { children?: ReactNode }) => {
return (
<Header as="header">
<Heading color={colors.primary} size="large">
<img width="64" src="/web-check.png" alt="Web Check Icon" />
<img width="64" src="/favicon.svg" alt="Web Check Icon" />
<a href="/" target="_self">
Web Check
</a>
Expand Down
12 changes: 8 additions & 4 deletions src/client/components/misc/FancyBackground.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -315,12 +315,16 @@ const FancyBackground = (): JSX.Element => {
useEffect(() => {
App.setup();
App.draw();

var frame = function () {
App.evolve();
const frameInterval = 25;
let lastTime = 0;
const frame = (now: number) => {
if (now - lastTime >= frameInterval) {
App.evolve();
lastTime = now;
}
requestAnimationFrame(frame);
};
frame();
requestAnimationFrame(frame);
}, [App]);

return (
Expand Down
2 changes: 1 addition & 1 deletion src/client/components/misc/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ const Footer = (props: { isFixed?: boolean }): JSX.Element => {
</span>
<span>
<Link to="/about">Web-Check</Link> is licensed under <ALink href={licenseUrl}>MIT</ALink> -
© <ALink href={authorUrl}>Alicia Sykes</ALink> 2023
© <ALink href={authorUrl}>Alicia Sykes</ALink> 2026
</span>
</StyledFooter>
);
Expand Down
16 changes: 6 additions & 10 deletions src/client/components/misc/Loader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@ const LoaderContainer = styled(StyledCard)`
margin: 0 auto;
width: 95vw;
position: relative;
transition: all 0.2s ease-in-out;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
gap: 2rem;
height: 50vh;
transition: all 0.3s ease-in-out;
transition:
height 0.3s ease-in-out,
opacity 0.3s ease-in-out;
p.loadTimeInfo {
text-align: center;
margin: 0;
Expand All @@ -29,14 +30,9 @@ const LoaderContainer = styled(StyledCard)`
height: 0;
overflow: hidden;
opacity: 0;
margin: -1rem 0 0 0;
padding: 0;
svg {
width: 0;
}
h4 {
font-size: 0;
}
margin-top: -1rem;
padding-top: 0;
padding-bottom: 0;
}
&.hide {
display: none;
Expand Down
5 changes: 2 additions & 3 deletions src/client/jobs/registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,11 @@ const fetchAndPoll = (path: string) =>
}),
);

// Re-run on transient errors, returning the last error if all attempts fail
// Re-run on transient errors or when the server hints `retryable: true`
const fetchAndRetry = (path: string) =>
retrying(
path,
(r) => !!r?.error,
(r) => !!r?.error || !!r?.retryable,
3,
2000,
(last) => last,
Expand Down Expand Up @@ -207,7 +207,6 @@ export const jobs: JobSpec[] = [
{
id: 'tls-labs',
expectedAddressTypes: [...URL_ONLY],
noClientTimeout: true,
cards: [
card('tls-security-audit', 'TLS Security Audit', ['security'], TlsSecurityAuditCard),
card('tls-client-compat', 'TLS Client Compatibility', ['security'], TlsClientCompatCard),
Expand Down
5 changes: 2 additions & 3 deletions src/client/views/About.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -121,12 +121,11 @@ const SponsorshipContainer = styled.div`
}
`;

const makeAnchor = (title: string): string => {
return title
const makeAnchor = (title: string): string =>
title
.toLowerCase()
.replace(/[^\w\s]|_/g, '')
.replace(/\s+/g, '-');
};

const About = (): JSX.Element => {
const location = useLocation();
Expand Down
Loading