daemon-sec-cheatsheet

The cheatsheet vault for operators: AD, enumeration, exploitation, priv-esc, web, DFIR
git clone https://git.daemon-sec.xyz/daemon-sec-cheatsheet.git
Log | Files | Refs | README | LICENSE

sheets.ts (2473B)


      1 import { getCollection, type CollectionEntry } from 'astro:content';
      2 import { CATEGORIES } from './taxonomy';
      3 
      4 export type Sheet = CollectionEntry<'sheets'>;
      5 
      6 export async function allSheets(): Promise<Sheet[]> {
      7   const sheets = await getCollection('sheets', ({ data }) => data.draft !== true);
      8   return sheets.sort((a, b) => a.data.title.localeCompare(b.data.title));
      9 }
     10 
     11 export function sheetHref(entry: Sheet): string {
     12   return `sheets/${entry.id}`;
     13 }
     14 
     15 export function sheetCategories(entry: Sheet): string[] {
     16   return [...new Set([entry.data.category, ...entry.data.alsoIn])];
     17 }
     18 
     19 /** Sheets grouped by category, in taxonomy order. */
     20 export async function sheetsByCategory(): Promise<{ slug: string; items: Sheet[] }[]> {
     21   const sheets = await allSheets();
     22   return CATEGORIES.map((c) => ({
     23     slug: c.slug,
     24     items: sheets.filter((s) => sheetCategories(s).includes(c.slug)),
     25   }));
     26 }
     27 
     28 export async function categoryCounts(): Promise<Record<string, number>> {
     29   const sheets = await allSheets();
     30   const counts: Record<string, number> = {};
     31   for (const s of sheets) {
     32     for (const category of sheetCategories(s)) counts[category] = (counts[category] ?? 0) + 1;
     33   }
     34   return counts;
     35 }
     36 
     37 /** Previous / next sheet within the same category. */
     38 export function prevNext(items: Sheet[], current: Sheet): { prev?: Sheet; next?: Sheet } {
     39   const i = items.findIndex((s) => s.id === current.id);
     40   return { prev: i > 0 ? items[i - 1] : undefined, next: i >= 0 && i < items.length - 1 ? items[i + 1] : undefined };
     41 }
     42 
     43 /** Distinct tags with usage counts, most-used first. */
     44 export async function allTags(): Promise<{ tag: string; count: number }[]> {
     45   const sheets = await allSheets();
     46   const map = new Map<string, number>();
     47   for (const s of sheets) for (const t of s.data.tags) map.set(t, (map.get(t) ?? 0) + 1);
     48   return [...map.entries()].map(([tag, count]) => ({ tag, count })).sort((a, b) => b.count - a.count || a.tag.localeCompare(b.tag));
     49 }
     50 
     51 export async function allTools(): Promise<{ tool: string; count: number }[]> {
     52   const sheets = await allSheets();
     53   const map = new Map<string, number>();
     54   for (const s of sheets) for (const t of s.data.tools) map.set(t, (map.get(t) ?? 0) + 1);
     55   return [...map.entries()].map(([tool, count]) => ({ tool, count })).sort((a, b) => b.count - a.count || a.tool.localeCompare(b.tool));
     56 }
     57 
     58 export function tagSlug(tag: string): string {
     59   return tag.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '');
     60 }