6 Commits

Author SHA1 Message Date
Hadi 35ac328d5e Change links for error pages
Signed-off-by: Hadi <112569860+anotherhadi@users.noreply.github.com>
2026-04-29 19:40:30 +02:00
Hadi 5ad26be352 Change notes titles
Signed-off-by: Hadi <112569860+anotherhadi@users.noreply.github.com>
2026-04-29 19:38:36 +02:00
Hadi fac0a2fff6 edit tooltip
Signed-off-by: Hadi <hadi@example.com>
2026-04-29 16:41:19 +02:00
Hadi d2424e0a17 edit notes
Signed-off-by: Hadi <hadi@example.com>
2026-04-29 16:33:11 +02:00
Hadi 3b17b01d86 add disclaimer
Signed-off-by: Hadi <hadi@example.com>
2026-04-29 16:33:01 +02:00
Hadi 0e83788a15 Edit nav & add folder pages
Signed-off-by: Hadi <hadi@example.com>
2026-04-29 16:23:51 +02:00
16 changed files with 585 additions and 104 deletions
+4
View File
@@ -356,6 +356,10 @@ const {
Projects Projects
<ArrowRight class="size-4" /> <ArrowRight class="size-4" />
</a> </a>
<a href="/notes" class="btn btn-ghost gap-2">
Infosec Notes
<ArrowRight class="size-4" />
</a>
<a href="/#contact" class="btn btn-ghost gap-2"> <a href="/#contact" class="btn btn-ghost gap-2">
Contact Me Contact Me
<ArrowRight class="size-4" /> <ArrowRight class="size-4" />
+6 -2
View File
@@ -4,7 +4,7 @@ const pathname = Astro.url.pathname;
const links = [ const links = [
{ href: "/", label: "home" }, { href: "/", label: "home" },
{ href: "/blog", label: "blog" }, { href: "/blog", label: "blog" },
{ href: "/notes", label: "notes" }, { href: "/notes", label: "infosec notes" },
{ href: "/projects", label: "projects" }, { href: "/projects", label: "projects" },
]; ];
@@ -28,7 +28,11 @@ function isActive(href: string) {
~/hadi ~/hadi
</a> </a>
<div id="oneko-track" transition:persist class="flex-1 relative h-12 pointer-events-none"> <div
id="oneko-track"
transition:persist
class="flex-1 relative h-12 pointer-events-none"
>
</div> </div>
<nav class="hidden md:flex items-center"> <nav class="hidden md:flex items-center">
+26 -11
View File
@@ -1,5 +1,6 @@
<script lang="ts"> <script lang="ts">
import { slide } from "svelte/transition"; import { slide } from "svelte/transition";
import { untrack } from "svelte";
interface Note { interface Note {
id: string; id: string;
@@ -9,11 +10,12 @@
interface Props { interface Props {
notes: Note[]; notes: Note[];
currentEntry: Note; currentEntry?: Note;
currentCategory?: string;
categories: string[]; categories: string[];
} }
const { notes, currentEntry, categories }: Props = $props(); const { notes, currentEntry, currentCategory, categories }: Props = $props();
let search = $state(""); let search = $state("");
@@ -46,8 +48,12 @@
: title.includes(term) || tags.join(",").includes(term); : title.includes(term) || tags.join(",").includes(term);
} }
const activeCategory = $derived(
currentCategory ?? (currentEntry ? getCategory(currentEntry) : null),
);
let openCategories = $state<string[]>( let openCategories = $state<string[]>(
categories.filter((c) => c === getCategory(currentEntry)), untrack(() => categories.filter((c) => c === activeCategory)),
); );
function toggle(cat: string) { function toggle(cat: string) {
@@ -99,11 +105,13 @@
(n) => getCategory(n) === cat && matchesSearch(n), (n) => getCategory(n) === cat && matchesSearch(n),
)} )}
{#if catNotes.length > 0 || !search} {#if catNotes.length > 0 || !search}
{@const isFolder = notes.some((n) => n.id.includes("/") && getCategory(n) === cat)}
<div> <div>
<!-- Category header --> <!-- Category header -->
<div class="flex items-center w-full">
<button <button
onclick={() => toggle(cat)} onclick={() => toggle(cat)}
class="w-full flex items-center gap-1.5 px-2 py-1 rounded-md hover:bg-base-200/40 transition-colors duration-150 group" class="flex items-center gap-1.5 px-2 py-1 rounded-md hover:bg-base-200/40 transition-colors duration-150 shrink-0"
> >
<svg <svg
class="w-3 h-3 text-base-content/35 shrink-0 transition-transform duration-200" class="w-3 h-3 text-base-content/35 shrink-0 transition-transform duration-200"
@@ -119,12 +127,20 @@
<path d="m9 18 6-6-6-6" /> <path d="m9 18 6-6-6-6" />
</svg> </svg>
<span class="text-primary/50 font-mono text-xs shrink-0">/</span> <span class="text-primary/50 font-mono text-xs shrink-0">/</span>
<span </button>
class="font-bold tracking-tight text-sm truncate text-base-content/80" {#if isFolder}
<a
href={`/notes/${cat}`}
class="flex-1 min-w-0 px-1 py-1 rounded-md hover:bg-base-200/40 transition-colors duration-150 font-bold tracking-tight text-sm truncate text-base-content/80 hover:text-base-content"
> >
{cat} {cat}
</a>
{:else}
<span class="flex-1 min-w-0 px-1 py-1 font-bold tracking-tight text-sm truncate text-base-content/80">
{cat}
</span> </span>
</button> {/if}
</div>
<!-- Notes list --> <!-- Notes list -->
{#if openCategories.includes(cat)} {#if openCategories.includes(cat)}
@@ -133,17 +149,16 @@
transition:slide={{ duration: 180 }} transition:slide={{ duration: 180 }}
> >
{#each catNotes as note} {#each catNotes as note}
<li> <li class="tooltip tooltip-right w-full" data-tip={note.data.title}>
<a <a
href={`/notes/${note.id}`} href={`/notes/${note.id}`}
title={note.data.title}
class="flex items-center gap-1.5 px-2 py-1 rounded-md text-xs font-mono truncate transition-colors duration-150 class="flex items-center gap-1.5 px-2 py-1 rounded-md text-xs font-mono truncate transition-colors duration-150
{note.id === currentEntry.id {currentEntry && note.id === currentEntry.id
? 'text-primary/90 bg-primary/10' ? 'text-primary/90 bg-primary/10'
: 'text-base-content/45 hover:text-base-content/80 hover:bg-base-200/40'}" : 'text-base-content/45 hover:text-base-content/80 hover:bg-base-200/40'}"
> >
<span class="shrink-0 font-mono text-base-content/20"> <span class="shrink-0 font-mono text-base-content/20">
{note.id === currentEntry.id ? "▸" : ""} {currentEntry && note.id === currentEntry.id ? "▸" : ""}
</span> </span>
<span class="truncate">{note.data.title}</span> <span class="truncate">{note.data.title}</span>
</a> </a>
+62
View File
@@ -0,0 +1,62 @@
---
title: "FTP"
description: "Enumeration, exploitation and post-exploitation techniques for FTP servers."
tags: ["ftp", "network", "service"]
publishDate: 2026-04-29
---
## Overview
FTP runs on **port 21** (control) and uses a secondary data channel (port 20 for active, ephemeral port for passive).
Common implementations: vsftpd, ProFTPD, Pure-FTPd, FileZilla Server, IIS FTP.
## Enumeration
### Banner grabbing
```bash
nc -nv $IP 21
ftp $IP
```
The banner often reveals the software version: cross-reference with CVE databases.
### Nmap
```bash
nmap -sV -p 21 $IP
nmap -p 21 --script ftp-* $IP
```
Key scripts:
- `ftp-anon`: checks anonymous login
- `ftp-bounce`: tests for FTP bounce attack
- `ftp-brute`: brute-force credentials
- `ftp-syst`: retrieves system info
## Anonymous Login
```bash
ftp $IP
# Username: anonymous
# Password: <empty> or anonymous@
```
If allowed, list and download everything:
```bash
ls -la
mget *
```
Check for writable directories: you may be able to upload a webshell if FTP root overlaps with a web root.
## Brute Force
```bash
hydra -l $user -P /usr/share/wordlists/rockyou.txt ftp://$IP
medusa -h $IP -u $user -P /usr/share/wordlists/rockyou.txt -M ftp
```
Try default credentials first: `admin:admin`, `ftp:ftp`, `user:password`.
-14
View File
@@ -1,14 +0,0 @@
---
title: "Notes in comming.."
description: ""
tags: []
publishDate: 2026-04-24
---
## Notes
Salut comment ça va ! $test1
```bash
nmap -p $port "$Ip"
```
+97
View File
@@ -0,0 +1,97 @@
---
title: "Bluesky"
description: "Enumeration, search operators, API endpoints and tools for investigating Bluesky accounts."
tags: ["osint", "bluesky", "social-media", "enumeration"]
publishDate: 2026-04-29
---
## Key Concepts
Bluesky is built on the **AT Protocol**. Every account has two identifiers:
- **Handle**: `user.bsky.social` or a custom domain (can change)
- **DID**: `did:plc:ewvi7nxzyoun6zhxrhs64oiz` (permanent, survives handle changes)
All public content is accessible **without an account**. Follower/following lists are also public by default.
## Account Enumeration
### Resolve handle → DID
```
https://bsky.social/xrpc/com.atproto.identity.resolveHandle?handle=$HANDLE
```
### Resolve DID → history (all past handles, keys, creation date)
```
https://plc.directory/$DID
```
### Get profile metadata
```
https://public.api.bsky.app/xrpc/app.bsky.actor.getProfile?actor=$HANDLE
```
Returns: DID, display name, description, follower/following count, creation date, avatar URL.
### Followers / following
```
https://public.api.bsky.app/xrpc/app.bsky.graph.getFollowers?actor=$HANDLE&limit=100
https://public.api.bsky.app/xrpc/app.bsky.graph.getFollows?actor=$HANDLE&limit=100
```
Paginate with the `cursor` field from the response.
## Search Operators
Bluesky's full-text search supports these operators (combinable):
| Operator | Example | Effect |
| ----------- | ----------------------------- | ----------------------------- |
| `"..."` | `"exact phrase"` | Exact match |
| `from:` | `from:handle.bsky.social` | Posts by user |
| `mentions:` | `mentions:handle.bsky.social` | Posts mentioning user |
| `since:` | `since:2024-01-01` | After date (UTC, YYYY-MM-DD) |
| `until:` | `until:2024-06-30` | Before date (UTC, YYYY-MM-DD) |
| `lang:` | `lang:fr` | Language (ISO 639-1) |
| `domain:` | `domain:github.com` | Posts linking to domain |
| `#tag` | `#osint` | Hashtag |
#### API equivalent
```
https://public.api.bsky.app/xrpc/app.bsky.feed.searchPosts?q={QUERY}&author={HANDLE}&since=2024-01-01&until=2024-12-31&lang=en&limit=25
```
## Google Dorks
Bluesky is heavily indexed by Google. Useful for finding profiles and posts without touching the platform:
```
site:bsky.app "$TARGET_NAME"
site:bsky.app "$TARGET_NAME" inurl:profile
site:bsky.app "$KEYWORD" since:2024-01-01
```
## Tools
### BlueSkyNet
Web app for searching and exporting Bluesky data to CSV. Wraps the public API with a UI for advanced search filters.
- [github.com/jakecreps/blueskynet](https://github.com/jakecreps/blueskynet)
### ClearSky
Shows block lists, blocking history, and who blocked a given account. Useful for mapping relationships and adversarial clusters.
- [clearsky.app](https://clearsky.app)
### plc.directory
Official DID PLC directory. Lookup a DID to get full account history: creation date, all past handles, key rotations.
- [plc.directory](https://plc.directory)
+138
View File
@@ -0,0 +1,138 @@
---
title: "X / Twitter"
description: "Enumeration, search operators, deleted content recovery and tools for investigating X accounts."
tags: ["osint", "twitter", "x", "social-media", "enumeration"]
publishDate: 2026-04-29
---
## Key Concepts
Every account has two identifiers:
- **Handle**: `@username` (can change)
- **User ID**: numeric, permanent (survives handle changes and suspensions)
Unlike [Bluesky](/notes/osint/bluesky), X now requires a login to browse most content in the browser. The free API tier (v2) is severely limited. Most open-source scraping tools that bypassed the API (Twint, snscrape, GetOldTweets3) are broken since the 2023 API lockdown.
## Account Enumeration
### Handle to User ID
The user ID stays constant when someone changes their handle or gets suspended. Several web tools resolve it:
- [tweeterid.com](https://tweeterid.com/)
- [commentpicker.com/twitter-id.php](https://commentpicker.com/twitter-id.php)
Or via the profile page source: look for `"id_str"` in the page JSON.
### Banner last update time
The profile banner URL contains a Unix timestamp indicating when the banner was last changed:
```
https://pbs.twimg.com/profile_banners/{user_id}/{unix_timestamp}/600x200
```
Right-click the banner image and copy the URL, or inspect the page source. Convert the timestamp at [unixtimestamp.com](https://www.unixtimestamp.com/).
### Timestamp from ID (Snowflake)
Twitter IDs are Snowflake IDs: the numeric value encodes the exact creation time of a tweet or account. Extract it with:
```python
tweet_id = 1234567890123456789
timestamp_ms = (tweet_id >> 22) + 1288834974657
```
`1288834974657` is Twitter's custom epoch (Nov 4, 2010). Works on both tweet IDs and user IDs — useful to confirm account creation date without needing profile metadata.
Several online converters exist if you don't want to do it manually — search "snowflake id decoder".
### Direct profile URL by ID
Old tweet/profile URLs using numeric IDs still resolve even after handle changes:
```
https://x.com/i/user/$USER_ID
```
## Search Operators
Accessible at `x.com/search`. Operators are combinable.
| Operator | Example | Effect |
| ----------------- | -------------------------- | ------------------------ |
| `"..."` | `"exact phrase"` | Exact match |
| `from:` | `from:handle` | Posts by user |
| `to:` | `to:handle` | Posts directed at user |
| `since:` | `since:2024-01-01` | After date (YYYY-MM-DD) |
| `until:` | `until:2024-06-30` | Before date (YYYY-MM-DD) |
| `lang:` | `lang:fr` | Language (ISO 639-1) |
| `near:` | `near:"Paris" within:10km` | Geo (web only, not API) |
| `geocode:` | `geocode:48.85,2.35,5km` | Geo by coordinates |
| `filter:images` | | Posts with images |
| `filter:videos` | | Posts with videos |
| `filter:links` | | Posts with URLs |
| `filter:verified` | | Verified accounts only |
| `-filter:replies` | | Exclude replies |
| `min_retweets:` | `min_retweets:100` | Engagement threshold |
| `min_faves:` | `min_faves:500` | Engagement threshold |
| `#tag` | `#osint` | Hashtag |
| `-term` | `-spam` | Exclude term |
Boolean: spaces imply AND, use uppercase `OR` for alternatives, parentheses for grouping.
#### Direct search URL
```
https://x.com/search?q=from%3A$HANDLE+since%3A2024-01-01&f=live
```
`f=live` returns chronological results instead of relevance-ranked.
## Google Dorks
```
site:x.com "$TARGET"
site:twitter.com "$TARGET"
site:x.com/i/status "$KEYWORD"
"twitter.com/$HANDLE" OR "x.com/$HANDLE"
```
Old `twitter.com` URLs are still indexed separately from `x.com`, search both.
## Deleted and Archived Content
### Wayback Machine
```
https://web.archive.org/web/*/twitter.com/$HANDLE/status/*
https://web.archive.org/web/*/x.com/$HANDLE/status/*
```
Manually browse snapshots, or use [waybacktweets](https://github.com/claromes/waybacktweets) to batch-retrieve CDX data:
```bash
pip install waybacktweets
waybacktweets $HANDLE
```
Outputs CSV/JSON with archived tweet URLs. Useful for deleted posts and suspended accounts.
### Twayback
Web tool wrapping the same Wayback CDX API with a UI:
```
https://twayback.space/
```
Note: only works if the tweet was crawled before deletion.
### Profile history
The Wayback Machine also archives profile pages: past bios, display names, profile photos, header images. Check snapshots at:
```
https://web.archive.org/web/*/twitter.com/$HANDLE
```
-14
View File
@@ -1,14 +0,0 @@
---
title: "test2"
description: ""
tags: []
publishDate: 2026-04-24
---
## Notes
Salut comment ça va ! $test1
```bash
nmap -p $test2 "$test3$test4"
```
-14
View File
@@ -1,14 +0,0 @@
---
title: "Bla blablalbal ae aetnaekjta ektae ktklaaek ljbtaekjb taekbt akejbt"
description: "lorem est seot nopsejt soejtosehtose ose toiseht jophs etosh etoshte osehtosht oshe topsh etopshiospehitopsehti."
tags: ["test", "test1", "test2"]
publishDate: 2026-04-24
---
## Notes
Salut comment ça va ! $test1
```bash
nmap -p $port "$Ip"
```
+3 -5
View File
@@ -30,10 +30,6 @@ import { House, FolderOpen } from "@lucide/astro";
<House class="size-5" /> <House class="size-5" />
Go Home Go Home
</a> </a>
<a href="/projects" class="btn btn-outline gap-2">
<FolderOpen class="size-5" />
View Projects
</a>
</div> </div>
<!-- Helpful Links --> <!-- Helpful Links -->
@@ -44,7 +40,9 @@ import { House, FolderOpen } from "@lucide/astro";
<div class="flex gap-3 justify-center flex-wrap text-sm"> <div class="flex gap-3 justify-center flex-wrap text-sm">
<a href="/blog" class="link link-hover">Blog</a> <a href="/blog" class="link link-hover">Blog</a>
<span class="text-base-content/30">•</span> <span class="text-base-content/30">•</span>
<a href="/projects" class="link link-hover">All my Projects</a> <a href="/projects" class="link link-hover">Projects</a>
<span class="text-base-content/30">•</span>
<a href="/notes" class="link link-hover">Infosec Notes</a>
</div> </div>
</div> </div>
</div> </div>
+3 -5
View File
@@ -30,10 +30,6 @@ import { House, FolderOpen } from "@lucide/astro";
<House class="size-5" /> <House class="size-5" />
Go Home Go Home
</a> </a>
<a href="/projects" class="btn btn-outline gap-2">
<FolderOpen class="size-5" />
View Projects
</a>
</div> </div>
<!-- Helpful Links --> <!-- Helpful Links -->
@@ -44,7 +40,9 @@ import { House, FolderOpen } from "@lucide/astro";
<div class="flex gap-3 justify-center flex-wrap text-sm"> <div class="flex gap-3 justify-center flex-wrap text-sm">
<a href="/blog" class="link link-hover">Blog</a> <a href="/blog" class="link link-hover">Blog</a>
<span class="text-base-content/30">•</span> <span class="text-base-content/30">•</span>
<a href="/projects" class="link link-hover">All my Projects</a> <a href="/projects" class="link link-hover">Projects</a>
<span class="text-base-content/30">•</span>
<a href="/notes" class="link link-hover">Infosec Notes</a>
</div> </div>
</div> </div>
</div> </div>
+6
View File
@@ -68,6 +68,12 @@ if (error instanceof Error) {
rel="noopener noreferrer" rel="noopener noreferrer"
class="link link-hover">Report Issue</a class="link link-hover">Report Issue</a
> >
<span class="text-base-content/30">•</span>
<a href="/blog" class="link link-hover">Blog</a>
<span class="text-base-content/30">•</span>
<a href="/projects" class="link link-hover">Projects</a>
<span class="text-base-content/30">•</span>
<a href="/notes" class="link link-hover">Infosec Notes</a>
</div> </div>
</div> </div>
</div> </div>
+6
View File
@@ -68,6 +68,12 @@ if (error instanceof Error) {
rel="noopener noreferrer" rel="noopener noreferrer"
class="link link-hover">Report Issue</a class="link link-hover">Report Issue</a
> >
<span class="text-base-content/30">•</span>
<a href="/blog" class="link link-hover">Blog</a>
<span class="text-base-content/30">•</span>
<a href="/projects" class="link link-hover">Projects</a>
<span class="text-base-content/30">•</span>
<a href="/notes" class="link link-hover">Infosec Notes</a>
</div> </div>
</div> </div>
</div> </div>
+26 -16
View File
@@ -6,11 +6,7 @@ import NoteTOC from "../../components/NoteTOC.astro";
import NoteNavSidebar from "../../components/NoteNavSidebar.svelte"; import NoteNavSidebar from "../../components/NoteNavSidebar.svelte";
import NoteGraphSidebar from "../../components/NoteGraphSidebar.astro"; import NoteGraphSidebar from "../../components/NoteGraphSidebar.astro";
import NoteVars from "../../components/NoteVars.svelte"; import NoteVars from "../../components/NoteVars.svelte";
import { import { getCategory, extractLinks, extractHeadings } from "../../utils/notes";
getCategory,
extractLinks,
extractHeadings,
} from "../../utils/notes";
export async function getStaticPaths() { export async function getStaticPaths() {
const notes = await getCollection("notes"); const notes = await getCollection("notes");
@@ -41,7 +37,11 @@ const backlinks = allNotes.filter(
const graphNodes = [ const graphNodes = [
{ id: entry.id, title: entry.data.title, current: true }, { id: entry.id, title: entry.data.title, current: true },
...forwardLinks.map((n) => ({ id: n.id, title: n.data.title, current: false })), ...forwardLinks.map((n) => ({
id: n.id,
title: n.data.title,
current: false,
})),
...backlinks ...backlinks
.filter((n) => !forwardLinks.some((f) => f.id === n.id)) .filter((n) => !forwardLinks.some((f) => f.id === n.id))
.map((n) => ({ id: n.id, title: n.data.title, current: false })), .map((n) => ({ id: n.id, title: n.data.title, current: false })),
@@ -72,7 +72,7 @@ const headings = extractHeadings(entry.body ?? "");
</style> </style>
<Layout <Layout
title={`${entry.data.title} — Security Notes`} title={`${entry.data.title} - Infosec Notes`}
description={entry.data.description} description={entry.data.description}
> >
<main class="max-w-screen-2xl mx-auto"> <main class="max-w-screen-2xl mx-auto">
@@ -92,12 +92,24 @@ const headings = extractHeadings(entry.body ?? "");
> >
<ul> <ul>
<li> <li>
<a <a href="/notes" class="hover:text-base-content/70"
href="/notes" >notes</a
class="hover:text-base-content/70" >
>notes</a> </li>
<li>
{
entry.id.includes("/") ? (
<a
href={`/notes/${getCategory(entry)}`}
class="hover:text-base-content/70"
>
{getCategory(entry)}
</a>
) : (
getCategory(entry)
)
}
</li> </li>
<li>{getCategory(entry)}</li>
</ul> </ul>
</div> </div>
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
@@ -196,8 +208,7 @@ const headings = extractHeadings(entry.body ?? "");
<label <label
for="nav-drawer" for="nav-drawer"
aria-label="close sidebar" aria-label="close sidebar"
class="drawer-overlay" class="drawer-overlay"></label>
></label>
<NoteNavSidebar <NoteNavSidebar
client:load client:load
notes={sortedNotes} notes={sortedNotes}
@@ -212,8 +223,7 @@ const headings = extractHeadings(entry.body ?? "");
<label <label
for="graph-drawer" for="graph-drawer"
aria-label="close sidebar" aria-label="close sidebar"
class="drawer-overlay xl:hidden" class="drawer-overlay xl:hidden"></label>
></label>
<NoteGraphSidebar <NoteGraphSidebar
entry={entry} entry={entry}
graphNodes={graphNodes} graphNodes={graphNodes}
+178
View File
@@ -0,0 +1,178 @@
---
import { getCollection } from "astro:content";
import Layout from "../../layouts/Layout.astro";
import NoteNavSidebar from "../../components/NoteNavSidebar.svelte";
import { getCategory } from "../../utils/notes";
import { List } from "@lucide/astro";
export async function getStaticPaths() {
const notes = await getCollection("notes");
const folderCategories = [
...new Set(
notes.filter((n) => n.id.includes("/")).map((n) => getCategory(n)),
),
];
return folderCategories.map((category) => {
const allNotes = notes.sort((a, b) =>
a.data.title.localeCompare(b.data.title),
);
const categories = [...new Set(notes.map(getCategory))].sort();
return {
params: { category },
props: {
category,
categoryNotes: notes
.filter((n) => getCategory(n) === category)
.sort((a, b) => a.data.title.localeCompare(b.data.title)),
allNotes,
categories,
},
};
});
}
const { category, categoryNotes, allNotes, categories } = Astro.props;
if (!categoryNotes) {
return new Response(null, { status: 404, statusText: "Not found" });
}
---
<style>
.drawer.lg\:drawer-open > .drawer-side {
top: 3rem;
height: calc(100vh - 3rem);
}
</style>
<Layout
title={`${category} - Infosec Notes`}
description={`Notes on ${category}.`}
>
<main class="max-w-screen-2xl mx-auto">
<div class="drawer lg:drawer-open min-h-[calc(100vh-3rem)]">
<input id="nav-drawer" type="checkbox" class="drawer-toggle" />
<div class="drawer-content flex flex-col min-w-0">
<main class="flex-1 px-4 sm:px-6 lg:px-10 py-6 lg:py-10 min-w-0">
<div class="max-w-3xl mx-auto lg:mx-0">
<div class="flex items-center justify-between mb-10">
<div
class="breadcrumbs text-xs font-mono text-base-content/35 p-0"
>
<ul>
<li>
<a href="/notes" class="hover:text-base-content/70">notes</a
>
</li>
<li class="text-base-content/60">{category}</li>
</ul>
</div>
<label
for="nav-drawer"
class="btn btn-ghost btn-xs lg:hidden font-mono text-base-content/40 hover:text-base-content/70 border border-base-300/50"
>
<List size={11} />
nav
</label>
</div>
<div class="mb-10">
<div class="flex items-baseline gap-3 mb-1">
<h1 class="text-4xl sm:text-5xl font-bold">
<span class="text-primary/40 font-mono mr-1">/</span>{
category
}
</h1>
</div>
<p class="font-mono text-xs text-base-content/25 ml-8">
{categoryNotes.length} note{
categoryNotes.length !== 1 ? "s" : ""
}
</p>
</div>
<div class="border-t border-base-300/40 mb-1"></div>
<ul class="divide-y divide-base-300/20">
{
categoryNotes.map((note) => (
<li>
<a
href={`/notes/${note.id}`}
class="group flex items-center gap-4 py-3 hover:bg-base-200/30 px-2 -mx-2 transition-colors"
>
<div class="flex-1 min-w-0">
<div class="flex flex-col mb-0.5">
<span class="font-semibold text-sm group-hover:text-primary transition-colors">
{note.data.title}
</span>
{note.data.description && (
<span class="text-xs text-base-content/35 truncate">
{note.data.description}
</span>
)}
</div>
{note.data.tags.length > 0 && (
<div class="flex flex-wrap gap-1 mt-1">
{note.data.tags.map((tag) => (
<span class="badge badge-ghost badge-xs font-mono text-base-content/30">
{tag}
</span>
))}
</div>
)}
</div>
<svg
xmlns="http://www.w3.org/2000/svg"
width="14"
height="14"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="text-base-content/20 group-hover:text-primary/50 shrink-0 transition-colors"
>
<path d="m9 18 6-6-6-6" />
</svg>
</a>
</li>
))
}
</ul>
<div
class="border-t border-base-300/30 mt-12 pt-6 flex items-center justify-between font-mono text-[10px] text-base-content/25"
>
<a
href="/notes"
class="hover:text-base-content/50 transition-colors"
>
← all notes
</a>
<a href="/" class="hover:text-base-content/50 transition-colors">
~/hadi
</a>
</div>
</div>
</main>
</div>
<div class="drawer-side z-50">
<label
for="nav-drawer"
aria-label="close sidebar"
class="drawer-overlay"></label>
<NoteNavSidebar
client:load
notes={allNotes}
currentCategory={category}
categories={categories}
/>
</div>
</div>
</main>
</Layout>
+11 -4
View File
@@ -22,16 +22,23 @@ const searchNotes = sortedNotes.map((n) => ({
--- ---
<Layout <Layout
title="Security Notes Another Hadi" title="Infosec Notes - Another Hadi"
description="Reference notes on cybersecurity tools and techniques." description="Cheatsheets on cybersecurity tools and techniques."
> >
<main class="max-w-4xl mx-auto px-4 py-16 sm:py-20"> <main class="max-w-4xl mx-auto px-4 py-16 sm:py-20">
<div class="text-center mb-12"> <div class="text-center mb-12">
<h1 class="text-4xl sm:text-5xl font-bold mb-4">Notes</h1> <h1 class="text-4xl sm:text-5xl font-bold mb-4">Infosec Notes</h1>
<p class="text-xl text-base-content/70"> <p class="text-xl text-base-content/70">
Reference sheets on cybersecurity tools and techniques. Cheat sheets on cybersecurity tools and techniques.
</p> </p>
</div> </div>
<div
class="text-xs font-mono text-base-content/25 border border-base-300/30 rounded-box px-4 py-3 mb-10 max-w-xl mx-auto text-center leading-relaxed"
>
All content is intended for educational purposes, CTF challenges, and
authorized penetration testing only. Do not use any of this against
systems you do not own or have explicit permission to test.
</div>
<NotesSearch client:load notes={searchNotes} /> <NotesSearch client:load notes={searchNotes} />
</main> </main>
</Layout> </Layout>