mirror of
https://github.com/anotherhadi/default-creds.git
synced 2026-04-04 12:22:11 +02:00
init
This commit is contained in:
30
src/pages/403.astro
Normal file
30
src/pages/403.astro
Normal file
@@ -0,0 +1,30 @@
|
||||
---
|
||||
import Layout from "../layouts/Layout.astro";
|
||||
import { ShieldAlert, Home } from "lucide-svelte";
|
||||
---
|
||||
|
||||
<Layout title="403 - Access Denied">
|
||||
<main
|
||||
class="flex flex-col items-center justify-center gap-6 px-4 text-center"
|
||||
>
|
||||
<div class="flex flex-col items-center mt-20">
|
||||
<ShieldAlert size={80} class="text-warning" />
|
||||
<h1 class="text-4xl font-black text-warning opacity-50 mb-10">403</h1>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h2 class="text-3xl font-bold logo-gradient italic">Access Denied</h2>
|
||||
<p class="opacity-60 max-w-xs mx-auto mt-2">
|
||||
You don't have the necessary clearance to access this sector of the app.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="badge badge-outline badge-warning font-mono text-xs p-3">
|
||||
ERROR_CODE: INSUFFICIENT_PERMISSIONS
|
||||
</div>
|
||||
|
||||
<a href="/" class="btn btn-soft btn-warning gap-2">
|
||||
<Home size={16} /> Return to Surface
|
||||
</a>
|
||||
</main>
|
||||
</Layout>
|
||||
26
src/pages/404.astro
Normal file
26
src/pages/404.astro
Normal file
@@ -0,0 +1,26 @@
|
||||
---
|
||||
import Layout from "../layouts/Layout.astro";
|
||||
import { Ghost, Home } from "lucide-svelte";
|
||||
---
|
||||
|
||||
<Layout title="404 - Page Not Found">
|
||||
<main
|
||||
class="flex flex-col items-center justify-center gap-6 px-4 text-center"
|
||||
>
|
||||
<div class="flex flex-col items-center mt-20">
|
||||
<Ghost size={80} class="text-primary" />
|
||||
<h1 class="text-4xl font-black text-primary opacity-50 mb-10">404</h1>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h2 class="text-3xl font-bold logo-gradient italic">Lost?</h2>
|
||||
<p class="opacity-60 max-w-xs mx-auto mt-2">
|
||||
The page you are looking for doesn't exist or has been moved.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<a href="/" class="btn btn-soft btn-primary gap-2">
|
||||
<Home size={16} /> Back to Home
|
||||
</a>
|
||||
</main>
|
||||
</Layout>
|
||||
32
src/pages/500.astro
Normal file
32
src/pages/500.astro
Normal file
@@ -0,0 +1,32 @@
|
||||
---
|
||||
import Layout from "../layouts/Layout.astro";
|
||||
import { AlertTriangle, RefreshCw } from "lucide-svelte";
|
||||
---
|
||||
|
||||
<Layout title="500 - Server Error">
|
||||
<main
|
||||
class="flex flex-col items-center justify-center gap-6 px-4 text-center"
|
||||
>
|
||||
<div class="flex flex-col items-center mt-20">
|
||||
<AlertTriangle size={80} class="text-error" />
|
||||
<h1 class="text-4xl font-black text-error opacity-50 mb-10">500</h1>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h2 class="text-3xl font-bold logo-gradient italic">System Failure</h2>
|
||||
<p class="opacity-60 max-w-xs mx-auto mt-2">
|
||||
The server encountered an unexpected error.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="flex gap-4">
|
||||
<button
|
||||
onclick="window.location.reload()"
|
||||
class="btn btn-soft btn-error gap-2"
|
||||
>
|
||||
<RefreshCw size={16} /> Retry
|
||||
</button>
|
||||
<a href="/" class="btn btn-soft btn-primary">Go Home</a>
|
||||
</div>
|
||||
</main>
|
||||
</Layout>
|
||||
175
src/pages/api-docs.astro
Normal file
175
src/pages/api-docs.astro
Normal file
@@ -0,0 +1,175 @@
|
||||
---
|
||||
import Layout from "../layouts/Layout.astro";
|
||||
import { Terminal, Settings, Database, Info, Code } from "lucide-svelte";
|
||||
---
|
||||
|
||||
<Layout title="API Documentation">
|
||||
<main class="max-w-4xl mx-auto p-6 space-y-12 my-10">
|
||||
<header class="space-y-4 border-b border-white/5 pb-8">
|
||||
<h1
|
||||
class="text-5xl font-black uppercase tracking-tighter flex items-center gap-4 text-primary"
|
||||
>
|
||||
<Terminal size={48} />
|
||||
<span class="logo-gradient">API Docs</span>
|
||||
</h1>
|
||||
<p class="text-xl opacity-70">
|
||||
Integrate our community-driven default credentials database into your
|
||||
own security tools.
|
||||
</p>
|
||||
</header>
|
||||
|
||||
<section class="space-y-4">
|
||||
<h2
|
||||
class="text-2xl font-bold italic text-primary flex items-center gap-2"
|
||||
>
|
||||
<Code size={24} />Base Endpoint
|
||||
</h2>
|
||||
<div
|
||||
class="mockup-code bg-base-300 border border-white/5 shadow-2xl before:content-none"
|
||||
>
|
||||
<pre
|
||||
data-prefix="GET"
|
||||
class="px-5"><code>/api/search?q={query}</code></pre>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="space-y-4">
|
||||
<h2
|
||||
class="text-2xl font-bold italic text-secondary flex items-center gap-2"
|
||||
>
|
||||
<Settings size={24} /> Query Parameters
|
||||
</h2>
|
||||
<div
|
||||
class="overflow-x-auto bg-base-200 rounded-box border border-white/5 shadow-lg"
|
||||
>
|
||||
<table class="table w-full">
|
||||
<thead>
|
||||
<tr class="text-secondary opacity-60 uppercase text-xs">
|
||||
<th>Parameter</th>
|
||||
<th>Type</th>
|
||||
<th>Default</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="hover:bg-white/5 transition-colors">
|
||||
<td class="font-mono text-primary font-bold">q</td>
|
||||
<td><span class="badge badge-outline badge-sm">string</span></td>
|
||||
<td class="opacity-50">-</td>
|
||||
<td
|
||||
>Target name or tag (e.g. <code class="text-accent"
|
||||
>"admin"</code
|
||||
>, <code class="text-accent">"ubnt"</code>)</td
|
||||
>
|
||||
</tr>
|
||||
<tr class="hover:bg-white/5 transition-colors">
|
||||
<td class="font-mono text-primary font-bold">page</td>
|
||||
<td><span class="badge badge-outline badge-sm">number</span></td>
|
||||
<td class="text-secondary">1</td>
|
||||
<td>Page number for pagination results.</td>
|
||||
</tr>
|
||||
<tr class="hover:bg-white/5 transition-colors">
|
||||
<td class="font-mono text-primary font-bold">size</td>
|
||||
<td><span class="badge badge-outline badge-sm">number</span></td>
|
||||
<td class="text-secondary">10</td>
|
||||
<td
|
||||
>Results per page <span class="text-xs opacity-50"
|
||||
>(Min: 1, Max: 20)</span
|
||||
></td
|
||||
>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="space-y-6">
|
||||
<h2 class="text-2xl font-bold italic text-accent flex items-center gap-2">
|
||||
<Terminal size={24} /> Usage Examples
|
||||
</h2>
|
||||
|
||||
<div class="space-y-2">
|
||||
<p class="text-sm font-mono opacity-50">
|
||||
// 1. Basic search for cisco admin panels
|
||||
</p>
|
||||
<div
|
||||
class="mockup-code bg-base-300 border border-white/5 shadow-xl group"
|
||||
>
|
||||
<pre
|
||||
data-prefix="$"><code>curl -X GET "https://default-creds.hadi.diy/api/search?q=cisco"</code></pre>
|
||||
<pre
|
||||
data-prefix=">"
|
||||
class="text-success"><code>HTTP/1.1 200 OK</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2 pt-4">
|
||||
<p class="text-sm font-mono opacity-50">
|
||||
// 2. Specific pagination request
|
||||
</p>
|
||||
<div class="mockup-code bg-base-300 border border-white/5 shadow-xl">
|
||||
<pre
|
||||
data-prefix="$"><code>curl -G "https://default-creds.hadi.diy/api/search" \
|
||||
-d "q=cisco" \
|
||||
-d "page=2" \
|
||||
-d "size=5"</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="space-y-4">
|
||||
<h2
|
||||
class="text-2xl font-bold italic text-primary flex items-center gap-2"
|
||||
>
|
||||
<Database size={24} /> JSON Response Structure
|
||||
</h2>
|
||||
<div class="mockup-code bg-base-300 border border-white/5 shadow-inner">
|
||||
<pre
|
||||
class="text-xs lg:text-sm"><code>{
|
||||
"results": [
|
||||
{
|
||||
"manufacturer": "Ubiquiti",
|
||||
"name": "UniFi",
|
||||
"icon": "ubnt-icon",
|
||||
"tags": ["network", "router"],
|
||||
"version": "all",
|
||||
"user": "ubnt",
|
||||
"pass": "ubnt"
|
||||
}
|
||||
...
|
||||
],
|
||||
"pagination": {
|
||||
"totalResults": 42,
|
||||
"totalPages": 5,
|
||||
"currentPage": 1,
|
||||
"pageSize": 10
|
||||
}
|
||||
}</code></pre>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="alert bg-base-300 border border-primary/20 shadow-lg mt-10">
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="bg-primary/10 p-3 rounded-full">
|
||||
<Info class="text-primary" size={24} />
|
||||
</div>
|
||||
<div>
|
||||
<h3
|
||||
class="font-bold text-primary italic uppercase text-xs tracking-widest"
|
||||
>
|
||||
Rate Limiting & Ethics
|
||||
</h3>
|
||||
<p class="text-xs opacity-70 mt-1 leading-relaxed">
|
||||
This API is provided for educational and authorized penetration
|
||||
testing only. Excessive requests may lead to temporary IP
|
||||
blacklisting. You can found the full database on Github. Contribute
|
||||
to the database on <a
|
||||
href="https://github.com/anotherhadi/default-creds/blob/main/CONTRIBUTING.md"
|
||||
class="link link-primary">GitHub</a
|
||||
>.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</Layout>
|
||||
109
src/pages/api/search.ts
Normal file
109
src/pages/api/search.ts
Normal file
@@ -0,0 +1,109 @@
|
||||
import type { APIRoute } from "astro";
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import yaml from "js-yaml";
|
||||
|
||||
export interface CredentialEntry {
|
||||
manufacturer: string;
|
||||
name: string;
|
||||
icon: string;
|
||||
tags: string[];
|
||||
version: string;
|
||||
user: string;
|
||||
pass: string;
|
||||
comment: string;
|
||||
searchStr: string;
|
||||
}
|
||||
|
||||
let cachedData: CredentialEntry[] | null = null;
|
||||
|
||||
export function getAllData(): CredentialEntry[] {
|
||||
if (cachedData) return cachedData;
|
||||
|
||||
const dataDir = path.join(process.cwd(), "src", "data");
|
||||
|
||||
if (!fs.existsSync(dataDir)) {
|
||||
console.warn(`Data directory not found at ${dataDir}`);
|
||||
return [];
|
||||
}
|
||||
|
||||
const files = fs.readdirSync(dataDir);
|
||||
const allResults: CredentialEntry[] = [];
|
||||
|
||||
for (const file of files) {
|
||||
if (file.endsWith(".yaml") || file.endsWith(".yml")) {
|
||||
try {
|
||||
const content = fs.readFileSync(path.join(dataDir, file), "utf8");
|
||||
const doc = yaml.load(content) as any;
|
||||
|
||||
if (!doc || !doc.entries || !Array.isArray(doc.entries)) continue;
|
||||
|
||||
const manufacturerTags = doc.tags || [];
|
||||
const manufacturerName = doc.name || "Unknown";
|
||||
const manufacturerIcon = doc.icon || "terminal";
|
||||
|
||||
for (const entry of doc.entries) {
|
||||
allResults.push({
|
||||
manufacturer: manufacturerName,
|
||||
name: entry.name || "Generic Device",
|
||||
icon: manufacturerIcon,
|
||||
tags: manufacturerTags,
|
||||
version: entry.version || "all",
|
||||
user: String(entry.user ?? ""),
|
||||
pass: String(entry.pass ?? ""),
|
||||
comment: entry.comment || "",
|
||||
searchStr:
|
||||
`${manufacturerName} ${entry.name} ${entry.comment} ${manufacturerTags.join(" ")}`.toLowerCase(),
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(`Error parsing ${file}:`, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cachedData = allResults;
|
||||
return allResults;
|
||||
}
|
||||
|
||||
export const GET: APIRoute = async ({ url }) => {
|
||||
const query = url.searchParams.get("q")?.trim().toLowerCase() || "";
|
||||
const page = Math.max(1, parseInt(url.searchParams.get("page") || "1"));
|
||||
const size = Math.min(
|
||||
50,
|
||||
Math.max(1, parseInt(url.searchParams.get("size") || "10")),
|
||||
);
|
||||
|
||||
const allEntries = getAllData();
|
||||
|
||||
let filtered = allEntries;
|
||||
if (query) {
|
||||
const queryTokens = query.split(/\s+/).filter((t) => t.length > 0);
|
||||
filtered = allEntries.filter((entry) =>
|
||||
queryTokens.every((token) => entry.searchStr.includes(token)),
|
||||
);
|
||||
}
|
||||
|
||||
const totalResults = filtered.length;
|
||||
const totalPages = Math.ceil(totalResults / size);
|
||||
const start = (page - 1) * size;
|
||||
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
results: filtered.slice(start, start + size),
|
||||
pagination: {
|
||||
totalResults,
|
||||
totalPages,
|
||||
currentPage: page,
|
||||
pageSize: size,
|
||||
},
|
||||
}),
|
||||
{
|
||||
status: 200,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"Cache-Control": "public, max-age=3600",
|
||||
},
|
||||
},
|
||||
);
|
||||
};
|
||||
31
src/pages/api/stats.ts
Normal file
31
src/pages/api/stats.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import type { APIRoute } from "astro";
|
||||
import { getAllData } from "./search";
|
||||
|
||||
export const GET: APIRoute = async () => {
|
||||
try {
|
||||
const allEntries = getAllData();
|
||||
|
||||
const uniqueManufacturers = new Set(
|
||||
allEntries.map((entry) => entry.manufacturer),
|
||||
);
|
||||
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
totalApps: uniqueManufacturers.size,
|
||||
totalPasswords: allEntries.length,
|
||||
}),
|
||||
{
|
||||
status: 200,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"Cache-Control": "public, max-age=3600",
|
||||
},
|
||||
},
|
||||
);
|
||||
} catch (error) {
|
||||
console.error("Error generating stats:", error);
|
||||
return new Response(JSON.stringify({ error: "Internal Server Error" }), {
|
||||
status: 500,
|
||||
});
|
||||
}
|
||||
};
|
||||
22
src/pages/index.astro
Normal file
22
src/pages/index.astro
Normal file
@@ -0,0 +1,22 @@
|
||||
---
|
||||
import Layout from "../layouts/Layout.astro";
|
||||
import SearchApp from "../components/SearchApp.svelte";
|
||||
---
|
||||
|
||||
<Layout>
|
||||
<img src="/logo.svg" class="m-auto size-28" />
|
||||
|
||||
<header class="text-center mb-12">
|
||||
<h2 class="text-md tracking-widest uppercase mt-5 mb-4">
|
||||
Open-source Default Credentials Database
|
||||
</h2>
|
||||
<p class="max-w-xl text-center m-auto">
|
||||
Find default credentials for many devices and software. <a
|
||||
href="https://github.com/anotherhadi/default-creds/blob/main/CONTRIBUTING.md"
|
||||
class="text-primary">Contribute</a
|
||||
> to the database by submitting new credentials or updating existing ones.
|
||||
</p>
|
||||
</header>
|
||||
|
||||
<SearchApp client:load />
|
||||
</Layout>
|
||||
Reference in New Issue
Block a user