From a67eb0a3762f81711dd4bd96dc0a5ba5d26d089f Mon Sep 17 00:00:00 2001 From: dusk Date: Tue, 26 Nov 2024 21:24:27 +0300 Subject: [PATCH] feat: block any requests that are disallowed by robots txt --- bun.lockb | Bin 177552 -> 177928 bytes package.json | 1 + src/lib/lastfm.ts | 2 +- src/lib/robots.ts | 53 +++++++++++++++++++++++++++++++ src/routes/+layout.server.ts | 9 +++++- src/routes/robots.txt/+server.ts | 38 ++-------------------- 6 files changed, 65 insertions(+), 38 deletions(-) create mode 100644 src/lib/robots.ts diff --git a/bun.lockb b/bun.lockb index f5a6b334141fe4b4772634230fc6fde9f946b3e6..3e978011e5c7df7254a53a03c4c68d096242926e 100755 GIT binary patch delta 29759 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 Gm;8U1KCnCh diff --git a/package.json b/package.json index 0a7f2a4..ac16773 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,7 @@ "nanoid": "^5.0.9", "rehype-autolink-headings": "^7.1.0", "rehype-slug": "^6.0.0", + "robots-parser": "^3.0.1", "steamgriddb": "^2.2.0", "typescript-svelte-plugin": "^0.3.43" }, diff --git a/src/lib/lastfm.ts b/src/lib/lastfm.ts index dabceb2..25425e5 100644 --- a/src/lib/lastfm.ts +++ b/src/lib/lastfm.ts @@ -15,7 +15,7 @@ export const lastFmGetNowPlaying: () => Promise = async () => try { var resp = await (await fetch(GET_RECENT_TRACKS_ENDPOINT)).json() var track = resp.recenttracks.track[0] ?? null - if (!(track['@attr'].nowplaying ?? null)) { + if (!((track['@attr'] ?? {}).nowplaying ?? null)) { throw "no nowplaying track found" } var data = { diff --git a/src/lib/robots.ts b/src/lib/robots.ts new file mode 100644 index 0000000..4578f01 --- /dev/null +++ b/src/lib/robots.ts @@ -0,0 +1,53 @@ +import { env } from '$env/dynamic/private' +import { get, writable } from 'svelte/store' +import { type Robot } from 'robots-parser' +import robotsParser from 'robots-parser' +import { PUBLIC_BASE_URL } from '$env/static/public' + +const cachedParsedRobots = writable(null) +const cachedRobots = writable("") +const lastFetched = writable(Date.now()) + +const fetchRobotsTxt = async () => { + const robotsTxtResp = await fetch( + "https://api.darkvisitors.com/robots-txts", + { + method: "POST", + headers: { + "Authorization": `Bearer ${env.DARK_VISITORS_TOKEN}`, + "Content-Type": "application/json" + }, + body: JSON.stringify({ + agent_types: [ + "AI Assistant", + "AI Data Scraper", + "AI Search Crawler", + "Undocumented AI Agent", + ], + disallow: "/" + }) + } + ) + const robotsTxt = await robotsTxtResp.text() + lastFetched.set(Date.now()) + return robotsTxt +} + +export const getRobotsTxt = async () => { + let robotsTxt = get(cachedRobots) + if (robotsTxt.length === 0 || Date.now() - get(lastFetched) > 1000 * 60 * 60 * 24) { + robotsTxt = await fetchRobotsTxt() + cachedRobots.set(robotsTxt) + cachedParsedRobots.set(robotsParser(`${PUBLIC_BASE_URL}/robots.txt`, robotsTxt)) + } + return robotsTxt +} + +export const testUa = async (url: string, ua: string) => { + let parsedRobots = get(cachedParsedRobots) + if (parsedRobots === null) { + parsedRobots = robotsParser(`${PUBLIC_BASE_URL}/robots.txt`, await getRobotsTxt()) + cachedParsedRobots.set(parsedRobots) + } + return parsedRobots.isAllowed(url, ua) +} \ No newline at end of file diff --git a/src/routes/+layout.server.ts b/src/routes/+layout.server.ts index bef57e6..c868567 100644 --- a/src/routes/+layout.server.ts +++ b/src/routes/+layout.server.ts @@ -1,13 +1,20 @@ +import { testUa } from '$lib/robots.js'; import { incrementVisitCount, notifyDarkVisitors } from '$lib/visits.js'; +import { error } from '@sveltejs/kit'; export const csr = true; export const ssr = true; export const prerender = false; export const trailingSlash = 'always'; -export async function load({ request, cookies, url, setHeaders }) { +export async function load({ request, cookies, url }) { notifyDarkVisitors(url, request) // no await so it doesnt block load + // block any requests if the user agent is disallowed by our robots txt + if (await testUa(url.toString(), request.headers.get('user-agent') ?? "unknown user agent") === false) { + throw error(403, "get a better user agent silly") + } + return { route: url.pathname, visitCount: incrementVisitCount(request, cookies), diff --git a/src/routes/robots.txt/+server.ts b/src/routes/robots.txt/+server.ts index 2a18f2d..b98a0a4 100644 --- a/src/routes/robots.txt/+server.ts +++ b/src/routes/robots.txt/+server.ts @@ -1,39 +1,5 @@ -import { env } from '$env/dynamic/private'; -import { get, writable } from 'svelte/store'; - -const cachedRobots = writable("") -const lastFetched = writable(Date.now()) - -const fetchRobotsTxt = async () => { - const robotsTxtResp = await fetch( - "https://api.darkvisitors.com/robots-txts", - { - method: "POST", - headers: { - "Authorization": `Bearer ${env.DARK_VISITORS_TOKEN}`, - "Content-Type": "application/json" - }, - body: JSON.stringify({ - agent_types: [ - "AI Assistant", - "AI Data Scraper", - "AI Search Crawler", - "Undocumented AI Agent", - ], - disallow: "/" - }) - } - ) - const robotsTxt = await robotsTxtResp.text() - lastFetched.set(Date.now()) - return robotsTxt -} +import { getRobotsTxt } from "$lib/robots" export const GET = async ({ }) => { - let robotsTxt = get(cachedRobots) - if (robotsTxt.length === 0 || Date.now() - get(lastFetched) > 1000 * 60 * 60 * 24) { - robotsTxt = await fetchRobotsTxt() - cachedRobots.set(robotsTxt) - } - return new Response(robotsTxt) + return new Response(await getRobotsTxt()) } \ No newline at end of file