Skip to content

Commit 4c7aa45

Browse files
committed
feat(security): divert bot traffic
1 parent 0ebefb4 commit 4c7aa45

29 files changed

Lines changed: 2977 additions & 38 deletions

.husky/pre-commit

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
#!/bin/sh
2-
npx lint-staged
2+
npm run check:no-build

package-lock.json

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
"check:openapi": "npm run generate:openapi && npm run generate:skills && tsx scripts/check-openapi-contract.ts && git diff --exit-code docs/openapi.json docs/openapi.yaml docs/skills.json",
2424
"check:skills": "npm run generate:skills && tsx scripts/check-openapi-contract.ts && git diff --exit-code docs/skills.json",
2525
"check": "tsx scripts/check.ts",
26+
"check:no-build": "tsx scripts/check.ts --skip-build",
2627
"check:verbose": "tsx scripts/check.ts --verbose",
2728
"check:dry": "npm run check",
2829
"prepare": "npm run build:sdk && husky",
@@ -68,6 +69,7 @@
6869
"@noble/hashes": "^2.2.0",
6970
"@number-flow/react": "^0.6.0",
7071
"@remixicon/react": "^4.9.0",
72+
"asn-blocklist": "^1.20260703.2",
7173
"boring-avatars": "^2.0.4",
7274
"class-variance-authority": "^0.7.1",
7375
"clsx": "^2.1.1",

scripts/check-runner/cli.ts

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ interface TaskResult extends StepResult {
2525
failedStep?: string;
2626
}
2727

28+
interface CheckOptions {
29+
verbose: boolean;
30+
skipBuild: boolean;
31+
}
32+
2833
export const rlog = createScriptLogger({
2934
silent: true,
3035
});
@@ -163,33 +168,43 @@ async function runTask(task: CheckTask, verbose: boolean): Promise<TaskResult> {
163168
};
164169
}
165170

166-
function parseArgs(argv: string[]): { verbose: boolean } {
167-
const knownArgs = new Set(["--verbose", "--help", "-h"]);
171+
function parseArgs(argv: string[]): CheckOptions {
172+
const knownArgs = new Set([
173+
"--verbose",
174+
"--skip-build",
175+
"--no-build",
176+
"--help",
177+
"-h",
178+
]);
168179
const unknownArgs = argv.filter((arg) => !knownArgs.has(arg));
169180

170181
if (argv.includes("--help") || argv.includes("-h")) {
171-
rlog.info("Usage: tsx scripts/check.ts [--verbose]");
182+
rlog.info("Usage: tsx scripts/check.ts [--verbose] [--skip-build]");
172183
rlog.info(
173-
"Runs the same quality, coverage, spec, and build checks used by CI.",
184+
"Runs the same quality, coverage, spec, and build checks used by CI. Use --skip-build for commit-time checks.",
174185
);
175186
process.exit(0);
176187
}
177188

178189
if (unknownArgs.length > 0) {
179190
rlog.error(`Unknown option: ${unknownArgs.join(", ")}`);
180-
rlog.info("Usage: tsx scripts/check.ts [--verbose]");
191+
rlog.info("Usage: tsx scripts/check.ts [--verbose] [--skip-build]");
181192
process.exit(1);
182193
}
183194

184195
return {
185196
verbose: argv.includes("--verbose"),
197+
skipBuild: argv.includes("--skip-build") || argv.includes("--no-build"),
186198
};
187199
}
188200

189201
export async function runCli(argv = process.argv.slice(2)): Promise<void> {
190-
const { verbose } = parseArgs(argv);
202+
const { verbose, skipBuild } = parseArgs(argv);
203+
const selectedTasks = skipBuild
204+
? tasks.filter((task) => task.name !== "Build")
205+
: tasks;
191206
const results = await Promise.all(
192-
tasks.map((task) => runTask(task, verbose)),
207+
selectedTasks.map((task) => runTask(task, verbose)),
193208
);
194209
const failures = results.filter((result) => !result.ok);
195210

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { notFound } from "next/navigation";
2+
3+
import { BotProtectionClient } from "@/components/dashboard/bot-protection-client";
4+
import { getDashboardProfile } from "@/lib/dashboard/server";
5+
import { resolveLocale } from "@/lib/i18n/config";
6+
import { getMessages } from "@/lib/i18n/messages";
7+
8+
interface BotProtectionPageProps {
9+
params: Promise<{
10+
locale: string;
11+
}>;
12+
}
13+
14+
export async function generateMetadata({ params }: BotProtectionPageProps) {
15+
const { locale } = await params;
16+
const resolvedLocale = resolveLocale(locale);
17+
const messages = getMessages(resolvedLocale);
18+
19+
return {
20+
title: messages.botProtection.title,
21+
};
22+
}
23+
24+
export default async function BotProtectionPage({
25+
params,
26+
}: BotProtectionPageProps) {
27+
const { locale } = await params;
28+
const resolvedLocale = resolveLocale(locale);
29+
const messages = getMessages(resolvedLocale);
30+
const profile = await getDashboardProfile();
31+
32+
if (!profile || profile.user.systemRole !== "admin") {
33+
notFound();
34+
}
35+
36+
return <BotProtectionClient locale={resolvedLocale} messages={messages} />;
37+
}

src/app/[locale]/app/(root)/manage/system-settings/page.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { notFound } from "next/navigation";
22

33
import { PageHeading } from "@/components/dashboard/page-heading";
4+
import { BotAnalyticsSettingsClient } from "@/components/dashboard/system-settings/bot-analytics-settings-client";
45
import { LoginTurnstileSettingsClient } from "@/components/dashboard/system-settings/login-turnstile-settings-client";
56
import { NotificationEmailSettingsClient } from "@/components/dashboard/system-settings/notification-email-settings-client";
67
import { getDashboardProfile } from "@/lib/dashboard/server";
@@ -41,6 +42,7 @@ export default async function SystemSettingsPage({
4142
title={messages.systemSettings.title}
4243
subtitle={messages.systemSettings.subtitle}
4344
/>
45+
<BotAnalyticsSettingsClient messages={messages} />
4446
<LoginTurnstileSettingsClient messages={messages} />
4547
<NotificationEmailSettingsClient
4648
locale={resolvedLocale}

0 commit comments

Comments
 (0)