This commit is contained in:
Hadi
2026-04-06 15:12:34 +02:00
commit 4989225671
117 changed files with 11454 additions and 0 deletions

30
front/src/pages/403.astro Normal file
View File

@@ -0,0 +1,30 @@
---
import Layout from "@src/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
front/src/pages/404.astro Normal file
View File

@@ -0,0 +1,26 @@
---
import Layout from "@src/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
front/src/pages/500.astro Normal file
View File

@@ -0,0 +1,32 @@
---
import Layout from "@src/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>

View File

@@ -0,0 +1,126 @@
---
import Layout from "@src/layouts/Layout.astro";
import { getCollection, render } from "astro:content";
export async function getStaticPaths() {
const sheets = await getCollection("cheatsheets");
return sheets.map((sheet) => ({
params: { slug: sheet.id },
props: { sheet },
}));
}
const { sheet } = Astro.props;
const { Content, headings } = await render(sheet);
const toc = headings.filter((h) => h.depth === 2 || h.depth === 3);
---
<Layout title={`${sheet.data.title} - Cheatsheets`} description={sheet.data.description}>
<div class="pb-4">
<div class="mb-6">
<a href="/cheatsheets" class="btn btn-ghost btn-sm gap-1">← Cheatsheets</a>
</div>
<div class="mb-8">
<h1 class="text-2xl font-bold tracking-tight">{sheet.data.title}</h1>
{sheet.data.description && (
<p class="text-base-content/50 text-sm mt-1">{sheet.data.description}</p>
)}
{sheet.data.tags && sheet.data.tags.length > 0 && (
<div class="flex gap-2 mt-3">
{sheet.data.tags.map((tag) => (
<a href={`/cheatsheets?tag=${tag}`} class="badge badge-ghost badge-sm">{tag}</a>
))}
</div>
)}
</div>
{toc.length > 0 && (
<details class="lg:hidden mb-6 border border-base-300 rounded-lg">
<summary class="cursor-pointer px-4 py-3 text-sm font-semibold select-none list-none flex items-center justify-between">
<span>On this page</span>
<svg class="size-4 opacity-50 details-chevron" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg>
</summary>
<nav class="px-4 pb-4 pt-1">
<ul class="flex flex-col gap-1">
{toc.map((h) => (
<li style={h.depth === 3 ? "padding-left: 0.875rem" : ""}>
<a href={`#${h.slug}`} class="toc-link text-sm text-base-content/60 hover:text-base-content transition-colors">
{h.text}
</a>
</li>
))}
</ul>
</nav>
</details>
)}
<div class="flex gap-10 items-start">
<div class="prose prose-sm max-w-none flex-1 min-w-0 break-words">
<Content />
</div>
{toc.length > 0 && (
<aside class="hidden lg:block w-48 shrink-0">
<nav class="sticky top-8">
<p class="text-xs font-semibold uppercase tracking-wider text-base-content/40 mb-3">
On this page
</p>
<ul class="flex flex-col gap-1.5">
{toc.map((h) => (
<li style={h.depth === 3 ? "padding-left: 0.75rem" : ""}>
<a
href={`#${h.slug}`}
data-toc-link
class="toc-link text-xs text-base-content/50 hover:text-base-content transition-colors leading-snug block"
>
{h.text}
</a>
</li>
))}
</ul>
</nav>
</aside>
)}
</div>
</div>
</Layout>
<style>
details[open] .details-chevron {
transform: rotate(180deg);
}
.details-chevron {
transition: transform 0.2s;
}
.toc-link.active {
color: var(--color-primary);
}
</style>
<script>
const links = document.querySelectorAll<HTMLAnchorElement>("[data-toc-link]");
if (links.length > 0) {
const headingEls = [...links].map((l) =>
document.querySelector(decodeURIComponent(new URL(l.href).hash))
);
const observer = new IntersectionObserver(
(entries) => {
for (const entry of entries) {
if (entry.isIntersecting) {
const idx = headingEls.indexOf(entry.target);
links.forEach((l) => l.classList.remove("active"));
if (idx !== -1) links[idx].classList.add("active");
}
}
},
{ rootMargin: "-20% 0px -70% 0px" }
);
headingEls.forEach((el) => el && observer.observe(el));
}
</script>

View File

@@ -0,0 +1,33 @@
---
import Layout from "@src/layouts/Layout.astro";
import { getCollection } from "astro:content";
import CheatsheetList from "@src/components/CheatsheetList.svelte";
const sheets = (await getCollection("cheatsheets"))
.sort((a, b) => (a.data.order ?? 99) - (b.data.order ?? 99))
.map((s) => ({
id: s.id,
title: s.data.title,
description: s.data.description,
tags: s.data.tags,
}));
---
<Layout title="Cheatsheets">
<div class="max-w-3xl mx-auto px-4 pb-4">
<div class="mb-6">
<a href="/" class="btn btn-ghost btn-sm gap-1">← Back</a>
</div>
<div class="mb-8">
<h1 class="text-2xl font-bold tracking-tight">OSINT Cheatsheets</h1>
<p class="text-base-content/50 text-sm mt-1">
Quick reference cards for common OSINT techniques.
</p>
</div>
<CheatsheetList {sheets} client:only="svelte" />
</div>
</Layout>

172
front/src/pages/help.astro Normal file
View File

@@ -0,0 +1,172 @@
---
import Layout from "@src/layouts/Layout.astro";
---
<Layout title="How it works">
<div class="max-w-3xl mx-auto px-4 pb-4">
<div class="mb-6">
<a href="/" class="btn btn-ghost btn-sm gap-1">← Back</a>
</div>
<div class="mb-8">
<h1 class="text-2xl font-bold tracking-tight">How it works</h1>
<p class="text-base-content/50 text-sm mt-1">
A guide to iknowyou: concepts, tools, profiles, and configuration.
</p>
</div>
<div class="flex flex-col gap-8">
<section class="flex flex-col gap-3">
<h2 class="text-lg font-bold flex items-center gap-2">
<span class="size-2 rounded-full bg-primary inline-block"></span>
What is it?
</h2>
<p class="text-base-content/70 text-sm leading-relaxed">
<strong>Iknowyou</strong> (IKY) is an OSINT aggregation platform. It runs multiple
open-source intelligence tools against a target in parallel and presents the results
in a unified interface. Targets can be email addresses, usernames, phone numbers, IP
addresses, domains, and more.
</p>
<p class="text-base-content/70 text-sm leading-relaxed">
Instead of running each tool manually, IKY handles orchestration, config management,
and result rendering so you can focus on analysis.
</p>
</section>
<div class="divider my-0"></div>
<section class="flex flex-col gap-3">
<h2 class="text-lg font-bold flex items-center gap-2">
<span class="size-2 rounded-full bg-primary inline-block"></span>
Tools
</h2>
<p class="text-base-content/70 text-sm leading-relaxed">
Each <strong>tool</strong> is a Go module that knows how to query one data source
(a website, an API, a local binary...). Tools declare:
</p>
<ul class="list-disc list-inside text-base-content/70 text-sm leading-relaxed space-y-1 ml-2">
<li>Which <strong>input types</strong> they accept (email, username, IP...)</li>
<li>Optional <strong>configuration fields</strong> (API keys, options)</li>
<li>Whether they require an <strong>external binary</strong> to be installed</li>
</ul>
<p class="text-base-content/70 text-sm leading-relaxed">
The <a href="/tools" class="link link-primary">Tools page</a> shows all registered tools
grouped by status:
</p>
<div class="flex flex-col gap-2 ml-2">
<div class="flex items-center gap-2 text-sm">
<span class="size-2 rounded-full bg-success shrink-0"></span>
<span><strong>Active</strong> - ready to run</span>
</div>
<div class="flex items-center gap-2 text-sm">
<span class="size-2 rounded-full bg-warning shrink-0"></span>
<span><strong>Active: config missing</strong> - needs an API key or required field</span>
</div>
<div class="flex items-center gap-2 text-sm">
<span class="size-2 rounded-full bg-error shrink-0"></span>
<span><strong>Active: unavailable</strong> - required binary not found on the system</span>
</div>
<div class="flex items-center gap-2 text-sm">
<span class="size-2 rounded-full bg-base-content/20 shrink-0"></span>
<span><strong>Disabled</strong> - excluded by the selected profile</span>
</div>
</div>
</section>
<div class="divider my-0"></div>
<section class="flex flex-col gap-3">
<h2 class="text-lg font-bold flex items-center gap-2">
<span class="size-2 rounded-full bg-primary inline-block"></span>
Profiles
</h2>
<p class="text-base-content/70 text-sm leading-relaxed">
A <strong>profile</strong> is a named search configuration. When you start a search,
you pick which profile to use. Profiles control:
</p>
<ul class="list-disc list-inside text-base-content/70 text-sm leading-relaxed space-y-1 ml-2">
<li><strong>Enabled list</strong> (whitelist): if set, only these tools run</li>
<li><strong>Disabled list</strong> (blacklist): these tools are always skipped</li>
<li><strong>Tool overrides</strong>: per-profile config that overrides global settings for specific tools</li>
<li><strong>Notes</strong>: a description of what the profile is for</li>
</ul>
<p class="text-base-content/70 text-sm leading-relaxed">
Two profiles are built-in and cannot be modified:
</p>
<div class="flex flex-col gap-2 ml-2">
<div class="card bg-base-200 p-3 text-sm">
<span class="font-mono font-bold">default</span>
<p class="text-base-content/60 text-xs mt-1">
All tools active with default settings. No restrictions.
</p>
</div>
<div class="card bg-base-200 p-3 text-sm">
<span class="font-mono font-bold">hard</span>
<p class="text-base-content/60 text-xs mt-1">
Aggressive mode. All tools active, including those that may send
notifications or leave traces at the target.
</p>
</div>
</div>
<p class="text-base-content/70 text-sm leading-relaxed">
You can create custom profiles on the <a href="/profiles" class="link link-primary">Profiles page</a>.
</p>
</section>
<div class="divider my-0"></div>
<section class="flex flex-col gap-3">
<h2 class="text-lg font-bold flex items-center gap-2">
<span class="size-2 rounded-full bg-primary inline-block"></span>
Configuration &amp; Overrides
</h2>
<p class="text-base-content/70 text-sm leading-relaxed">
Tool configuration works in two layers:
</p>
<ol class="list-decimal list-inside text-base-content/70 text-sm leading-relaxed space-y-2 ml-2">
<li>
<strong>Global config</strong>: set on the
<a href="/tools" class="link link-primary">Tools page</a>. Applied to every
search regardless of profile.
</li>
<li>
<strong>Profile override</strong>: set inside a profile. Takes precedence over
global config when that profile is used. Useful when you want a tool to behave
differently in specific contexts (e.g. slower rate-limiting in a "quiet" profile).
</li>
</ol>
<p class="text-base-content/70 text-sm leading-relaxed">
Config is stored in <code class="font-mono bg-base-300 px-1 rounded text-xs">config.yaml</code>.
Built-in profiles are hardcoded in Go and are never written to disk.
</p>
</section>
<div class="divider my-0"></div>
<section class="flex flex-col gap-3">
<h2 class="text-lg font-bold flex items-center gap-2">
<span class="size-2 rounded-full bg-primary inline-block"></span>
How a search runs
</h2>
<ol class="list-decimal list-inside text-base-content/70 text-sm leading-relaxed space-y-2 ml-2">
<li>You enter a target, select its type (email, username...) and pick a profile.</li>
<li>
The backend filters tools by input type and the profile's enabled/disabled rules,
then skips any tool with a missing required config field.
</li>
<li>All eligible tools run in parallel against the target.</li>
<li>
The frontend polls for results and renders them progressively as each tool finishes.
</li>
</ol>
<p class="text-base-content/70 text-sm leading-relaxed">
A search can be cancelled at any time from the results page.
Completed searches are kept in memory.
</p>
</section>
</div>
</div>
</Layout>

View File

@@ -0,0 +1,19 @@
---
import Layout from "@src/layouts/Layout.astro";
import HomePage from "@src/components/HomePage.svelte";
---
<Layout title="iknowyou">
<div class="max-w-3xl mx-auto px-4 py-6 flex flex-col gap-10">
<header class="text-center">
<img src="/logo.svg" class="m-auto w-36" alt="iknowyou" />
<h1 class="font-unbounded logo-gradient text-6xl tracking-[-0.11em] leading-normal mb-2 mt-0">i know you</h1>
<p class="text-base-content/50 text-sm max-w-xl mx-auto">
Centralizing your OSINT tools in one place.<br/>
<strong>Iknowyou</strong> is a self-hosted OSINT (Open-Source Intelligence) platform that centralises reconnaissance tools
into a single reactive web interface. Instead of juggling terminals, browser tabs, and disconnected CLI tools, you type a target once and get results in real time.
</p>
</header>
<HomePage client:only="svelte" />
</div>
</Layout>

View File

@@ -0,0 +1,21 @@
---
import Layout from "@src/layouts/Layout.astro";
import ProfileSettings from "@src/components/ProfileSettings.svelte";
---
<Layout title="Profiles">
<div class="max-w-4xl mx-auto px-4 pb-4">
<div class="mb-6">
<a href="/" class="btn btn-ghost btn-sm gap-1">← Back</a>
</div>
<div class="mb-6">
<h1 class="text-xl font-bold tracking-tight">Profiles</h1>
<p class="text-base-content/50 text-sm mt-1">
Manage search profiles: allowed/blocked tools and per-tool config overrides.
</p>
</div>
<ProfileSettings client:only="svelte" />
</div>
</Layout>

View File

@@ -0,0 +1,22 @@
---
import Layout from "@src/layouts/Layout.astro";
import SearchDetail from "@src/components/SearchDetail.svelte";
export async function getStaticPaths() {
return [{ params: { id: "_" } }];
}
// Shell page — SearchDetail reads the real ID from window.location.
const id = null;
---
<Layout title="Search">
<div class="max-w-4xl mx-auto px-4 pb-4">
<div class="mb-6">
<a href="/" class="btn btn-ghost btn-sm gap-1">← Back</a>
</div>
<SearchDetail {id} client:only="svelte" />
</div>
</Layout>

View File

@@ -0,0 +1,22 @@
---
import Layout from "@src/layouts/Layout.astro";
import ToolDetail from "@src/components/ToolDetail.svelte";
export async function getStaticPaths() {
return [{ params: { name: "_" } }];
}
// Shell page — ToolDetail reads the real name from window.location.
const name = null;
---
<Layout title="Tool">
<div class="max-w-3xl mx-auto px-4 pb-4">
<div class="mb-6">
<a href="/tools" class="btn btn-ghost btn-sm gap-1">← Tools</a>
</div>
<ToolDetail {name} client:only="svelte" />
</div>
</Layout>

View File

@@ -0,0 +1,20 @@
---
import Layout from "@src/layouts/Layout.astro";
import ToolList from "@src/components/ToolList.svelte";
---
<Layout title="Tools">
<div class="max-w-4xl mx-auto px-4 pb-4">
<div class="mb-6">
<a href="/" class="btn btn-ghost btn-sm gap-1">← Back</a>
</div>
<div class="mb-6">
<h1 class="text-xl font-bold tracking-tight">Tools</h1>
<p class="text-base-content/50 text-sm mt-1">All registered OSINT tools.</p>
</div>
<ToolList client:only="svelte" />
</div>
</Layout>