daemon-sec-lotl

DÆMONBins: GTFOBins × LOLBAS × WADComs × LOOBins in one filterable catalog
git clone https://git.daemon-sec.xyz/daemon-sec-lotl.git
Log | Files | Refs | Submodules | README | LICENSE

catalog-workspace.ts (2293B)


      1 import { FACET_KEYS, facetValues, matches, type Technique, type CatalogFilters, type FacetKey } from './techniques';
      2 export type SortOrder = 'tool' | 'source' | 'reviewed';
      3 export function sortTechniques(rows: Technique[], order: SortOrder, query = ''): Technique[] {
      4   const needle = query.trim().toLowerCase();
      5   return [...rows].sort((a, b) => {
      6     const exact = Number(b.toolName.toLowerCase() === needle) - Number(a.toolName.toLowerCase() === needle);
      7     if (exact) return exact;
      8     if (order === 'reviewed') { const date = (b.reviewedAt || '').localeCompare(a.reviewedAt || ''); if (date) return date; }
      9     if (order === 'source') { const source = a.source.localeCompare(b.source); if (source) return source; }
     10     return a.toolName.localeCompare(b.toolName, 'en', { numeric: true, sensitivity: 'base' }) || a.id.localeCompare(b.id);
     11   });
     12 }
     13 export function groupTechniques(rows: Technique[]): Technique[][] {
     14   const groups = new Map<string, Technique[]>();
     15   for (const t of rows) { const group = groups.get(t.toolId) || []; group.push(t); groups.set(t.toolId, group); }
     16   return [...groups.values()];
     17 }
     18 export function contextualCounts(rows: Technique[], filters: CatalogFilters): Record<FacetKey, Record<string, number>> {
     19   return Object.fromEntries(FACET_KEYS.map(key => {
     20     const counts: Record<string, number> = {};
     21     for (const t of rows) if (matches(t, { ...filters, [key]: [] })) for (const value of facetValues(t, key)) counts[value] = (counts[value] || 0) + 1;
     22     return [key, counts];
     23   })) as Record<FacetKey, Record<string, number>>;
     24 }
     25 export function quoteArgument(value: string, shell: 'posix' | 'powershell'): string {
     26   if (/[\r\n\0]/.test(value)) throw new Error('Use a single-line value.');
     27   return shell === 'powershell' ? `'${value.replace(/'/g, "''")}'` : `'${value.replace(/'/g, "'\"'\"'")}'`;
     28 }
     29 export function configureCommand(template: NonNullable<Technique['template']>, values: Record<string, string>): string {
     30   const keys = new Set(template.variables.map(v => v.key));
     31   return template.command.replace(/\{\{([a-z][a-z0-9_]*)\}\}/g, (_, key: string) => {
     32     if (!keys.has(key)) throw new Error(`Unknown variable: ${key}`);
     33     return quoteArgument(values[key] ?? template.variables.find(v => v.key === key)!.default, template.shell);
     34   });
     35 }