Skip to content

Commit 50329a5

Browse files
committed
Implement api token reporting endpoint
1 parent ea409c8 commit 50329a5

1 file changed

Lines changed: 110 additions & 0 deletions

File tree

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
<script lang="ts">
2+
import { OctagonAlert } from '@lucide/svelte';
3+
import { goto } from '$app/navigation';
4+
import { apiTokensApi } from '$lib/api';
5+
import Turnstile from '$lib/components/Turnstile.svelte';
6+
import { Button } from '$lib/components/ui/button';
7+
import * as Card from '$lib/components/ui/card';
8+
import { Checkbox } from '$lib/components/ui/checkbox';
9+
import { Label } from '$lib/components/ui/label';
10+
import ScrollArea from '$lib/components/ui/scroll-area/scroll-area.svelte';
11+
import { handleApiError } from '$lib/errorhandling/apiErrorHandling';
12+
import { toast } from 'svelte-sonner';
13+
14+
function isValid(str: string): boolean {
15+
return /^[0-9a-zA-Z]{32,64}$/i.test(str);
16+
}
17+
18+
let secrets = $state<string[]>([]);
19+
let turnstileResponse = $state<string | null>(null);
20+
let acknowledgement = $state(false);
21+
let isAllValid = $derived(secrets.every(isValid));
22+
let canSubmit = $derived(
23+
secrets.length > 0 && isAllValid && turnstileResponse !== null && acknowledgement
24+
);
25+
26+
async function handleSubmit() {
27+
if (!canSubmit || !turnstileResponse) return;
28+
29+
try {
30+
await apiTokensApi.tokensReportTokens({ turnstileResponse, secrets });
31+
goto('/login');
32+
} catch (err) {
33+
handleApiError(err);
34+
}
35+
}
36+
37+
async function pasteFromClipboard() {
38+
try {
39+
const text = await navigator.clipboard.readText();
40+
secrets = text
41+
.split(/\s|,/)
42+
.map((s) => s.trim())
43+
.filter((s) => s.length > 0);
44+
} catch (err) {
45+
toast.error(`Failed to read clipboard: ${err}`);
46+
}
47+
}
48+
</script>
49+
50+
<div class="max-w-3xl mx-auto my-10 space-y-6 px-4">
51+
<Card.Header>
52+
<Card.Title class="text-3xl font-semibold flex justify-between items-center">
53+
Report Leaked API Tokens
54+
<Button onclick={pasteFromClipboard} size="sm" variant="outline">Paste from clipboard</Button>
55+
</Card.Title>
56+
</Card.Header>
57+
58+
<Card.Content class="space-y-5">
59+
<!-- Warning Message -->
60+
<div class="flex items-start gap-3 p-4 border-l-4 border-red-500 bg-red-50 rounded-md">
61+
<OctagonAlert class="text-red-600" />
62+
<p class="text-sm text-red-800 leading-snug">
63+
<strong>This form is only for reporting accidentally leaked API tokens.</strong><br />
64+
<u>Intentional abuse will result in bans or severe endpoint restrictions.</u>
65+
</p>
66+
</div>
67+
68+
<!-- Token Preview -->
69+
<span class="block text-sm font-medium text-gray-700 mb-2">Detected Tokens</span>
70+
<ScrollArea class="h-48 border rounded-md p-3 bg-gray-50">
71+
{#each secrets as secret}
72+
<p
73+
class="text-sm font-mono break-all px-2 py-1 mb-1 rounded
74+
{isValid(secret) ? 'bg-green-200 text-gray-800' : 'bg-red-200 text-red-700'}"
75+
>
76+
{secret}
77+
</p>
78+
{/each}
79+
</ScrollArea>
80+
{#if !isAllValid}
81+
<div
82+
class="mt-2 flex items-start gap-2 text-sm text-red-700 bg-red-50 border border-red-200 p-3 rounded-md"
83+
>
84+
<span> One or more tokens appear to be invalid. Please check for formatting issues. </span>
85+
</div>
86+
{/if}
87+
88+
<!-- Turnstile + Acknowledgement -->
89+
<div class="space-y-3">
90+
<Turnstile action="report-token" bind:response={turnstileResponse} />
91+
<div class="flex items-center space-x-2">
92+
<Checkbox
93+
id="acknowledgement"
94+
bind:checked={acknowledgement}
95+
aria-labelledby="acknowledgement-label"
96+
/>
97+
<Label
98+
id="acknowledgement-label"
99+
for="acknowledgement"
100+
class="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
101+
>
102+
I confirm I understand what this feature is for and accept responsibility.
103+
</Label>
104+
</div>
105+
</div>
106+
107+
<!-- Submit -->
108+
<Button onclick={handleSubmit} disabled={!canSubmit} class="w-full">Submit Report</Button>
109+
</Card.Content>
110+
</div>

0 commit comments

Comments
 (0)