Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

175 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Cybersecurity Mode // Red Team — Tauri + Solid.js

Przebudowa oryginalnej makiety (React + Vite, "AI Studio" export) na natywną aplikację desktopową: Tauri v2 (backend Rust) + Solid.js (frontend).

Struktura repo

cybersec-mode/
├── Makefile                     # make dev / build / lint / icons / clean
├── scripts/                     # setup.sh, dev.sh, build-release.sh
├── ipc/                         # placeholder na wspólny kontrakt frontend<->backend (patrz ipc/README.md)
└── source-code/
    ├── frontend/                # Solid.js + Vite + Tailwind
    │   ├── src/
    │   │   ├── components/      # Terminal, ToolShop, Analytics, NetworkMonitor,
    │   │   │                    # DraggableScanner, PowerButton
    │   │   ├── lib/tauri.ts     # jedyne miejsce wołające @tauri-apps/api
    │   │   ├── App.tsx
    │   │   └── main.tsx
    │   └── package.json
    └── backend/                 # src-tauri (Rust)
        ├── src/{main,lib}.rs
        ├── capabilities/default.json
        ├── icons/
        ├── Cargo.toml
        └── tauri.conf.json

Szybki start

./scripts/setup.sh      # albo: make install
make dev                # tryb deweloperski (hot reload)
make build               # bundle produkcyjny (.deb/.AppImage/.msi/.dmg zależnie od OS)

Wymagania: Node.js 18+, Rust (rustup) i zależności systemowe Tauri dla Twojej platformy — https://tauri.app/start/prerequisites/.

Co zostało zrobione w tej przebudowie

  • Migracja komponentów z React (hooks, JSX) na Solid.js (signals, <For>, createEffect/onMount/onCleanup), bez zmiany warstwy wizualnej.
  • framer-motion zastąpiony natywnymi transitions CSS + Pointer Events API (drag okna skanera) — jedna zależność mniej, brak odpowiednika 1:1 w ekosystemie Solid, więc lepiej nie ciągnąć dodatkowego pakietu tylko dla jednego elementu.
  • lucide-reactlucide-solid.
  • Cały frontend spakowany jako natywna appka desktopowa przez Tauri (Rust webview), zamiast SPA serwowanego przez Express/Vite preview.
  • Dodany przycisk zasilania (lewy dolny róg, zawsze na wierzchu, wymaga dwukliku w oknie 4s) — wywołuje exit(0) z @tauri-apps/plugin-process.
  • Wydzielona warstwa src/lib/tauri.ts jako jedyny punkt styku z Tauri API, żeby komponenty UI nie znały nazw komend/pluginów bezpośrednio.
  • Struktura repo rozdzielona na source-code/frontend i source-code/backend
    • Makefile, scripts/, ipc/ (placeholder) zgodnie z ustaloną konwencją.

BlackArch Store (nowość) — jak to działa

Arsenal w górnej nawigacji (albo ikona warstw w lewym pasku) otwiera pełny "software center" w stylu Discover/GNOME Software, ale nad prawdziwym pacmanem BlackArch działającym w kontenerze podman:

  • Backend (source-code/backend/src/blackarch.rs) zakłada, że podman jest już zainstalowany w systemie hosta — sam go nie instaluje, tylko sprawdza (podman --version) i jasno komunikuje brak w UI.
  • Przy pierwszym otwarciu Store, jeśli kontener blackarch-redteam nie istnieje, pokazuje ekran onboardingu z przyciskiem "Utwórz kontener BlackArch" → podman run -d --name blackarch-redteam ... blackarch/blackarch tail -f /dev/null, potem pacman -Sy w środku kontenera.
  • Kategorie w lewej kolumnie Store to realne grupy pakietów BlackArch (blackarch-recon, blackarch-scanner, blackarch-exploitation, itd.), pobierane przez pacman -Sg <grupa> + pacman -Si dla opisów/wersji.
  • Wyszukiwarka woła pacman -Ss <fraza> wewnątrz kontenera.
  • Install/Usuń wołają odpowiednio pacman -S --noconfirm <pkg> i pacman -R --noconfirm <pkg> w kontenerze — backend Rust jest jedynym miejscem, które faktycznie odpala procesy; frontend tylko woła komendy Tauri (src/lib/tauri.ts) i renderuje wynik.
  • W przeglądarce (poza Tauri, npm run dev bez tauri dev) lib/tauri.ts przełącza się na dane mockowe, żeby dało się developować UI bez podmana.

Co jeszcze wymaga rozbudowy

To był i jest w dużej mierze mockup UI poza samym Store, który teraz faktycznie mówi do pacmana — reszta (terminal, wykres ruchu, lista "zagrożeń") to nadal dane zaszyte na sztywno. Do wersji, która faktycznie nadaje się dla zespołu red-team w środowisku korporacyjnym, potrzeba świadomie zaprojektowanej warstwy backendowej — to nie jest coś, co da się "dopisać" bezmyślnie w komponencie:

  1. Autentykacja i autoryzacja operatora — appka otwiera się od razu w trybie "root", bez logowania. W środowisku korporacyjnym potrzebny jest ekran logowania, integracja z SSO/LDAP firmy, oraz podział na role (operator / lead / audytor tylko-do-odczytu) — w tym kto w ogóle ma prawo instalować pakiety przez Store.
  2. Bezpieczeństwo kontenera Store — dziś ensure_container tworzy kontener z domyślnymi ustawieniami sieci (pełny dostęp) i bez limitów zasobów. Do użytku firmowego: rootless podman, ograniczona sieć (proxy przez firmowy egress zamiast pełnego internetu), limity CPU/RAM, read-only rootfs poza katalogiem roboczym, oraz decyzja czy instalacja pakietów wymaga zatwierdzenia (np. allowlist pakietów zamiast pełnego dostępu do repo BlackArch).
  3. Progres instalacji w czasie rzeczywistyminstall_package dziś czeka na zakończenie pacman -S i dopiero wtedy zwraca wynik. Realny pasek postępu wymaga strumieniowania stdout pacmana do frontendu przez eventy Tauri (app.emit() + listen() po stronie Solid), nie tylko spinnera "instaluję...".
  4. Prawdziwe źródło danych dla reszty appki — CVE, alerty, wykres ruchu sieciowego to dziś stałe wartości. Docelowo: backend Rust jako pośrednik do wewnętrznych systemów firmy (SIEM, EDR, wewnętrzna baza CVE) — nigdy bezpośrednio z frontendu do internetu.
  5. Kontrakt IPC (ipc/) — wciąż pusty placeholder, mimo że Store już ma 9 komend Tauri z własnymi typami (Package, Category). Warto ustalić wspólne typy request/response między Solid.js a Rust (np. przez specta), zanim liczba komend urośnie dalej.
  6. Terminal — nadal symulacja z zaszytymi odpowiedziami, całkiem niepodłączona do kontenera Store, który już naprawdę istnieje. Podłączenie realnej powłoki w tym samym kontenerze podman (np. przez portable-pty po stronie Rust) to osobna decyzja bezpieczeństwa — sandboxing, logowanie każdej sesji, jasna polityka uprawnień.
  7. Audyt i logowanie działań — w środowisku korpo każda akcja operatora (instalacja/usunięcie pakietu, skan, eksport raportu) powinna trafiać do logu z timestampem i tożsamością operatora, najlepiej po stronie backendu (żeby log nie dało się podmienić z poziomu frontendu).
  8. Podpisywanie i dystrybucja buildówtauri.conf.json nie ma konfiguracji code-signing. Do dystrybucji w firmie potrzebny jest certyfikat (macOS notarization, Windows Authenticode) oraz pipeline CI/CD budujący i podpisujący binarki dla wszystkich platform.
  9. Aktualizacje — brak tauri-plugin-updater. Warto dodać, żeby appka (i lista dostępnych kategorii/pakietów) mogła się aktualizować bez ręcznej redystrybucji.
  10. Testy — zero testów, teraz już przy realnej logice (parsowanie wyjścia pacman -Ss/-Si w blackarch.rs, stany instalacji w Store.tsx) to nie jest opcjonalne. Parsery tekstowe pacmana są szczególnie kruche na zmiany formatu między wersjami — potrzebują testów jednostkowych z przykładowym wyjściem.

Chętnie wejdę głębiej w którykolwiek z powyższych punktów — powiedz, od którego zacząć (np. streaming postępu instalacji, bo widać go najszybciej w UI, albo bezpieczeństwo kontenera, bo to fundament dla reszty).

Runda 2 — zrobione w tej iteracji

Wszystkie 9 punktów z listy wyżej zaadresowane. Tauri v2 (bez zmian — tauri = "2" w Cargo.toml, @tauri-apps/api v2 we frontendzie).

  1. Terminal → prawdziwy PTY (source-code/backend/src/pty.rs) — portable-pty spawnuje podman exec -it blackarch-redteam bash, stdout/stderr strumieniowane do frontendu eventem pty://output, wejście operatora idzie przez komendę pty_write. Terminal.tsx przepisany na konsumenta tego strumienia zamiast zaszytych odpowiedzi.
  2. Audit log (src/audit.rs) — append-only JSONL w katalogu danych appki (~/.local/share/cybersecurity-mode/audit.jsonl na Linuksie). Każda mutująca akcja (login/logout, tworzenie kontenera, instalacja/ usunięcie/odrzucenie pakietu, zmiana allowlisty) loguje operatora, timestamp i szczegóły. Podgląd ostatnich wpisów w panelu Analytics.
  3. Code-signing i dystrybucjatauri.conf.json ma teraz sekcje bundle.macOS/bundle.windows z polami na certyfikat oraz plugins.updater z endpointem i kluczem publicznym (placeholdery do podmiany). Pełny przepis krok-po-kroku (generowanie klucza, notarization, Authenticode) w SIGNING.md. Szkielet pipeline'u w .github/workflows/release.yml.
  4. Aktualizacjetauri-plugin-updater dodany po stronie Rust (lib.rs) i JS (@tauri-apps/plugin-updater). lib/tauri.ts eksportuje checkForUpdate()/downloadAndInstallUpdate(); header appki pokazuje przycisk "Aktualizacja X.Y.Z", gdy nowa wersja jest dostępna.
  5. Testy — Rust: #[cfg(test)] w blackarch.rs z przykładowym wyjściem pacman -Ss/-Si (w tym przypadek pustego/uszkodzonego wejścia) — cargo test. Frontend: vitest skonfigurowany (npm run test), przykład na wyodrębnionej czystej funkcji (lib/networkScale.ts + lib/__tests__/networkScale.test.ts).
  6. Auth / role (src/auth.rs) — appka nie startuje już w trybie "root", tylko pokazuje ekran logowania (Login.tsx), dopóki current_session() nie zwróci sesji. Logowanie idzie przez systemowy PAM — dokładnie to samo konto i hasło co do su/konsoli na tym hoście (moduł pam_unix, weryfikacja hasła przez setuid-root unix_chkpwd, appka NIE musi być rootem). Jeśli host ma PAM/NSS podpięte pod firmowe LDAP/SSSD/Kerberos, appka loguje przez to źródło automatycznie — nie ma już własnej bazy loginów do zarządzania. Rola (Operator/Lead/Auditor) wynika z przynależności do grup uniksowych (redteam-lead/redteam-operator, nazwy nadpisywalne zmiennymi środowiskowymi — patrz komentarz modułu).
  7. Bezpieczeństwo kontenera Storeensure_container tworzy teraz kontener z --cap-drop=ALL, --security-opt no-new-privileges, twardym limitem --memory 2g --cpus 2. Dodana allowlist pakietów (get_allowlist/set_allowlist, zarządzana przez rolę Lead) — domyślnie allow_all: true (żeby Store działał od razu), ale gotowa do zawężenia do zatwierdzonego zestawu narzędzi. Rootless podman i ograniczenie sieci do firmowego egress proxy zostają jako kolejny krok — patrz pkt niżej.
  8. Progres instalacji w czasie rzeczywistyminstall_package, remove_package i ensure_container strumieniują teraz stdout/stderr procesu przez event store://progress zamiast czekać w ciszy; Store.tsx renderuje log na żywo (ekran onboardingu + pasek podczas instalacji/usuwania).
  9. Prawdziwe źródła danych (src/threat_feed.rs) — NetworkMonitor czyta teraz realne I/O kontenera przez podman stats --format json zamiast losowych słupków. Analytics woła get_threat_feed(), które uczciwie zwraca pustą listę / błąd zamiast zmyślonych CVE, dopóki nikt nie skonfiguruje threat_feed.json/source_url — podpięcie realnego SIEM/CVE API to świadomie zostawiony, oznaczony TODO krok (wymaga dodania klienta HTTP, np. reqwest).

Ważne przed pierwszym uruchomieniem

  • Uruchamiaj tauri (CLI) tylko przez npm run tauri ... z source-code/frontend — skrypt w package.json sam robi cd ../backend przed odpaleniem CLI. Jeśli wywołasz tauri/npx tauri bezpośrednio z innego katalogu, dostaniesz błąd "Couldn't recognize the current folder as a Tauri project" — to ograniczenie samego Tauri CLI (szuka configu tylko w podkatalogach bieżącego katalogu), nie bug w tym repo. make dev / make build używają tej samej ścieżki.
  • beforeDevCommand/beforeBuildCommand używają jawnej formy obiektowej { "cwd": "../frontend", "script": "..." }, nie samego stringa z --prefix. Tauri CLI ma udokumentowaną, mylącą zasadę ustalania cwd dla wersji string-owej (liczy je względem najbliższego package.json od strony CLI, nie względem tauri.conf.json) — patrz tauri-apps/tauri#3551. Efekt uboczny: npm run build --prefix ../frontend potrafi rozwiązać się o katalog za wysoko (np. cybersec-mode/frontend zamiast cybersec-mode/source-code/frontend) i wywalić się z ENOENT. Forma obiektowa z cwd jest liczona względem lokalizacji tauri.conf.json (czyli source-code/backend), więc "cwd": "../frontend" jednoznacznie wskazuje source-code/frontend — bez zgadywania.
  • Logowanie = konto systemowe tego hosta (PAM), nie osobna baza. Zaloguj się loginem/hasłem dowolnego użytkownika Linuksa, który już istnieje na maszynie uruchamiającej appkę. Domyślnie appka odwołuje się do usługi PAM login (nadpisywalne zmienną CYBERSEC_MODE_PAM_SERVICE, np. na Fedorze warto ustawić system-auth). Żeby ktoś dostał rolę Operator albo Lead zamiast domyślnego Auditor (tylko podgląd), dodaj go do grupy: sudo usermod -aG redteam-operator <użytkownik> (albo redteam-lead) — nazwy grup też nadpisywalne (CYBERSEC_MODE_OPERATOR_GROUP, CYBERSEC_MODE_LEAD_GROUP). Kompilacja wymaga nagłówków PAM w systemie: Debian/Ubuntu sudo apt install libpam0g-dev, Fedora/RHEL sudo dnf install pam-devel, Arch zwykle ma je już z pakietu pam.
  • plugins.updater.pubkey i endpoints w tauri.conf.json to placeholdery — appka nie znajdzie aktualizacji, dopóki nie wygenerujesz klucza i nie podepniesz prawdziwego endpointu (patrz SIGNING.md).
  • threat_feed.json nie istnieje domyślnie — panel Analytics uczciwie pokaże "brak podpiętego źródła", dopóki go nie skonfigurujesz.

Co dalej (nowe punkty po tej rundzie)

  • Rootless podman + ograniczenie sieci kontenera do firmowego egress proxy.
  • Realny klient HTTP w threat_feed.rs (dziś tylko kontrakt + TODO).
  • Pełne nagrywanie sesji terminala do audit logu (dziś logujemy tylko start/koniec sesji, nie treść — to świadoma decyzja do podjęcia osobno, bo dotyczy prywatności operatora i wolumenu logów).
  • Realna integracja OIDC/LDAP na poziomie appki, jeśli PAM+SSSD na hoście kiedyś przestanie wystarczać (dziś: PAM już pośrednio to ogarnia, jeśli host ma SSSD/LDAP skonfigurowane — patrz punkt 6 wyżej).
  • Kontrakt w ipc/ — wciąż pusty, a komend Tauri przybyło (auth, audit, pty, threat_feed) — coraz bardziej warto to ustandaryzować.

Runda 3 — poprawki po pierwszym realnym buildzie

  • Zła nazwa obrazu kontenerablackarch/blackarch nie istnieje; poprawny, oficjalny obraz to blackarchlinux/blackarch (publikowany przez BlackArch/blackarch-docker). To był najpewniejszy powód błędu "Proces podman zakończył się kodem Some(125)" przy pierwszym tworzeniu kontenera (manifest unknown przy próbie ściągnięcia nieistniejącego obrazu).
  • ensure_container używa teraz podman run --replace, więc nieudana poprzednia próba (zawieszony/martwy kontener o tej samej nazwie) już nie blokuje kolejnej próby błędem "name already in use".
  • run_streaming zbiera teraz ostatnie linie stdout/stderr i dołącza je do zwracanego błędu — kolejne awarie tego typu pokażą realny komunikat podmana/pacmana, nie tylko gołą liczbę kodu wyjścia.
  • Auth przepisany na PAM (src/auth.rs) — appka nie ma już własnej bazy loginów (operators.json, Argon2, seed admin/changeme — to wszystko usunięte). Logowanie idzie przez systemowy PAM, czyli realne konto systemowe tego hosta; patrz punkt 6 w "Runda 2" wyżej (zaktualizowany) po szczegóły i zmienne środowiskowe do konfiguracji grup/usługi PAM.

Releases

Packages

Contributors

Languages