mirror of
https://github.com/BishopFox/sliver.git
synced 2026-11-08 08:04:14 -10:00
Compare commits
110
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
205f5b4196 | ||
|
|
0bbecc16ec | ||
|
|
0c216161c2 | ||
|
|
8ad9c62eb5 | ||
|
|
4c99fbfd82 | ||
|
|
ed713e199c | ||
|
|
aacdb71c4a | ||
|
|
6968c3aae5 | ||
|
|
410fd93025 | ||
|
|
f2a0435dd2 | ||
|
|
d66ec956a4 | ||
|
|
8229722735 | ||
|
|
dcd81a4db7 | ||
|
|
2617387417 | ||
|
|
56aee7d6e4 | ||
|
|
b4f07e8629 | ||
|
|
280cb34049 | ||
|
|
8e5c5f1450 | ||
|
|
b8f4f0c1ea | ||
|
|
17cb7fbd50 | ||
|
|
9963bc6a3f | ||
|
|
274943f383 | ||
|
|
be81755056 | ||
|
|
a5861c43f2 | ||
|
|
e3025a2da2 | ||
|
|
40cc1f4eeb | ||
|
|
b117a1325d | ||
|
|
a809989536 | ||
|
|
a9ee3ca9ed | ||
|
|
56d972dd32 | ||
|
|
b4091264d7 | ||
|
|
23bf325a66 | ||
|
|
d9344a4c79 | ||
|
|
67d9a772e3 | ||
|
|
dae284e62e | ||
|
|
60f48bdc51 | ||
|
|
0d7885de29 | ||
|
|
d41d29fc1e | ||
|
|
3f400bd3f0 | ||
|
|
d43f664821 | ||
|
|
85c57c07da | ||
|
|
60d15447e0 | ||
|
|
6351b2d671 | ||
|
|
c7535ec509 | ||
|
|
67e17d073b | ||
|
|
c5cb4dcb6c | ||
|
|
0b9fe603a8 | ||
|
|
c7141892d1 | ||
|
|
c5556f9e2b | ||
|
|
1bc45c2ab2 | ||
|
|
739ad98b81 | ||
|
|
95c1697d1b | ||
|
|
f7b9571cfc | ||
|
|
0d08f8c62f | ||
|
|
aa9c8d89e9 | ||
|
|
152e60ba29 | ||
|
|
d13a71b808 | ||
|
|
b17e2f056f | ||
|
|
42fb1e835e | ||
|
|
521356ff6e | ||
|
|
74b5d720b2 | ||
|
|
cd75545323 | ||
|
|
396dc9724f | ||
|
|
33398146d3 | ||
|
|
21039554e5 | ||
|
|
cca73be1c8 | ||
|
|
596bc455d8 | ||
|
|
400c36c5df | ||
|
|
c94dde3efb | ||
|
|
827a9ca156 | ||
|
|
d066dbc49a | ||
|
|
f1fbc345a2 | ||
|
|
2889c1ee29 | ||
|
|
28ee216b36 | ||
|
|
2dd3e84f60 | ||
|
|
067cdf712d | ||
|
|
22ae941e17 | ||
|
|
7c0c2c2dda | ||
|
|
39de742223 | ||
|
|
b07e750cf5 | ||
|
|
8786979001 | ||
|
|
aa223e4488 | ||
|
|
8785c55cf3 | ||
|
|
38fa64d266 | ||
|
|
b04fff21fd | ||
|
|
3f656da786 | ||
|
|
55311868a7 | ||
|
|
422a1d39c3 | ||
|
|
6938759e9d | ||
|
|
5febe5e539 | ||
|
|
38479e34aa | ||
|
|
abe8f8e77b | ||
|
|
c0f3161525 | ||
|
|
c6bbba16e1 | ||
|
|
af4f99de51 | ||
|
|
8e6e8e18ad | ||
|
|
544e577eb2 | ||
|
|
9939d2c320 | ||
|
|
f47af1e94e | ||
|
|
d3302583f5 | ||
|
|
d9403c7f05 | ||
|
|
65eb72506b | ||
|
|
d86cdcad8e | ||
|
|
7d7f858c15 | ||
|
|
ee1ad9edd1 | ||
|
|
927ff9c4ab | ||
|
|
87dfe96ee9 | ||
|
|
5bb4338d76 | ||
|
|
bb35fa56d6 | ||
|
|
fbab18b2fe |
No files matched your search
@@ -1,4 +1,9 @@
|
||||
# go-assets.sh downloads
|
||||
/server/assets/fs/**.zip
|
||||
/server/assets/fs/**/garble*
|
||||
/server/assets/fs/**/zig.tar.xz
|
||||
/server/assets/fs/**/zig.zip
|
||||
/server/assets/fs/src.zip
|
||||
|
||||
/*.sdk.tar.xz
|
||||
|
||||
@@ -19,3 +24,5 @@
|
||||
/SECURITY.md
|
||||
/README.md
|
||||
/CONTRIBUTING.md
|
||||
|
||||
.downloaded_assets
|
||||
@@ -11,10 +11,10 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
- name: Go 1.21
|
||||
uses: actions/setup-go@v5
|
||||
- name: Go 1.25
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: "^1.21"
|
||||
go-version: "^1.25"
|
||||
|
||||
- name: OS Packages
|
||||
run: |
|
||||
@@ -22,7 +22,7 @@ jobs:
|
||||
git build-essential zlib1g zlib1g-dev wget zip unzip
|
||||
|
||||
- name: Check Out Code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Git Fetch Tags
|
||||
run: git fetch --prune --unshallow --tags -f
|
||||
@@ -31,7 +31,7 @@ jobs:
|
||||
run: make servers
|
||||
|
||||
- name: Server Artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: servers
|
||||
path: ./sliver-server_*
|
||||
@@ -42,13 +42,13 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
- name: Go 1.22
|
||||
uses: actions/setup-go@v5
|
||||
- name: Go 1.25
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: "^1.22"
|
||||
go-version: "^1.25"
|
||||
|
||||
- name: Check Out Code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Git Fetch Tags
|
||||
run: git fetch --prune --unshallow --tags -f
|
||||
@@ -57,7 +57,7 @@ jobs:
|
||||
run: make clients
|
||||
|
||||
- name: Client Artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: clients
|
||||
path: ./sliver-client_*
|
||||
@@ -72,7 +72,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- run: mkdir -p ./builds
|
||||
- uses: actions/download-artifact@v4
|
||||
- uses: actions/download-artifact@v6
|
||||
with:
|
||||
path: ./builds
|
||||
|
||||
|
||||
@@ -16,13 +16,13 @@ jobs:
|
||||
|
||||
steps:
|
||||
# Setup go environment
|
||||
- name: Go 1.22
|
||||
uses: actions/setup-go@v5
|
||||
- name: Go 1.25
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: "^1.22"
|
||||
go-version: "^1.25"
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
# Must fetch at least the immediate parents so that if this is
|
||||
# a pull request then we can checkout the head of the pull request.
|
||||
@@ -36,10 +36,10 @@ jobs:
|
||||
git build-essential zlib1g zlib1g-dev wget zip unzip
|
||||
|
||||
- name: Check Out Code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v3
|
||||
uses: github/codeql-action/init@v4
|
||||
with:
|
||||
config-file: ./.github/codeql/codeql-config.yml
|
||||
languages: go
|
||||
@@ -48,6 +48,6 @@ jobs:
|
||||
run: make
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v3
|
||||
uses: github/codeql-action/analyze@v4
|
||||
env:
|
||||
VERSION: ${{github.sha}}
|
||||
@@ -35,7 +35,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Detect package manager
|
||||
id: detect-package-manager
|
||||
@@ -56,7 +56,7 @@ jobs:
|
||||
fi
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
cache: "npm"
|
||||
cache-dependency-path: "**/package-lock.json"
|
||||
@@ -85,7 +85,7 @@ jobs:
|
||||
run: ${{ steps.detect-package-manager.outputs.runner }} next build
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-pages-artifact@v3
|
||||
uses: actions/upload-pages-artifact@v4
|
||||
with:
|
||||
path: ${{ github.workspace }}/docs/sliver-docs/out
|
||||
|
||||
|
||||
@@ -21,12 +21,12 @@ jobs:
|
||||
linux-windows-build-test:
|
||||
name: Linux & Windows Test
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 90
|
||||
timeout-minutes: 180
|
||||
steps:
|
||||
- name: Go 1.22
|
||||
uses: actions/setup-go@v5
|
||||
- name: Go 1.25
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: "^1.22"
|
||||
go-version: "^1.25"
|
||||
|
||||
- name: OS Packages
|
||||
run: |
|
||||
@@ -34,38 +34,36 @@ jobs:
|
||||
git build-essential zlib1g zlib1g-dev wget zip unzip
|
||||
|
||||
- name: Check Out Code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Git Fetch Tags
|
||||
run: git fetch --prune --unshallow --tags -f
|
||||
|
||||
- name: Make Linux (amd64)
|
||||
run: make linux-amd64
|
||||
|
||||
- name: Test Linux
|
||||
run: ./sliver-server unpack --force && ./go-tests.sh
|
||||
|
||||
- name: Make Windows (amd64)
|
||||
run: make windows-amd64
|
||||
|
||||
- name: Make Linux (arm64)
|
||||
run: make linux-arm64
|
||||
|
||||
- name: Make Linux (amd64)
|
||||
run: make linux-amd64
|
||||
|
||||
- name: Test Linux
|
||||
run: make clean && make && ./sliver-server unpack --force && ./go-tests.sh
|
||||
|
||||
|
||||
macos-build-test:
|
||||
name: MacOS Test
|
||||
runs-on: macos-latest
|
||||
timeout-minutes: 90
|
||||
timeout-minutes: 180
|
||||
steps:
|
||||
- name: Go 1.22
|
||||
uses: actions/setup-go@v5
|
||||
- name: Go 1.25
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: "^1.22"
|
||||
|
||||
- name: Mingw
|
||||
run: brew install mingw-w64
|
||||
go-version: "^1.25"
|
||||
|
||||
- name: Check Out Code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Git Fetch Tags
|
||||
run: git fetch --prune --unshallow --tags -f
|
||||
@@ -73,24 +71,24 @@ jobs:
|
||||
- name: Make MacOS (amd64)
|
||||
run: make macos-amd64
|
||||
|
||||
- name: Test MacOS (amd64)
|
||||
run: ./sliver-server unpack --force && ./go-tests.sh
|
||||
|
||||
- name: Make MacOS (arm64)
|
||||
run: make macos-arm64
|
||||
|
||||
- name: Test MacOS
|
||||
run: make clean && make && ./sliver-server unpack --force && ./go-tests.sh
|
||||
|
||||
clients-build:
|
||||
name: Clients Build
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 90
|
||||
steps:
|
||||
- name: Go 1.22
|
||||
uses: actions/setup-go@v5
|
||||
- name: Go 1.25
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: "^1.22"
|
||||
go-version: "^1.25"
|
||||
|
||||
- name: Check Out Code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Git Fetch Tags
|
||||
run: git fetch --prune --unshallow --tags -f
|
||||
|
||||
@@ -45,6 +45,8 @@ sliver-server-windows.zip
|
||||
.DS_Store
|
||||
|
||||
dist/
|
||||
.gocache/
|
||||
.gomodcache/
|
||||
|
||||
# Flag to show that go-assets.sh has been run
|
||||
.downloaded_assets
|
||||
@@ -0,0 +1,41 @@
|
||||
# Repository Guidelines
|
||||
|
||||
## Project Structure & Module Organization
|
||||
- `client/` holds the CLI client and interactive commands.
|
||||
- `server/` contains the server runtime, C2 logic, configs, and web assets.
|
||||
- `implant/` is the implant runtime and transport implementations.
|
||||
- `protobuf/` stores protobuf definitions and generated Go types.
|
||||
- `util/` is shared helpers (crypto, encoders, minisign, etc.).
|
||||
- `docs/sliver-docs/` is the Next.js documentation site and prebuild scripts.
|
||||
- `vendor/` is the vendored Go dependency tree used by builds.
|
||||
- Build outputs land in the repo root as `sliver-client*` and `sliver-server*`.
|
||||
|
||||
## Build, Test, and Development Commands
|
||||
- `make` builds server + client using vendored modules and runs `go-assets.sh`.
|
||||
- `make client` builds a CGO-free client; `make debug` keeps symbols.
|
||||
- `make pb` regenerates protobuf stubs from `protobuf/`.
|
||||
- `./go-tests.sh` runs the curated Go test suite with build tags.
|
||||
- Docs site: `cd docs/sliver-docs && npm install && npm run dev` for local dev; `npm run build` for a static build.
|
||||
- Go toolchain: the Makefile enforces Go >= 1.24.
|
||||
|
||||
## Coding Style & Naming Conventions
|
||||
- Run `gofmt` on all Go code; keep package names lowercase and idiomatic.
|
||||
- Avoid `CGO` and empty interfaces; prefer explicit types and interfaces.
|
||||
- Do not import `server` packages from `client`.
|
||||
- If `math/rand` is required, import it as `insecureRand` and avoid security use.
|
||||
|
||||
## Testing Guidelines
|
||||
- Go tests follow standard `_test.go` naming within each package.
|
||||
- Prefer `./go-tests.sh` (uses tags like `client`, `server`, `osusergo`, `netgo`, `go_sqlite`) to match CI expectations.
|
||||
- Add or update tests when behavior changes; some server packages run longer tests.
|
||||
|
||||
## Commit & Pull Request Guidelines
|
||||
- Commits must be signed for PRs to `master`; work in a feature branch.
|
||||
- Commit subjects are short and imperative (e.g., "Fix ...", "Add ...", "Update ...", "Bump ...").
|
||||
- Changes to `vendor/` should be in a distinct commit.
|
||||
- PRs should link the tracking issue, note tests run, and confirm `gofmt` plus unit tests as applicable.
|
||||
|
||||
## Security Notes
|
||||
- Default to secure configuration; fail closed rather than open.
|
||||
- Avoid insecure algorithms (MD5/SHA1/AES-ECB); prefer AES-GCM and modern curves.
|
||||
- Treat user input as untrusted: canonicalize paths and use restrictive file permissions.
|
||||
+3
-3
@@ -9,7 +9,7 @@
|
||||
|
||||
# STAGE: base
|
||||
## Compiles Sliver for use
|
||||
FROM golang:1.23.5 AS base
|
||||
FROM golang:latest AS base
|
||||
|
||||
### Base packages
|
||||
RUN apt-get update --fix-missing && apt-get -y install \
|
||||
@@ -20,10 +20,10 @@ RUN groupadd -g 999 sliver && useradd -r -u 999 -g sliver sliver
|
||||
RUN mkdir -p /home/sliver/ && chown -R sliver:sliver /home/sliver
|
||||
|
||||
### Build sliver:
|
||||
RUN mkdir -p /go/src/github.com/bishopfox/sliver
|
||||
WORKDIR /go/src/github.com/bishopfox/sliver
|
||||
ADD . /go/src/github.com/bishopfox/sliver/
|
||||
RUN make clean-all
|
||||
RUN make
|
||||
RUN make
|
||||
RUN cp -vv sliver-server /opt/sliver-server
|
||||
|
||||
# STAGE: test
|
||||
|
||||
@@ -27,7 +27,7 @@ GO_VERSION = $(shell $(GO) version)
|
||||
GO_MAJOR_VERSION = $(shell $(GO) version | cut -c 14- | cut -d' ' -f1 | cut -d'.' -f1)
|
||||
GO_MINOR_VERSION = $(shell $(GO) version | cut -c 14- | cut -d' ' -f1 | cut -d'.' -f2)
|
||||
MIN_SUPPORTED_GO_MAJOR_VERSION = 1
|
||||
MIN_SUPPORTED_GO_MINOR_VERSION = 21
|
||||
MIN_SUPPORTED_GO_MINOR_VERSION = 24
|
||||
GO_VERSION_VALIDATION_ERR_MSG = Golang version is not supported, please update to at least $(MIN_SUPPORTED_GO_MAJOR_VERSION).$(MIN_SUPPORTED_GO_MINOR_VERSION)
|
||||
|
||||
VERSION ?= $(shell git describe --abbrev=0)
|
||||
|
||||
+23
-15
@@ -1,18 +1,26 @@
|
||||
Client
|
||||
=======
|
||||
# client
|
||||
|
||||
This directory contains the client implementation, pretty much all of this code is also used by the server console.
|
||||
## Overview
|
||||
|
||||
__Important:__ No code in this directory can import any code from `server/`.
|
||||
Main command-line client for interacting with and administering Sliver servers. Provides the Cobra entrypoint and aggregates console, command, and transport subsystems.
|
||||
|
||||
* `assets/` - Static asset files and management code (e.g. client configs)
|
||||
* `cli/` - Command line interface implementation
|
||||
* `command/` - Console command implementations
|
||||
* `constants/` - Various shared constant values
|
||||
* `core/` - Client state management
|
||||
* `licenses/` - Open source licenses
|
||||
* `spin/` - Console spinner library
|
||||
* `tcpproxy/` - Local TCP proxy listener code
|
||||
* `transport/` - Wires the client to the server
|
||||
* `version/` - Version information
|
||||
* `main.go` - Entrypoint
|
||||
## Go Files
|
||||
|
||||
- `main.go` – Entry point that initializes the CLI, processes flags, and launches the interactive console.
|
||||
|
||||
## Sub-packages
|
||||
|
||||
- `assets/` – Manages embedded client asset manifests such as operator profiles, settings, and armory catalogs. Handles serialization, bundling, and lookup of static client metadata.
|
||||
- `cli/` – Defines the Cobra root command and CLI initialization for the Sliver client binary. Sets up persistent flags, environment bootstrapping, and command wiring.
|
||||
- `command/` – Shared registration glue, scaffolding, and helpers for Sliver client console command groups. Hosts common utilities for binding Cobra commands to RPC-backed actions.
|
||||
- `console/` – Renders the interactive console UI, logging, and terminal helpers for the client. Coordinates readline behavior, prompt styling, and message formatting.
|
||||
- `constants/` – Centralizes constants shared across the client runtime and command packages. Captures strings, flag names, and feature toggles used throughout the CLI.
|
||||
- `core/` – Maintains client application state, background workers, and RPC coordination. Orchestrates session tracking, event streams, and health checks.
|
||||
- `credentials/` – Credential management utilities including sniffers and import helpers for operators. Provides parsers, storage helpers, and output formatting for recovered secrets.
|
||||
- `licenses/` – Holds embedded license metadata bundled with the client distribution. Supplies license retrieval utilities used for attribution commands.
|
||||
- `overlord/` – Supervises long-running client jobs, scheduling, and task orchestration. Tracks job lifecycle events and exposes status updates to the console.
|
||||
- `packages/` – Deals with packaged extensions and module discovery for the client. Scans, validates, and caches extension manifests and assets.
|
||||
- `spin/` – Lightweight terminal spinner utilities used for progress feedback. Wraps spinner styles and timing helpers shared across commands.
|
||||
- `tcpproxy/` – Implements the local TCP proxy used for port forwarding from the client side. Manages listener lifecycles, connection pumps, and cleanup hooks.
|
||||
- `transport/` – Client-side transports and RPC wiring to communicate with Sliver servers. Builds authenticated gRPC clients, TLS dialers, and reconnect logic.
|
||||
- `version/` – Build-time version and semantic metadata for the client binary. Exposes git information, release channels, and helper formatters.
|
||||
+14
-2
@@ -1,3 +1,15 @@
|
||||
Assets
|
||||
======
|
||||
# client/assets
|
||||
|
||||
## Overview
|
||||
|
||||
Manages embedded client asset manifests such as operator profiles, settings, and armory catalogs. Handles serialization, bundling, and lookup of static client metadata. Core logic addresses aliases, armories, C2 profiles, and extensions within the assets package.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `aliases.go` – Provides helpers for discovering, installing, and reading alias manifests shipped with the client.
|
||||
- `armories.go` – Loads configured armory definitions and persists operator customizations.
|
||||
- `assets.go` – Central entry point that exposes asset directories, lazy initialization, and filesystem utilities.
|
||||
- `c2profiles.go` – Embeds default HTTP C2 profile templates and exposes lookup utilities.
|
||||
- `config.go` – Tracks client configuration paths and manages persistence of runtime options.
|
||||
- `extensions.go` – Handles embedded extension manifests and supports lookup by command name.
|
||||
- `settings.go` – Stores default console settings and manages serialization to disk.
|
||||
@@ -96,7 +96,7 @@ func Setup(force bool, echo bool) {
|
||||
if force || localVer == "" || localVer != ver.GitCommit {
|
||||
if echo {
|
||||
fmt.Printf(`
|
||||
Sliver Copyright (C) 2022 Bishop Fox
|
||||
Sliver Copyright (C) 2025 Bishop Fox
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type 'licenses'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type 'licenses' for details.`)
|
||||
|
||||
+13
-3
@@ -1,4 +1,14 @@
|
||||
CLI
|
||||
===
|
||||
# client/cli
|
||||
|
||||
This package implements the Sliver client cli.
|
||||
## Overview
|
||||
|
||||
Defines the Cobra root command and CLI initialization for the Sliver client binary. Sets up persistent flags, environment bootstrapping, and command wiring. Core logic addresses console, implant, import, and version within the cli package.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `cli.go` – Builds the root Cobra command, wires global flags, and starts the console UI.
|
||||
- `config.go` – Parses CLI configuration files and environment variables used during startup.
|
||||
- `console.go` – Launches the interactive console mode and handles profile selection.
|
||||
- `implant.go` – Implements CLI entry points for implant-specific operations without launching the console.
|
||||
- `import.go` – Provides import routines for bringing external state into the client (e.g., implants or loot).
|
||||
- `version.go` – Prints version/build information for the CLI binary.
|
||||
+62
-11
@@ -1,14 +1,65 @@
|
||||
Command
|
||||
=======
|
||||
# client/command
|
||||
|
||||
This package contains all of the client command implementations that are shared between the client and the server console.
|
||||
## Overview
|
||||
|
||||
### Developers
|
||||
Shared registration glue, scaffolding, and helpers for Sliver client console command groups. Hosts common utilities for binding Cobra commands to RPC-backed actions. Core logic addresses sliver within the command package.
|
||||
|
||||
General guidance on the structure of this package:
|
||||
* One command per file and the name of the file should reflect the command it implements (or there about, trivial commands can go into the same file). This makes it easy to find where a command implementation lives within a package or to search by file name if it is not clear which package implements a given command.
|
||||
* The root command, and reused code should go into the file named after the command
|
||||
* For example, code shared between the `generate` and the `regenerate` command should go in `generate.go`, and any `regenerate` specific code should go in `regenerate.go`
|
||||
* Command entrypoint functions should have the suffix `Cmd` e.g., `GenerateCmd` is the entrypoint for `generate`
|
||||
* Command entrypoints should always a function signature of `func (ctx *grumble.Context, con *console.SliverConsoleClient)`
|
||||
* Functions that are only ever exported for other commands to use should go in a `helpers.go`, if the function is used internally and exported follow the guidance above on shared code.
|
||||
## Go Files
|
||||
|
||||
- `command.go` – Provides helpers for binding Cobra commands, flag sets, and visibility filters into the client command tree.
|
||||
- `server.go` – Defines the server menu composition, wiring each server-side command group onto the root console structure at runtime.
|
||||
- `sliver.go` – Builds the implant/Sliver menu, attaching per-target command groups and loading alias/extension manifests before exposure.
|
||||
|
||||
## Sub-packages
|
||||
|
||||
- `alias/` – Implements the 'alias' command group for the Sliver client console.
|
||||
- `armory/` – Implements the 'armory' command group for the Sliver client console.
|
||||
- `backdoor/` – Implements the 'backdoor' command group for the Sliver client console.
|
||||
- `beacons/` – Implements the 'beacons' command group for the Sliver client console.
|
||||
- `builders/` – Implements the 'builders' command group for the Sliver client console.
|
||||
- `c2profiles/` – Implements the 'c2profiles' command group for the Sliver client console.
|
||||
- `certificates/` – Implements the 'certificates' command group for the Sliver client console.
|
||||
- `clean/` – Implements the 'clean' command group for the Sliver client console.
|
||||
- `completers/` – Implements the 'completers' command group for the Sliver client console.
|
||||
- `crack/` – Implements the 'crack' command group for the Sliver client console.
|
||||
- `creds/` – Implements the 'creds' command group for the Sliver client console.
|
||||
- `cursed/` – Implements the 'cursed' command group for the Sliver client console.
|
||||
- `dllhijack/` – Implements the 'dllhijack' command group for the Sliver client console.
|
||||
- `environment/` – Implements the 'environment' command group for the Sliver client console.
|
||||
- `exec/` – Implements the 'exec' command group for the Sliver client console.
|
||||
- `exit/` – Implements the 'exit' command group for the Sliver client console.
|
||||
- `extensions/` – Implements the 'extensions' command group for the Sliver client console.
|
||||
- `filesystem/` – Implements the 'filesystem' command group for the Sliver client console.
|
||||
- `flags/` – Implements the 'flags' command group for the Sliver client console.
|
||||
- `generate/` – Implements the 'generate' command group for the Sliver client console.
|
||||
- `help/` – Implements the 'help' command group for the Sliver client console.
|
||||
- `hosts/` – Implements the 'hosts' command group for the Sliver client console.
|
||||
- `info/` – Implements the 'info' command group for the Sliver client console.
|
||||
- `jobs/` – Implements the 'jobs' command group for the Sliver client console.
|
||||
- `kill/` – Implements the 'kill' command group for the Sliver client console.
|
||||
- `licenses/` – Implements the 'licenses' command group for the Sliver client console.
|
||||
- `loot/` – Implements the 'loot' command group for the Sliver client console.
|
||||
- `monitor/` – Implements the 'monitor' command group for the Sliver client console.
|
||||
- `network/` – Implements the 'network' command group for the Sliver client console.
|
||||
- `operators/` – Implements the 'operators' command group for the Sliver client console.
|
||||
- `pivots/` – Implements the 'pivots' command group for the Sliver client console.
|
||||
- `portfwd/` – Implements the 'portfwd' command group for the Sliver client console.
|
||||
- `privilege/` – Implements the 'privilege' command group for the Sliver client console.
|
||||
- `processes/` – Implements the 'processes' command group for the Sliver client console.
|
||||
- `reaction/` – Implements the 'reaction' command group for the Sliver client console.
|
||||
- `reconfig/` – Implements the 'reconfig' command group for the Sliver client console.
|
||||
- `registry/` – Implements the 'registry' command group for the Sliver client console.
|
||||
- `rportfwd/` – Implements the 'rportfwd' command group for the Sliver client console.
|
||||
- `screenshot/` – Implements the 'screenshot' command group for the Sliver client console.
|
||||
- `sessions/` – Implements the 'sessions' command group for the Sliver client console.
|
||||
- `settings/` – Implements the 'settings' command group for the Sliver client console.
|
||||
- `shell/` – Implements the 'shell' command group for the Sliver client console.
|
||||
- `shikata-ga-nai/` – Implements the 'shikata-ga-nai' command group for the Sliver client console.
|
||||
- `socks/` – Implements the 'socks' command group for the Sliver client console.
|
||||
- `taskmany/` – Implements the 'taskmany' command group for the Sliver client console.
|
||||
- `tasks/` – Implements the 'tasks' command group for the Sliver client console.
|
||||
- `update/` – Implements the 'update' command group for the Sliver client console.
|
||||
- `use/` – Implements the 'use' command group for the Sliver client console.
|
||||
- `wasm/` – Implements the 'wasm' command group for the Sliver client console.
|
||||
- `websites/` – Implements the 'websites' command group for the Sliver client console.
|
||||
- `wireguard/` – Implements the 'wireguard' command group for the Sliver client console.
|
||||
@@ -1,11 +1,14 @@
|
||||
Alias
|
||||
===========
|
||||
# client/command/alias
|
||||
|
||||
Wraps external DLLs/tool in Sliver console commands.
|
||||
## Overview
|
||||
|
||||
Implements the 'alias' command group for the Sliver client console. Handlers map Cobra invocations to alias workflows such as install, load, and remove.
|
||||
|
||||
## Go Files
|
||||
|
||||
### Format
|
||||
|
||||
* `alias-dir/`
|
||||
* * `manifest.json` -
|
||||
- `alias.go` – Implements runtime alias management, printing installed aliases and exposing tab-completion helpers.
|
||||
- `alias_test.go` *(tests)* – Exercises manifest parsing logic to ensure alias metadata is interpreted correctly.
|
||||
- `commands.go` – Wires Cobra commands for listing, installing, loading, and removing aliases into the client console.
|
||||
- `install.go` – Handles installing alias bundles from directories or archives, writing manifests and payload artifacts to disk.
|
||||
- `load.go` – Loads alias manifests, validates target compatibility, and registers commands against the active console.
|
||||
- `remove.go` – Removes installed aliases, prompting for confirmation and deleting associated on-disk assets.
|
||||
@@ -114,7 +114,7 @@ func InstallFromFile(aliasGzFilePath string, aliasName string, promptToOverwrite
|
||||
} else {
|
||||
errorMsg = fmt.Sprintf("Failed to parse %s: %s\n", ManifestFileName, err)
|
||||
}
|
||||
con.PrintErrorf(errorMsg)
|
||||
con.PrintErrorf("%s", errorMsg)
|
||||
return nil
|
||||
}
|
||||
installPath := filepath.Join(assets.GetAliasesDir(), filepath.Base(manifest.CommandName))
|
||||
|
||||
@@ -311,7 +311,7 @@ func runAliasCommand(cmd *cobra.Command, con *console.SliverClient, args []strin
|
||||
} else if !aliasManifest.IsReflective {
|
||||
msgStr = " Arguments are limited to 256 characters when using the default fork/exec model for non-reflective PE payloads.\n"
|
||||
}
|
||||
con.PrintWarnf(msgStr)
|
||||
con.PrintWarnf("%s", msgStr)
|
||||
confirm := false
|
||||
prompt := &survey.Confirm{Message: "Do you want to continue?"}
|
||||
survey.AskOne(prompt, &confirm, nil)
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
# client/command/armory
|
||||
|
||||
## Overview
|
||||
|
||||
Implements the 'armory' command group for the Sliver client console. Handlers map Cobra invocations to armory workflows such as install, manage, parsers, and search.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `armory.go` – Maintains the armory cache lifecycle, fetching package metadata, verifying signatures, and presenting bundle listings.
|
||||
- `armory_test.go` *(tests)* – Placeholder for armory command tests; currently used to keep the package's test harness wired up.
|
||||
- `commands.go` – Declares the Cobra command hierarchy for armory actions and binds shared flag/completion plumbing.
|
||||
- `install.go` – Resolves dependencies and installs aliases or extensions from cached metadata, prompting when overwriting existing packages.
|
||||
- `manage.go` – Implements management helpers for viewing, adding, verifying, and persisting armory configurations.
|
||||
- `parsers.go` – Provides parsers and HTTP helpers for retrieving armory indexes and packages, including Minisign verification.
|
||||
- `search.go` – Implements the regex-driven search command that filters cached armory packages.
|
||||
- `update.go` – Calculates available package updates, presents options to the user, and orchestrates update installation.
|
||||
@@ -1,4 +1,10 @@
|
||||
Backdoor
|
||||
========
|
||||
# client/command/backdoor
|
||||
|
||||
Implements command related to `backdoor`
|
||||
## Overview
|
||||
|
||||
Implements the 'backdoor' command group for the Sliver client console.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `backdoor.go` – Implements the RPC workflow that backdoors a remote binary with Sliver shellcode for the active session.
|
||||
- `commands.go` – Registers the Cobra command, binds flags/completions, and restricts usage to applicable targets.
|
||||
@@ -1,4 +1,14 @@
|
||||
Beacons
|
||||
========
|
||||
# client/command/beacons
|
||||
|
||||
This package implements the beacons command, which can be used to list and interact with beacons.
|
||||
## Overview
|
||||
|
||||
Implements the 'beacons' command group for the Sliver client console. Handlers map Cobra invocations to beacons workflows such as prune, RM, and watch.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `beacons.go` – Retrieves beacon inventories and renders them in tabular form with optional filtering.
|
||||
- `commands.go` – Declares the beacons command set, binds flags/completions, and wires subcommands like prune, rm, and watch.
|
||||
- `helpers.go` – Provides helper RPC wrappers for selecting, fetching, and listing beacons.
|
||||
- `prune.go` – Implements the prune routine that removes stale beacon entries via the backend API.
|
||||
- `rm.go` – Removes a specific beacon by ID, coordinating confirmation and RPC teardown.
|
||||
- `watch.go` – Streams beacon events in a watch loop, handling cancellation and console interaction.
|
||||
@@ -0,0 +1,10 @@
|
||||
# client/command/builders
|
||||
|
||||
## Overview
|
||||
|
||||
Implements the 'builders' command group for the Sliver client console.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `builders.go` – Fetches external builder metadata and formats it for console display.
|
||||
- `commands.go` – Registers the builders CLI command with its flags and completion helpers.
|
||||
@@ -0,0 +1,10 @@
|
||||
# client/command/c2profiles
|
||||
|
||||
## Overview
|
||||
|
||||
Implements the 'c2profiles' command group for the Sliver client console. Handlers map Cobra invocations to c2profiles workflows such as C2 profiles.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `c2profiles.go` – Implements listing, import/export, and generation routines for HTTP C2 profiles, including protobuf/JSON conversion helpers.
|
||||
- `commands.go` – Binds the c2profiles command suite with flag handling and completions for profile management operations.
|
||||
@@ -0,0 +1,10 @@
|
||||
# client/command/certificates
|
||||
|
||||
## Overview
|
||||
|
||||
Implements the 'certificates' command group for the Sliver client console.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `certificates.go` – Retrieves certificate metadata from the server, formats expiration status, and prints results to the console.
|
||||
- `commands.go` – Registers the certificates command and binds the flags needed to query certificate inventories.
|
||||
@@ -0,0 +1,9 @@
|
||||
# client/command/clean
|
||||
|
||||
## Overview
|
||||
|
||||
Implements the 'clean' command group for the Sliver client console.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `clean.go` – Defines the clean command and its helpers that purge local build artifacts, cached profiles, and stale sessions.
|
||||
@@ -1,4 +1,9 @@
|
||||
Completers
|
||||
===========
|
||||
# client/command/completers
|
||||
|
||||
This package contains general purpose completers for the console, note that some package also contain their own package-specific completers.
|
||||
## Overview
|
||||
|
||||
Implements the 'completers' command group for the Sliver client console.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `completers.go` – Provides reusable carapace completion helpers for selecting client interfaces and proxy endpoints.
|
||||
@@ -0,0 +1,12 @@
|
||||
# client/command/crack
|
||||
|
||||
## Overview
|
||||
|
||||
Implements the 'crack' command group for the Sliver client console. Handlers map Cobra invocations to crack workflows such as crack files.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `commands.go` – Defines the crack command hierarchy, attaching operations for stations and file management.
|
||||
- `crack-files.go` – Manages cracking asset uploads, listings, and removals, handling streaming transfers and chunking.
|
||||
- `crack.go` – Implements station status reporting, health checks, and list rendering for distributed cracking nodes.
|
||||
- `helpers.go` – Supplies completion helpers and byte formatting utilities for crack subcommands.
|
||||
@@ -0,0 +1,14 @@
|
||||
# client/command/creds
|
||||
|
||||
## Overview
|
||||
|
||||
Implements the 'creds' command group for the Sliver client console. Handlers map Cobra invocations to creds workflows such as ADD, hash types, RM, and select.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `add.go` – Adds credentials to the client store via interactive or flag-based input.
|
||||
- `commands.go` – Registers credential management commands and subcommands.
|
||||
- `creds.go` – Lists stored credentials and formats them for display.
|
||||
- `hash-types.go` – Enumerates supported hash types and their identifiers.
|
||||
- `rm.go` – Removes credentials by ID or filter from the store.
|
||||
- `select.go` – Selects credentials for use in other workflows, updating defaults.
|
||||
@@ -1,3 +1,17 @@
|
||||
# Cursed
|
||||
# client/command/cursed
|
||||
|
||||
Cursed is a Sliver Chrome/Electron post-exploitation tool kit based on/integrated with [CursedChrome](https://github.com/mandatoryprogrammer/CursedChrome). Code injection is performed via the [DevTools protocol](https://chromedevtools.github.io/devtools-protocol/).
|
||||
## Overview
|
||||
|
||||
Implements the 'cursed' command group for the Sliver client console. Handlers map Cobra invocations to cursed workflows such as cursed chrome, cursed console, cursed cookies, and cursed edge.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `commands.go` – Exposes the cursed command suite and binds individual subcommands for supported targets.
|
||||
- `cursed-chrome.go` – Launches or hijacks Chrome debugging sessions, locating executables and wiring remote control.
|
||||
- `cursed-console.go` – Provides the interactive cursed console experience atop Chrome DevTools sessions.
|
||||
- `cursed-cookies.go` – Fetches and displays browser cookies from an active cursed session.
|
||||
- `cursed-edge.go` – Mirrors the Chrome workflow for Microsoft Edge, including process discovery logic.
|
||||
- `cursed-electron.go` – Drives cursed interactions with arbitrary Electron apps, validating binaries and starting injected sessions.
|
||||
- `cursed-rm.go` – Removes cursed sessions from the client cache and tears down associated resources.
|
||||
- `cursed-screenshot.go` – Captures screenshots from a cursed browser context via DevTools APIs.
|
||||
- `cursed.go` – Manages the cursed process registry, selection helpers, and remote debugger configuration defaults.
|
||||
@@ -23,7 +23,6 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
insecureRand "math/rand"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -36,6 +35,7 @@ import (
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
"github.com/bishopfox/sliver/protobuf/commonpb"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"github.com/bishopfox/sliver/util"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@@ -213,7 +213,7 @@ func startCursedChromeProcess(isEdge bool, session *clientpb.Session, cmd *cobra
|
||||
con.PrintInfof("Waiting for %s process to initialize ... ", name)
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
bindPort := insecureRand.Intn(10000) + 40000
|
||||
bindPort := util.Intn(10000) + 40000
|
||||
bindAddr := fmt.Sprintf("127.0.0.1:%d", bindPort)
|
||||
|
||||
remoteAddr := fmt.Sprintf("127.0.0.1:%d", debugPort)
|
||||
|
||||
@@ -22,7 +22,6 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
insecureRand "math/rand"
|
||||
"path"
|
||||
"time"
|
||||
|
||||
@@ -34,6 +33,7 @@ import (
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
"github.com/bishopfox/sliver/protobuf/commonpb"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"github.com/bishopfox/sliver/util"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@@ -118,7 +118,7 @@ func avadaKedavraElectron(electronExe string, session *clientpb.Session, cmd *co
|
||||
return curse
|
||||
}
|
||||
|
||||
func checkElectronPath(electronExe string, session *clientpb.Session, cmd *cobra.Command, con *console.SliverClient) (bool, error) {
|
||||
func checkElectronPath(electronExe string, _ *clientpb.Session, cmd *cobra.Command, con *console.SliverClient) (bool, error) {
|
||||
ls, err := con.Rpc.Ls(context.Background(), &sliverpb.LsReq{
|
||||
Request: con.ActiveTarget.Request(cmd),
|
||||
Path: electronExe,
|
||||
@@ -175,7 +175,7 @@ func startCursedElectronProcess(electronExe string, session *clientpb.Session, c
|
||||
con.PrintInfof("Waiting for process to initialize ... ")
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
bindPort := insecureRand.Intn(10000) + 40000
|
||||
bindPort := util.Intn(10000) + 40000
|
||||
bindAddr := fmt.Sprintf("127.0.0.1:%d", bindPort)
|
||||
|
||||
remoteAddr := fmt.Sprintf("127.0.0.1:%d", debugPort)
|
||||
|
||||
@@ -21,7 +21,6 @@ package cursed
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
insecureRand "math/rand"
|
||||
"strconv"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
@@ -30,6 +29,7 @@ import (
|
||||
"github.com/bishopfox/sliver/client/command/settings"
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/client/core"
|
||||
"github.com/bishopfox/sliver/util"
|
||||
"github.com/jedib0t/go-pretty/v6/table"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@@ -115,7 +115,7 @@ func selectCursedProcess(con *console.SliverClient) *core.CursedProcess {
|
||||
func getRemoteDebuggerPort(cmd *cobra.Command) int {
|
||||
port, _ := cmd.Flags().GetInt("remote-debugging-port")
|
||||
if port == 0 {
|
||||
port = insecureRand.Intn(30000) + 10000
|
||||
port = util.Intn(30000) + 10000
|
||||
}
|
||||
return port
|
||||
}
|
||||
@@ -1,4 +1,10 @@
|
||||
DLL Hijack
|
||||
===========
|
||||
# client/command/dllhijack
|
||||
|
||||
Implements command related to `dllhijack`.
|
||||
## Overview
|
||||
|
||||
Implements the 'dllhijack' command group for the Sliver client console.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `commands.go` – Registers the dllhijack command, its flags, and completions for selecting remote DLL targets.
|
||||
- `dllhijack.go` – Performs the RPC call that plants a Sliver DLL alongside a target executable for hijacking.
|
||||
@@ -1,4 +1,12 @@
|
||||
Environment
|
||||
===========
|
||||
# client/command/environment
|
||||
|
||||
Contains command implementations for manipulating remote environment variables.
|
||||
## Overview
|
||||
|
||||
Implements the 'environment' command group for the Sliver client console. Handlers map Cobra invocations to environment workflows such as GET, SET, and unset.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `commands.go` – Declares environment command variations and wires subcommands for get/set/unset operations with shared flags.
|
||||
- `get.go` – Invokes the RPC to retrieve environment variables and prints the results for sessions or beacons.
|
||||
- `set.go` – Handles setting environment variables remotely, including beacon callback handling and result formatting.
|
||||
- `unset.go` – Removes environment variables on the remote target and reports task outcomes back to the user.
|
||||
@@ -1,4 +1,19 @@
|
||||
Exec
|
||||
====
|
||||
# client/command/exec
|
||||
|
||||
Implements execution related commands like `execute`, `execute-shellcode`, `execute-assembly`, etc.
|
||||
## Overview
|
||||
|
||||
Implements the 'exec' command group for the Sliver client console. Handlers map Cobra invocations to exec workflows such as execute assembly, execute shellcode, execute, and migrate.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `commands.go` – Registers the exec command family and binds shared flags across execution techniques.
|
||||
- `execute-assembly.go` – Uploads .NET assemblies and triggers in-memory execution, handling results and loot capture.
|
||||
- `execute-shellcode.go` – Executes raw shellcode via RPC, supporting interactive injection and task result printing.
|
||||
- `execute.go` – Runs arbitrary commands, streams combined stdout/stderr, and persists output as loot when requested.
|
||||
- `migrate.go` – Implements process migration, moving implants into new host processes and reporting completion.
|
||||
- `msf-inject.go` – Coordinates Metasploit payload injection tasks and prints remote execution responses.
|
||||
- `msf.go` – Launches Metasploit jobs on targets and tracks their beacon callbacks.
|
||||
- `psexec.go` – Provides PsExec-style remote service deployment using generated binaries and random filenames.
|
||||
- `sideload.go` – Executes unmanaged DLL exports in a remote process and summarizes task output.
|
||||
- `spawndll.go` – Spawns new processes with DLL injection, capturing returned handles and statuses.
|
||||
- `ssh.go` – Runs remote commands over SSH, sourcing credentials from loot and presenting command output.
|
||||
@@ -21,7 +21,6 @@ package exec
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
insecureRand "math/rand"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -32,6 +31,7 @@ import (
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
"github.com/bishopfox/sliver/protobuf/commonpb"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"github.com/bishopfox/sliver/util"
|
||||
"github.com/bishopfox/sliver/util/encoders"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@@ -175,8 +175,8 @@ func PsExecCmd(cmd *cobra.Command, con *console.SliverClient, args []string) {
|
||||
func randomString() string {
|
||||
alphanumeric := "abcdefghijklmnopqrstuvwxyz0123456789"
|
||||
str := ""
|
||||
for index := 0; index < insecureRand.Intn(8)+1; index++ {
|
||||
str += string(alphanumeric[insecureRand.Intn(len(alphanumeric))])
|
||||
for index := 0; index < util.Intn(8)+1; index++ {
|
||||
str += string(alphanumeric[util.Intn(len(alphanumeric))])
|
||||
}
|
||||
return str
|
||||
}
|
||||
@@ -184,7 +184,7 @@ func randomString() string {
|
||||
func randomFileName() string {
|
||||
noun := randomString()
|
||||
noun = strings.ToLower(noun)
|
||||
switch insecureRand.Intn(3) {
|
||||
switch util.Intn(3) {
|
||||
case 0:
|
||||
noun = strings.ToUpper(noun)
|
||||
case 1:
|
||||
@@ -192,16 +192,16 @@ func randomFileName() string {
|
||||
}
|
||||
|
||||
separators := []string{"", "", "", "", "", ".", "-", "_", "--", "__"}
|
||||
sep := separators[insecureRand.Intn(len(separators))]
|
||||
sep := separators[util.Intn(len(separators))]
|
||||
|
||||
alphanumeric := "abcdefghijklmnopqrstuvwxyz0123456789"
|
||||
prefix := ""
|
||||
for index := 0; index < insecureRand.Intn(3); index++ {
|
||||
prefix += string(alphanumeric[insecureRand.Intn(len(alphanumeric))])
|
||||
for index := 0; index < util.Intn(3); index++ {
|
||||
prefix += string(alphanumeric[util.Intn(len(alphanumeric))])
|
||||
}
|
||||
suffix := ""
|
||||
for index := 0; index < insecureRand.Intn(6)+1; index++ {
|
||||
suffix += string(alphanumeric[insecureRand.Intn(len(alphanumeric))])
|
||||
for index := 0; index < util.Intn(6)+1; index++ {
|
||||
suffix += string(alphanumeric[util.Intn(len(alphanumeric))])
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s%s%s%s%s", prefix, sep, noun, sep, suffix)
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
# client/command/exit
|
||||
|
||||
## Overview
|
||||
|
||||
Implements the 'exit' command group for the Sliver client console.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `exit.go` – Implements the client exit command, ensuring cleanup before terminating the console.
|
||||
@@ -1,67 +1,16 @@
|
||||
Extensions
|
||||
===========
|
||||
# client/command/extensions
|
||||
|
||||
Allows to load and execute 3rd party extensions.
|
||||
## Overview
|
||||
|
||||
Extensions directory structures can be arbitrary, however in the root of the directory or .tar.gz there
|
||||
must be a `extension.json` or a `alias.json` file. All paths are relative to the manifest/root directory,
|
||||
parent directories are not allowed. Only files listed in the manifest are copied, any other files will
|
||||
be ignored.
|
||||
Implements the 'extensions' command group for the Sliver client console. Handlers map Cobra invocations to extensions workflows such as argparser, install, list, and load.
|
||||
|
||||
```shell
|
||||
/path/to/extension/folder/
|
||||
├── extension.json
|
||||
└── windows
|
||||
│ └── extension.x86.dll
|
||||
│ └── extension.x64.dll
|
||||
└── linux
|
||||
│ └── extension.x86.so
|
||||
│ └── extension.x64.so
|
||||
└── darwin
|
||||
└── extension.x86.dylib
|
||||
└── extension.x64.dylib
|
||||
```
|
||||
## Go Files
|
||||
|
||||
Here's an example manifest (i.e., the `extension.json` or a `alias.json`):
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "foo",
|
||||
"version": "1.0.0",
|
||||
"extension_author": "ac1d-burn",
|
||||
"original_author": "zer0-cool",
|
||||
"repo_url": "https://github.com/foo/bar",
|
||||
"help": "Help for foo command",
|
||||
"entrypoint": "RunFoo",
|
||||
"init" :"NimMain",
|
||||
"depends_on": "bar",
|
||||
"files": [
|
||||
{
|
||||
"os": "windows",
|
||||
"arch": "amd64",
|
||||
"path": "extension.x64.o",
|
||||
}
|
||||
],
|
||||
"arguments": [
|
||||
{"name": "pid", "type": "int", "desc": "pid", "optional": false},
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
The structure is the following one:
|
||||
|
||||
- `name`: name of the extension, which will also be the name of the command in the sliver client
|
||||
- `help`: the documentation for the new command
|
||||
- `entrypoint`: the name of the exported function to call
|
||||
- `files`: a list of object pointing to the extensions files to load for each architectures and operating systems
|
||||
- `init`: the initialization function name (if relevant, can be omitted)
|
||||
- `arguments`: an optional list of objects (for DLLs), but mandatory for BOFs
|
||||
- `depends_on`: the name of an extension required by the current extension (won't load if the dependency is not loaded)
|
||||
|
||||
The `type` of an argument can be one of the following:
|
||||
|
||||
- `string`: regular ASCII string
|
||||
- `wstring`: string that will be UTF16 encoded
|
||||
- `int`: will be parsed as a 32 bit unsigned integer
|
||||
- `short`: will be parsed as a 16 bit unsigned integer
|
||||
- `file`: a string to a file path on the client side which content will be passed to the BOF
|
||||
- `argparser.go` – Builds argument buffers for extensions, including BOF-specific marshaling and validation.
|
||||
- `commands.go` – Declares the extensions command tree and binds subcommands for list, install, load, and remove actions.
|
||||
- `extensions.go` – Manages installed/temporary extension manifests, printing metadata and supplying completers.
|
||||
- `extensions_test.go` *(tests)* – Verifies manifest parsing and conversion routines to guard against format regressions.
|
||||
- `install.go` – Installs extension bundles from directories or archives, handling overwrite prompts and asset extraction.
|
||||
- `list.go` – Queries the server for matching extensions and renders results categorized by hash or type.
|
||||
- `load.go` – Loads extension binaries for the active target, registers generated commands, and dispatches execution RPCs.
|
||||
- `remove.go` – Removes installed extensions, coordinating manifest lookups and filesystem cleanup.
|
||||
@@ -309,7 +309,7 @@ func validManifest(manifest *ExtensionManifest) error {
|
||||
// argument specifications.
|
||||
func ExtensionRegisterCommand(extCmd *ExtCommand, cmd *cobra.Command, con *console.SliverClient) {
|
||||
if errInvalidArgs := checkExtensionArgs(extCmd); errInvalidArgs != nil {
|
||||
con.PrintErrorf(errInvalidArgs.Error())
|
||||
con.PrintErrorf("%s", errInvalidArgs.Error())
|
||||
return
|
||||
}
|
||||
|
||||
@@ -685,7 +685,7 @@ func PrintExtOutput(extName string, commandName string, outputSchema *packages.O
|
||||
}
|
||||
}
|
||||
if callExtension.Response != nil && callExtension.Response.Err != "" {
|
||||
con.PrintErrorf(callExtension.Response.Err)
|
||||
con.PrintErrorf("%s", callExtension.Response.Err)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -855,7 +855,7 @@ func makeExtensionArgCompleter(extCmd *ExtCommand, _ *cobra.Command, comps *cara
|
||||
usage += " (optional)"
|
||||
}
|
||||
|
||||
actions = append(actions, action.Usage(usage))
|
||||
actions = append(actions, action.Usage("%s", usage))
|
||||
}
|
||||
|
||||
comps.PositionalCompletion(actions...)
|
||||
|
||||
@@ -1,4 +1,28 @@
|
||||
Filesystem
|
||||
==========
|
||||
# client/command/filesystem
|
||||
|
||||
This package implements file system commands such as `ls`, `cd`, `rm`, `download`, `upload`, etc.
|
||||
## Overview
|
||||
|
||||
Implements the 'filesystem' command group for the Sliver client console. Handlers map Cobra invocations to filesystem workflows such as CAT, CD, chmod, and chown.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `cat.go` – Downloads remote files and prints contents locally with optional ANSI colorization.
|
||||
- `cd.go` – Changes the working directory of the active session or beacon.
|
||||
- `chmod.go` – Adjusts remote file permissions via RPC for Unix-like targets.
|
||||
- `chown.go` – Alters remote file ownership metadata where supported.
|
||||
- `chtimes.go` – Updates remote file access and modification timestamps.
|
||||
- `commands.go` – Assembles the filesystem command group and wires each file operation subcommand.
|
||||
- `cp.go` – Copies files on the remote target, handling overwrite prompts and path validation.
|
||||
- `download.go` – Retrieves files from the target and writes them to the local loot directory.
|
||||
- `grep.go` – Runs server-side grep equivalents with pattern, highlight, and streaming options.
|
||||
- `head.go` – Streams the first bytes or lines of a remote file.
|
||||
- `ls.go` – Lists directory contents with filtering, sorting, and long-format support.
|
||||
- `memfiles-add.go` – Uploads file data into in-memory implants for later retrieval.
|
||||
- `memfiles-list.go` – Enumerates in-memory file entries stored on the implant.
|
||||
- `memfiles-rm.go` – Removes staged in-memory files from the implant cache.
|
||||
- `mkdir.go` – Creates directories on the remote system, with recursive creation if requested.
|
||||
- `mount.go` – Mounts remote filesystem paths for live browsing through the client.
|
||||
- `mv.go` – Moves or renames remote files and directories.
|
||||
- `pwd.go` – Prints the current working directory of the active target.
|
||||
- `rm.go` – Deletes remote files or directories with optional recursive behavior.
|
||||
- `upload.go` – Transfers local files to the target and sets desired permissions.
|
||||
@@ -0,0 +1,9 @@
|
||||
# client/command/flags
|
||||
|
||||
## Overview
|
||||
|
||||
Implements the 'flags' command group for the Sliver client console.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `flags.go` – Provides shared helpers for binding Cobra flag sets, target filters, and carapace completions to commands.
|
||||
@@ -1,5 +1,24 @@
|
||||
Generate
|
||||
========
|
||||
# client/command/generate
|
||||
|
||||
Implements command related to implant generation such as `generate`, `regenerate`, `profiles`, etc.
|
||||
## Overview
|
||||
|
||||
Implements the 'generate' command group for the Sliver client console. Handlers map Cobra invocations to generate workflows such as canaries, generate beacon, generate info, and implants RM.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `canaries.go` – Lists DNS canaries, filters burned entries, and prints status tables.
|
||||
- `commands.go` – Defines the generate command hierarchy spanning implant, profile, and canary tooling.
|
||||
- `generate-beacon.go` – Builds staged beacons from profile/flag inputs and triggers compilation via RPC.
|
||||
- `generate-info.go` – Displays build configuration details for a generated implant artifact.
|
||||
- `generate.go` – Orchestrates implant compilation pipelines, parsing C2 flags and selecting targets/builders.
|
||||
- `helpers.go` – Supplies completions, helper lookups, and binary retrieval utilities used across generate commands.
|
||||
- `implants-rm.go` – Deletes stored implant builds from the server catalog.
|
||||
- `implants-stage.go` – Uploads generated implants into staging slots for later deployment.
|
||||
- `implants.go` – Lists implant builds, filters them, and resolves selected build metadata.
|
||||
- `profiles-generate.go` – Generates new implant profiles from templates and selected options.
|
||||
- `profiles-new.go` – Creates empty implant profiles populated with default settings.
|
||||
- `profiles-rm.go` – Removes saved implant profiles and confirms deletion state.
|
||||
- `profiles-stage.go` – Stages implant profiles to facilitate rapid build operations.
|
||||
- `profiles.go` – Lists profiles, prints detailed info, and resolves profile selections for other commands.
|
||||
- `regenerate.go` – Rebuilds implants from existing configuration IDs without re-specifying flags.
|
||||
- `traffic-encoders.go` – Manages generation of HTTP/DNS traffic encoder assets for implants.
|
||||
@@ -291,6 +291,13 @@ func parseCompileFlags(cmd *cobra.Command, con *console.SliverClient) (string, *
|
||||
sgnEnabled := false
|
||||
|
||||
var exports []string
|
||||
exportsArg, _ := cmd.Flags().GetString("exports")
|
||||
if exportsArg == "" {
|
||||
con.PrintErrorf("Shared libraries need at least one export\n")
|
||||
return "", nil
|
||||
} else {
|
||||
exports = strings.Split(exportsArg, ",")
|
||||
}
|
||||
|
||||
format, _ := cmd.Flags().GetString("format")
|
||||
runAtLoad := false
|
||||
@@ -302,13 +309,6 @@ func parseCompileFlags(cmd *cobra.Command, con *console.SliverClient) (string, *
|
||||
configFormat = clientpb.OutputFormat_SHARED_LIB
|
||||
isSharedLib = true
|
||||
runAtLoad, _ = cmd.Flags().GetBool("run-at-load")
|
||||
exportsArg, _ := cmd.Flags().GetString("exports")
|
||||
if exportsArg == "" {
|
||||
con.PrintErrorf("Shared libraries need at least one export\n")
|
||||
return "", nil
|
||||
} else {
|
||||
exports = strings.Split(exportsArg, ",")
|
||||
}
|
||||
case "shellcode":
|
||||
configFormat = clientpb.OutputFormat_SHELLCODE
|
||||
isShellcode = true
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
Help
|
||||
====
|
||||
# client/command/help
|
||||
|
||||
This package contains all of the long-form command help templates that are displayed when a user types `help <cmd>`
|
||||
## Overview
|
||||
|
||||
Implements the 'help' command group for the Sliver client console. Handlers map Cobra invocations to help workflows such as long help.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `help.go` – Houses the legacy grouped help implementation for the console, kept for reference and future reuse.
|
||||
- `long-help.go` – Stores long-form help templates and utilities for formatting command documentation.
|
||||
@@ -1,4 +1,13 @@
|
||||
Hosts
|
||||
======
|
||||
# client/command/hosts
|
||||
|
||||
Command to access and manage host information.
|
||||
## Overview
|
||||
|
||||
Implements the 'hosts' command group for the Sliver client console. Handlers map Cobra invocations to hosts workflows such as hosts IOC RM, hosts IOC, and hosts RM.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `commands.go` – Sets up the hosts command suite and its IOC management subcommands.
|
||||
- `hosts-ioc-rm.go` – Removes stored indicators of compromise for a host via RPC.
|
||||
- `hosts-ioc.go` – Lists and prints host IOC data retrieved from the server.
|
||||
- `hosts-rm.go` – Deletes hosts from inventory and confirms removal operations.
|
||||
- `hosts.go` – Displays host summaries, filters by query, and renders tabular output.
|
||||
@@ -1,4 +1,11 @@
|
||||
Info
|
||||
====
|
||||
# client/command/info
|
||||
|
||||
Implements session information commands like `info`, `print`, `whoami`, etc.
|
||||
## Overview
|
||||
|
||||
Implements the 'info' command group for the Sliver client console. Handlers map Cobra invocations to info workflows such as ping.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `commands.go` – Registers information-oriented commands and binds them into the console.
|
||||
- `info.go` – Queries detailed session or beacon metadata and prints rich status tables.
|
||||
- `ping.go` – Sends ping requests to implants to test connectivity and round-trip latency.
|
||||
@@ -2,10 +2,10 @@ package info
|
||||
|
||||
import (
|
||||
"context"
|
||||
insecureRand "math/rand"
|
||||
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"github.com/bishopfox/sliver/util"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@@ -16,7 +16,7 @@ func PingCmd(cmd *cobra.Command, con *console.SliverClient, args []string) {
|
||||
return
|
||||
}
|
||||
|
||||
nonce := insecureRand.Intn(999999)
|
||||
nonce := util.Intn(999999)
|
||||
con.PrintInfof("Ping %d\n", nonce)
|
||||
pong, err := con.Rpc.Ping(context.Background(), &sliverpb.Ping{
|
||||
Nonce: int32(nonce),
|
||||
|
||||
@@ -1,4 +1,16 @@
|
||||
Jobs
|
||||
=====
|
||||
# client/command/jobs
|
||||
|
||||
Implements commands related to starting/killing jobs like `jobs` and starting C2 listeners (`mtls`, `http`, etc.)
|
||||
## Overview
|
||||
|
||||
Implements the 'jobs' command group for the Sliver client console. Handlers map Cobra invocations to jobs workflows such as DNS, HTTP, HTTPS, and mTLS.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `commands.go` – Declares the jobs command tree and wires transport-specific subcommands.
|
||||
- `dns.go` – Lists, starts, and stops DNS listener jobs via RPC.
|
||||
- `http.go` – Manages HTTP listener jobs, including creation and teardown.
|
||||
- `https.go` – Handles HTTPS listener lifecycle operations with certificate options.
|
||||
- `jobs.go` – Provides common utilities for rendering job tables and selecting listener IDs.
|
||||
- `mtls.go` – Controls mTLS listener jobs and prints connection details.
|
||||
- `stage.go` – Manages staging servers for delivering payloads to new implants.
|
||||
- `wg.go` – Configures and monitors WireGuard listener jobs for C2 traffic.
|
||||
@@ -163,5 +163,5 @@ func Commands(con *console.SliverClient) []*cobra.Command {
|
||||
(*comp)["compress"] = carapace.ActionValues([]string{"zlib", "gzip", "deflate9", "none"}...).Tag("compression formats")
|
||||
})
|
||||
|
||||
return []*cobra.Command{jobsCmd, mtlsCmd, wgCmd, httpCmd, httpsCmd, stageCmd}
|
||||
return []*cobra.Command{jobsCmd, mtlsCmd, wgCmd, dnsCmd, httpCmd, httpsCmd, stageCmd}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
# client/command/kill
|
||||
|
||||
## Overview
|
||||
|
||||
Implements the 'kill' command group for the Sliver client console.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `commands.go` – Registers the kill command and binds timeout/target flags.
|
||||
- `kill.go` – Terminates sessions or beacons on the server, handling confirmations and output messaging.
|
||||
@@ -0,0 +1,9 @@
|
||||
# client/command/licenses
|
||||
|
||||
## Overview
|
||||
|
||||
Implements the 'licenses' command group for the Sliver client console.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `commands.go` – Displays third-party license information through a dedicated console command.
|
||||
@@ -1,5 +1,16 @@
|
||||
Loot
|
||||
=====
|
||||
# client/command/loot
|
||||
|
||||
Client loot command implementations
|
||||
## Overview
|
||||
|
||||
Implements the 'loot' command group for the Sliver client console. Handlers map Cobra invocations to loot workflows such as fetch, local, remote, and rename.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `commands.go` – Declares the loot command tree and binds fetch/local/removal subcommands.
|
||||
- `fetch.go` – Downloads remote loot artifacts and writes them to local storage.
|
||||
- `helpers.go` – Provides helper functions for lookup, filtering, and formatting loot entries.
|
||||
- `local.go` – Lists, inspects, and opens loot stored on the client filesystem.
|
||||
- `loot.go` – Shows remote loot inventory and renders summaries.
|
||||
- `remote.go` – Interacts with server-side loot, supporting filtering and detail views.
|
||||
- `rename.go` – Renames loot items while synchronizing local and remote metadata.
|
||||
- `rm.go` – Deletes loot entries from the server or local cache with confirmation prompts.
|
||||
@@ -1,5 +1,12 @@
|
||||
Monitor
|
||||
========
|
||||
# client/command/monitor
|
||||
|
||||
Contains `monitor` related command implementations.
|
||||
## Overview
|
||||
|
||||
Implements the 'monitor' command group for the Sliver client console. Handlers map Cobra invocations to monitor workflows such as start and stop.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `commands.go` – Registers the monitor command suite for live session monitoring.
|
||||
- `config.go` – Parses monitor configuration flags and resolves target selections.
|
||||
- `start.go` – Starts monitoring jobs and streams event output to the console.
|
||||
- `stop.go` – Stops active monitor jobs and reports termination status.
|
||||
@@ -1,4 +1,11 @@
|
||||
Network
|
||||
========
|
||||
# client/command/network
|
||||
|
||||
Network related command implementations such as `netstat` and `ifconfig`
|
||||
## Overview
|
||||
|
||||
Implements the 'network' command group for the Sliver client console. Handlers map Cobra invocations to network workflows such as ifconfig and netstat.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `commands.go` – Registers network inspection commands for implants.
|
||||
- `ifconfig.go` – Retrieves and prints interface configuration details from the target.
|
||||
- `netstat.go` – Displays remote socket listings similar to netstat output.
|
||||
@@ -1,6 +1,10 @@
|
||||
Operators
|
||||
==========
|
||||
# client/command/operators
|
||||
|
||||
Operator related command implementations.
|
||||
## Overview
|
||||
|
||||
__NOTE:__ Some operator-related commands are server-side only and are located instead in `server/console`
|
||||
Implements the 'operators' command group for the Sliver client console.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `commands.go` – Declares the operators command and binds associated flags.
|
||||
- `operators.go` – Lists operators connected to the server and prints session details.
|
||||
@@ -1,5 +1,15 @@
|
||||
Pivots
|
||||
=======
|
||||
# client/command/pivots
|
||||
|
||||
Pivot related command implementations, pivots are specifically for pivoting C2 traffic (not to be confused with port forwarding)
|
||||
## Overview
|
||||
|
||||
Implements the 'pivots' command group for the Sliver client console. Handlers map Cobra invocations to pivots workflows such as details, graph, start, and stop.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `commands.go` – Declares the pivots command family and ties start/stop operations together.
|
||||
- `details.go` – Prints detailed information about a specific pivot chain.
|
||||
- `graph.go` – Renders pivot relationships as ASCII graphs for situational awareness.
|
||||
- `helpers.go` – Supplies shared RPC helpers and completions used across pivot commands.
|
||||
- `pivots.go` – Lists pivot sessions and summarizes their status.
|
||||
- `start.go` – Initiates new pivot listeners or routes for the active target.
|
||||
- `stop.go` – Stops running pivots and cleans up resources on the implant.
|
||||
@@ -1,7 +1,12 @@
|
||||
Portfwd
|
||||
========
|
||||
# client/command/portfwd
|
||||
|
||||
In-band port forwarding related command implementations.
|
||||
## Overview
|
||||
|
||||
__NOTE:__ WireGuard port forwarding commands are located in `client/command/wireguard`
|
||||
Implements the 'portfwd' command group for the Sliver client console. Handlers map Cobra invocations to portfwd workflows such as portfwd ADD and portfwd RM.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `commands.go` – Sets up the port forwarding command suite.
|
||||
- `portfwd-add.go` – Adds new local-to-remote port forwarders on the active session.
|
||||
- `portfwd-rm.go` – Removes configured port forwarders by ID.
|
||||
- `portfwd.go` – Lists existing port forwards and renders their configuration.
|
||||
@@ -1,5 +1,15 @@
|
||||
Privilege
|
||||
==========
|
||||
# client/command/privilege
|
||||
|
||||
Commands related to manipulation of operating system privileges, such as Windows Tokens.
|
||||
## Overview
|
||||
|
||||
Implements the 'privilege' command group for the Sliver client console. Handlers map Cobra invocations to privilege workflows such as getprivs, getsystem, impersonate, and make token.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `commands.go` – Registers privilege escalation commands and binds platform restrictions.
|
||||
- `getprivs.go` – Queries and prints token privileges for the current user context.
|
||||
- `getsystem.go` – Attempts to obtain SYSTEM privileges via built-in escalation techniques.
|
||||
- `impersonate.go` – Handles impersonation of other logon sessions using available tokens.
|
||||
- `make-token.go` – Creates new logon tokens with supplied credentials for the implant.
|
||||
- `rev2self.go` – Reverts impersonation back to the implant's original security context.
|
||||
- `runas.go` – Runs commands under alternate credentials or integrity levels through runas-like workflows.
|
||||
@@ -1,4 +1,14 @@
|
||||
Processes
|
||||
==========
|
||||
# client/command/processes
|
||||
|
||||
Commands for manipulating remote processes, e.g. `ps`, `terminate`, etc.
|
||||
## Overview
|
||||
|
||||
Implements the 'processes' command group for the Sliver client console. Handlers map Cobra invocations to processes workflows such as procdump, PS, pstree, and terminate.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `commands.go` – Creates the processes command suite and binds subcommands for inspection and control.
|
||||
- `procdump.go` – Dumps process memory to loot for forensic analysis via RPC tasks.
|
||||
- `ps.go` – Lists active processes on the target with filtering options.
|
||||
- `pstree.go` – Renders process hierarchies as a tree view.
|
||||
- `services.go` – Enumerates Windows services and their states.
|
||||
- `terminate.go` – Terminates processes by PID with confirmation messaging.
|
||||
@@ -105,6 +105,8 @@ var knownSecurityTools = map[string][]string{
|
||||
"cyuserservice.exe": {console.Red, "Palo Alto Cortex"}, // Cortex XDR - user service
|
||||
"cywscsvc.exe": {console.Red, "Palo Alto Cortex"}, // Cortex XDR - security center service
|
||||
"tlaworker.exe": {console.Red, "Palo Alto Cortex"}, // Cortex XDR - local analysis worker
|
||||
"AEEngine.exe": {console.Red, "Faronics Anti-Executable"}, // Faronics Anti-Executable - security service
|
||||
"Antiexecutable.exe": {console.Red, "Faronics Anti-Executable"}, // Faronics Anti-Executable - gui and tray icon
|
||||
}
|
||||
|
||||
// PsCmd - List processes on the remote system
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
Reaction
|
||||
=========
|
||||
# client/command/reaction
|
||||
|
||||
Commands to set a reaction, or unset a reaction. Reactions allow the operator to automate commands in response to event(s).
|
||||
## Overview
|
||||
|
||||
Implements the 'reaction' command group for the Sliver client console. Handlers map Cobra invocations to reaction workflows such as reload, save, SET, and unset.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `commands.go` – Wires the reaction command set for automations and triggers.
|
||||
- `helpers.go` – Supplies shared lookup and persistence helpers for reaction rules.
|
||||
- `reaction.go` – Lists existing reactions and displays their trigger conditions.
|
||||
- `reload.go` – Reloads reaction definitions from disk into the client runtime.
|
||||
- `save.go` – Persists in-memory reaction definitions back to disk.
|
||||
- `set.go` – Creates or modifies reaction rules interactively.
|
||||
- `unset.go` – Removes configured reaction rules from the store.
|
||||
@@ -1,4 +1,11 @@
|
||||
Reconfig
|
||||
=========
|
||||
# client/command/reconfig
|
||||
|
||||
Commands used to reconfigure beacon/session times and metadata
|
||||
## Overview
|
||||
|
||||
Implements the 'reconfig' command group for the Sliver client console. Handlers map Cobra invocations to reconfig workflows such as rename.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `commands.go` – Registers the reconfig command and attaches subcommands such as rename.
|
||||
- `reconfig.go` – Shows current implant configuration and prompts for updates.
|
||||
- `rename.go` – Renames implants or beacons on the server for easier identification.
|
||||
@@ -1,4 +1,14 @@
|
||||
Registry
|
||||
========
|
||||
# client/command/registry
|
||||
|
||||
Commands for manipulating the Windows registry.
|
||||
## Overview
|
||||
|
||||
Implements the 'registry' command group for the Sliver client console. Handlers map Cobra invocations to registry workflows such as REG create, REG delete, REG list, and REG read.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `commands.go` – Exposes registry management commands for Windows targets.
|
||||
- `reg-create.go` – Creates new registry keys or values remotely.
|
||||
- `reg-delete.go` – Deletes registry keys/values with confirmation messaging.
|
||||
- `reg-list.go` – Enumerates registry subkeys and values for a provided path.
|
||||
- `reg-read.go` – Reads and prints registry value data.
|
||||
- `reg-write.go` – Writes registry values with type handling for supported data kinds.
|
||||
@@ -0,0 +1,12 @@
|
||||
# client/command/rportfwd
|
||||
|
||||
## Overview
|
||||
|
||||
Implements the 'rportfwd' command group for the Sliver client console. Handlers map Cobra invocations to rportfwd workflows such as portfwd ADD, portfwd RM, and portfwd.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `commands.go` – Registers reverse port forwarding commands tied to implant callbacks.
|
||||
- `portfwd-add.go` – Adds new reverse port forwards from remote hosts back to the operator.
|
||||
- `portfwd-rm.go` – Removes reverse port forwards by identifier.
|
||||
- `portfwd.go` – Lists active reverse port forwards and summarizes their endpoints.
|
||||
@@ -1,5 +1,10 @@
|
||||
Screenshot
|
||||
===========
|
||||
# client/command/screenshot
|
||||
|
||||
Screenshot command implementation.
|
||||
## Overview
|
||||
|
||||
Implements the 'screenshot' command group for the Sliver client console.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `commands.go` – Registers the screenshot command and binds output options.
|
||||
- `screenshot.go` – Requests a screenshot from the implant and saves or displays the resulting image.
|
||||
@@ -1,4 +1,15 @@
|
||||
Sessions
|
||||
=========
|
||||
# client/command/sessions
|
||||
|
||||
Session related command implementations.
|
||||
## Overview
|
||||
|
||||
Implements the 'sessions' command group for the Sliver client console. Handlers map Cobra invocations to sessions workflows such as background, close, interactive, and prune.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `background.go` – Sends interactive sessions to the background while keeping them connected.
|
||||
- `close.go` – Closes sessions cleanly via RPC.
|
||||
- `commands.go` – Assembles the sessions command hierarchy and subcommands.
|
||||
- `helpers.go` – Provides lookup utilities and prompt helpers for session selection.
|
||||
- `interactive.go` – Brings sessions into the foreground interactive console.
|
||||
- `prune.go` – Removes disconnected or dead sessions from the server inventory.
|
||||
- `sessions.go` – Lists active sessions and renders tabular summaries.
|
||||
@@ -1,4 +1,13 @@
|
||||
Style
|
||||
======
|
||||
# client/command/settings
|
||||
|
||||
Defines terminal interface styles.
|
||||
## Overview
|
||||
|
||||
Implements the 'settings' command group for the Sliver client console. Handlers map Cobra invocations to settings workflows such as beacons, opsec, and tables.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `beacons.go` – Configures beacon polling, jitter, and other runtime options.
|
||||
- `commands.go` – Registers the settings command namespace and attaches subcommands.
|
||||
- `opsec.go` – Manages operational security settings like auto tasks and notifications.
|
||||
- `settings.go` – Lists and updates general client settings persisted to disk.
|
||||
- `tables.go` – Adjusts table formatting preferences for console output.
|
||||
@@ -1,5 +1,12 @@
|
||||
Shell
|
||||
======
|
||||
# client/command/shell
|
||||
|
||||
Implements the interactive `shell` command.
|
||||
## Overview
|
||||
|
||||
Implements the 'shell' command group for the Sliver client console. Handlers map Cobra invocations to shell workflows such as filter reader generic and filter reader windows.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `commands.go` – Exposes the interactive shell command and binds its options.
|
||||
- `filter-reader_generic.go` – Provides output filtering for shell streams on POSIX targets.
|
||||
- `filter-reader_windows.go` – Implements CRLF-aware filtering and decoding for Windows shell sessions.
|
||||
- `shell.go` – Launches interactive command shells over RPC and manages IO loops.
|
||||
@@ -0,0 +1,10 @@
|
||||
# client/command/shikata-ga-nai
|
||||
|
||||
## Overview
|
||||
|
||||
Implements the 'shikata-ga-nai' command group for the Sliver client console. Handlers map Cobra invocations to shikata ga nai workflows such as SGN.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `commands.go` – Registers shikata-ga-nai encoder commands for payload generation.
|
||||
- `sgn.go` – Interfaces with the SGN service to build XOR polymorphic payloads and prints results.
|
||||
@@ -0,0 +1,13 @@
|
||||
# client/command/socks
|
||||
|
||||
## Overview
|
||||
|
||||
Implements the 'socks' command group for the Sliver client console. Handlers map Cobra invocations to socks workflows such as rootcommands, socks start, and socks stop.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `commands.go` – Registers SOCKS proxy commands within the client console.
|
||||
- `rootCommands.go` – Provides shared root-level wiring for SOCKS commands used in multiple menus.
|
||||
- `socks-start.go` – Starts local SOCKS proxy listeners tied to implants.
|
||||
- `socks-stop.go` – Stops running SOCKS proxies and frees ports.
|
||||
- `socks.go` – Lists SOCKS proxies and prints their connection details.
|
||||
@@ -1,3 +1,9 @@
|
||||
Taskmany
|
||||
========
|
||||
This package implements the `taskmany` command, which is used to task multiple beacons or sessions at once
|
||||
# client/command/taskmany
|
||||
|
||||
## Overview
|
||||
|
||||
Implements the 'taskmany' command group for the Sliver client console.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `taskmany.go` – Batches task execution across multiple sessions or beacons using shared parameters.
|
||||
@@ -1,5 +1,13 @@
|
||||
Tasks
|
||||
=======
|
||||
# client/command/tasks
|
||||
|
||||
Manage and interact with Beacon tasks
|
||||
## Overview
|
||||
|
||||
Implements the 'tasks' command group for the Sliver client console. Handlers map Cobra invocations to tasks workflows such as fetch and tasks cancel.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `commands.go` – Registers task management commands for viewing and controlling job history.
|
||||
- `fetch.go` – Downloads task artifacts and output generated by implants.
|
||||
- `helpers.go` – Provides shared utilities for task lookups, formatting, and completion.
|
||||
- `tasks-cancel.go` – Cancels queued or running tasks targeting implants.
|
||||
- `tasks.go` – Lists recent tasks with filters for status and target.
|
||||
@@ -1,4 +1,10 @@
|
||||
Update
|
||||
======
|
||||
# client/command/update
|
||||
|
||||
Implements the `update` command
|
||||
## Overview
|
||||
|
||||
Implements the 'update' command group for the Sliver client console.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `commands.go` – Registers the update command for checking new releases.
|
||||
- `update.go` – Contacts the update endpoint and reports available client/server versions.
|
||||
@@ -1,4 +1,12 @@
|
||||
Use
|
||||
====
|
||||
# client/command/use
|
||||
|
||||
This package implements the `use` command, which is used to select active sessions/beacons.
|
||||
## Overview
|
||||
|
||||
Implements the 'use' command group for the Sliver client console. Handlers map Cobra invocations to use workflows such as beacons and sessions.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `beacons.go` – Switches the active target to a selected beacon.
|
||||
- `commands.go` – Registers the use command and subcommands for session selection.
|
||||
- `sessions.go` – Sets the active session context for subsequent commands.
|
||||
- `use.go` – Implements shared helper logic for switching targets and updating prompts.
|
||||
@@ -0,0 +1,11 @@
|
||||
# client/command/wasm
|
||||
|
||||
## Overview
|
||||
|
||||
Implements the 'wasm' command group for the Sliver client console. Handlers map Cobra invocations to wasm workflows such as memfs.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `commands.go` – Registers WebAssembly-related commands.
|
||||
- `memfs.go` – Manages the WASM in-memory filesystem cache for implants.
|
||||
- `wasm.go` – Lists installed WASM modules and orchestrates execution requests.
|
||||
@@ -1,4 +1,14 @@
|
||||
Websites
|
||||
========
|
||||
# client/command/websites
|
||||
|
||||
Commands related to managing `website`'s
|
||||
## Overview
|
||||
|
||||
Implements the 'websites' command group for the Sliver client console. Handlers map Cobra invocations to websites workflows such as websites ADD content, websites RM content, websites RM, and websites update content.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `commands.go` – Registers website management commands for hosted phishing content.
|
||||
- `websites-add-content.go` – Uploads new site content (files or strings) to the server.
|
||||
- `websites-rm-content.go` – Removes specific content entries from a hosted site.
|
||||
- `websites-rm.go` – Deletes entire website definitions from the server.
|
||||
- `websites-update-content.go` – Replaces or updates existing hosted content assets.
|
||||
- `websites.go` – Lists configured websites and prints their metadata.
|
||||
@@ -1,7 +1,16 @@
|
||||
WireGuard
|
||||
==========
|
||||
# client/command/wireguard
|
||||
|
||||
This package implements commands related to WireGuard functionality such as `wg-socks` and `wg-portfwd`
|
||||
## Overview
|
||||
|
||||
__NOTE:__ Listener code for WireGuard (and all other protocols) is located in the `client/command/jobs` package
|
||||
Implements the 'wireguard' command group for the Sliver client console. Handlers map Cobra invocations to wireguard workflows such as WG config, WG portfwd ADD, WG portfwd RM, and WG portfwd.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `commands.go` – Registers WireGuard-centric commands and their subcommands.
|
||||
- `wg-config.go` – Generates and displays WireGuard configuration files for implants.
|
||||
- `wg-portfwd-add.go` – Adds WireGuard-based port forwarding rules.
|
||||
- `wg-portfwd-rm.go` – Removes WireGuard port forwarding entries.
|
||||
- `wg-portfwd.go` – Lists WireGuard forwarding rules with status information.
|
||||
- `wg-socks-start.go` – Starts SOCKS proxies over WireGuard tunnels.
|
||||
- `wg-socks-stop.go` – Stops WireGuard-backed SOCKS proxies.
|
||||
- `wg-socks.go` – Lists SOCKS proxies running over WireGuard connections.
|
||||
@@ -1,4 +1,10 @@
|
||||
Console (Client)
|
||||
=================
|
||||
# client/console
|
||||
|
||||
Contains the entrypoint for the console client
|
||||
## Overview
|
||||
|
||||
Renders the interactive console UI, logging, and terminal helpers for the client. Coordinates readline behavior, prompt styling, and message formatting.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `console.go` – Implements the interactive console, prompt rendering, and RPC client integration.
|
||||
- `log.go` – Provides structured logging utilities and output filters tailored to the console experience.
|
||||
@@ -24,7 +24,6 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
insecureRand "math/rand"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
@@ -40,6 +39,7 @@ import (
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
"github.com/bishopfox/sliver/protobuf/commonpb"
|
||||
"github.com/bishopfox/sliver/protobuf/rpcpb"
|
||||
"github.com/bishopfox/sliver/util"
|
||||
"github.com/gofrs/uuid"
|
||||
"github.com/reeflective/console"
|
||||
"github.com/reeflective/readline"
|
||||
@@ -356,7 +356,7 @@ func (con *SliverClient) triggerReactions(event *clientpb.Event) {
|
||||
for _, reaction := range reactions {
|
||||
for _, line := range reaction.Commands {
|
||||
con.PrintInfof(Bold+"Execute reaction: '%s'"+Normal, line)
|
||||
err := con.App.ActiveMenu().RunCommandLine(line)
|
||||
err := con.App.ActiveMenu().RunCommandLine(context.Background(), line)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Reaction command error: %s\n", err)
|
||||
}
|
||||
@@ -431,9 +431,9 @@ func (con *SliverClient) PrintLogo() {
|
||||
}
|
||||
serverSemVer := fmt.Sprintf("%d.%d.%d", serverVer.Major, serverVer.Minor, serverVer.Patch)
|
||||
|
||||
logo := asciiLogos[insecureRand.Intn(len(asciiLogos))]
|
||||
logo := asciiLogos[util.Intn(len(asciiLogos))]
|
||||
fmt.Println(strings.ReplaceAll(logo, "\n", "\r\n"))
|
||||
fmt.Println("All hackers gain " + abilities[insecureRand.Intn(len(abilities))] + "\r")
|
||||
fmt.Println("All hackers gain " + abilities[util.Intn(len(abilities))] + "\r")
|
||||
fmt.Printf(Info+"Server v%s - %s%s\r\n", serverSemVer, serverVer.Commit, dirty)
|
||||
if version.GitCommit != serverVer.Commit {
|
||||
fmt.Printf(Info+"Client %s\r\n", version.FullVersion())
|
||||
|
||||
+19
-1
@@ -78,6 +78,24 @@ func (con *SliverClient) logCommand(args []string) ([]string, error) {
|
||||
return args, nil
|
||||
}
|
||||
logger := slog.New(con.jsonHandler).With(slog.String("type", "command"))
|
||||
|
||||
// Attach active target context if available
|
||||
if session := con.ActiveTarget.GetSession(); session != nil {
|
||||
logger = logger.With(
|
||||
slog.String("id", session.ID),
|
||||
slog.String("name", session.Name),
|
||||
slog.String("hostname", session.Hostname),
|
||||
slog.String("username", session.Username),
|
||||
)
|
||||
} else if beacon := con.ActiveTarget.GetBeacon(); beacon != nil {
|
||||
logger = logger.With(
|
||||
slog.String("id", beacon.ID),
|
||||
slog.String("name", beacon.Name),
|
||||
slog.String("hostname", beacon.Hostname),
|
||||
slog.String("username", beacon.Username),
|
||||
)
|
||||
}
|
||||
|
||||
logger.Debug(strings.Join(args, " "))
|
||||
return args, nil
|
||||
}
|
||||
@@ -144,7 +162,7 @@ func (con *SliverClient) PrintAsyncResponse(resp *commonpb.Response) {
|
||||
defer cancel()
|
||||
beacon, err := con.Rpc.GetBeacon(ctx, &clientpb.Beacon{ID: resp.BeaconID})
|
||||
if err != nil {
|
||||
con.PrintWarnf(err.Error())
|
||||
con.PrintWarnf("%s", err.Error())
|
||||
return
|
||||
}
|
||||
con.PrintInfof("Tasked beacon %s (%s)\n", beacon.Name, strings.Split(resp.TaskID, "-")[0])
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
Constants
|
||||
==========
|
||||
# client/constants
|
||||
|
||||
A package of re-used strings and other constants
|
||||
## Overview
|
||||
|
||||
Centralizes constants shared across the client runtime and command packages. Captures strings, flag names, and feature toggles used throughout the CLI.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `constants.go` – Defines shared string and feature constants referenced across client packages.
|
||||
@@ -0,0 +1,16 @@
|
||||
# client/core
|
||||
|
||||
## Overview
|
||||
|
||||
Maintains client application state, background workers, and RPC coordination. Orchestrates session tracking, event streams, and health checks. Core logic addresses BOF, curses, portfwd, and reactions within the core package.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `bof.go` – Defines Beacon Object File argument buffers and helpers for executing BOF modules.
|
||||
- `curses.go` – Manages cursed browser sessions, caching processes and coordinating lifecycle events.
|
||||
- `portfwd.go` – Tracks active port forwards and exposes shared state for command packages.
|
||||
- `reactions.go` – Stores reaction definitions and evaluates triggers when new events arrive.
|
||||
- `socks.go` – Maintains SOCKS proxy metadata and orchestrates background goroutines.
|
||||
- `tunnel.go` – Represents individual tunnels and their configuration details.
|
||||
- `tunnel_io.go` – Implements IO handling and relay loops for tunnel data streams.
|
||||
- `tunnels.go` – Coordinates tunnel creation, lookup, and teardown across the client.
|
||||
@@ -0,0 +1,11 @@
|
||||
# client/credentials
|
||||
|
||||
## Overview
|
||||
|
||||
Credential management utilities including sniffers and import helpers for operators. Provides parsers, storage helpers, and output formatting for recovered secrets. Core logic addresses sniff within the credentials package.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `credentials.go` – Implements credential storage, lookup, and formatting helpers for the client.
|
||||
- `sniff.go` – Provides credential sniffing routines that parse captured outputs into structured records.
|
||||
- `sniff_test.go` *(tests)* – Validates the sniffing/parsing helpers against sample credential data.
|
||||
@@ -1,5 +1,9 @@
|
||||
Licenses
|
||||
=========
|
||||
# client/licenses
|
||||
|
||||
Copies of OSS licenses to be included in binary distributions.
|
||||
## Overview
|
||||
|
||||
Holds embedded license metadata bundled with the client distribution. Supplies license retrieval utilities used for attribution commands.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `licenses.go` – Provides accessors for embedded OSS license text and metadata.
|
||||
@@ -19,26 +19,9 @@ package main
|
||||
*/
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
insecureRand "math/rand"
|
||||
"time"
|
||||
|
||||
"github.com/bishopfox/sliver/client/cli"
|
||||
)
|
||||
|
||||
// Attempt to seed insecure rand with secure rand, but we really
|
||||
// don't care that much if it fails since it's insecure anyways
|
||||
func init() {
|
||||
buf := make([]byte, 8)
|
||||
_, err := rand.Read(buf)
|
||||
if err != nil {
|
||||
insecureRand.Seed(int64(time.Now().Unix()))
|
||||
} else {
|
||||
insecureRand.Seed(int64(binary.LittleEndian.Uint64(buf)))
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
cli.Execute()
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
# client/overlord
|
||||
|
||||
## Overview
|
||||
|
||||
Supervises long-running client jobs, scheduling, and task orchestration. Tracks job lifecycle events and exposes status updates to the console.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `overlord.go` – Manages background job scheduling, tracking, and event delivery to the console.
|
||||
@@ -0,0 +1,9 @@
|
||||
# client/packages
|
||||
|
||||
## Overview
|
||||
|
||||
Deals with packaged extensions and module discovery for the client. Scans, validates, and caches extension manifests and assets. Core logic addresses output within the packages package.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `output.go` – Defines schemas for extension output and assists with marshaling results.
|
||||
@@ -0,0 +1,9 @@
|
||||
# client/spin
|
||||
|
||||
## Overview
|
||||
|
||||
Lightweight terminal spinner utilities used for progress feedback. Wraps spinner styles and timing helpers shared across commands.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `spin.go` – Implements the console spinner and helper functions for running operations with progress feedback.
|
||||
@@ -0,0 +1,9 @@
|
||||
# client/tcpproxy
|
||||
|
||||
## Overview
|
||||
|
||||
Implements the local TCP proxy used for port forwarding from the client side. Manages listener lifecycles, connection pumps, and cleanup hooks.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `tcpproxy.go` – Implements the client-side TCP proxy listener, connection handlers, and shutdown logic.
|
||||
@@ -0,0 +1,9 @@
|
||||
# client/transport
|
||||
|
||||
## Overview
|
||||
|
||||
Client-side transports and RPC wiring to communicate with Sliver servers. Builds authenticated gRPC clients, TLS dialers, and reconnect logic. Core logic addresses mTLS within the transport package.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `mtls.go` – Configures the mutual TLS gRPC transport, including dial options and credential refresh logic.
|
||||
@@ -0,0 +1,10 @@
|
||||
# client/version
|
||||
|
||||
## Overview
|
||||
|
||||
Build-time version and semantic metadata for the client binary. Exposes git information, release channels, and helper formatters. Core logic addresses sliver version and updates within the version package.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `sliver-version.go` – Stores build metadata (version strings, commit hashes) and helper formatters.
|
||||
- `updates.go` – Tracks update state, caches release info, and signals when new versions are available.
|
||||
@@ -5,6 +5,7 @@ public/sitemap.json
|
||||
public/docs.json
|
||||
public/tutorials.json
|
||||
/www.zip
|
||||
util/__generated__/
|
||||
|
||||
# code editor files
|
||||
.vscode/
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
# Repository Guidelines
|
||||
|
||||
## Project Structure & Module Organization
|
||||
- `pages/` contains Next.js routes; Markdown docs live in `pages/docs/md`, tutorials under `pages/tutorials`.
|
||||
- `components/` hosts reusable UI; `util/` stores loaders such as `Docs` and `Themes`.
|
||||
- `public/` serves static assets and the generated `docs.json` consumed by search.
|
||||
- `prebuild/` scripts run during `next build` to turn Markdown into JSON payloads.
|
||||
- Tailwind config sits in `tailwind.config.ts`; shared CSS lives in `styles/`.
|
||||
|
||||
## Build, Test, and Development Commands
|
||||
- `npm install` sets up dependencies.
|
||||
- `npm run dev` starts the docs server with hot reload on `http://localhost:3000`.
|
||||
- `npm run build` exports the static site and regenerates `public/docs.json` plus tutorials JSON.
|
||||
- `npm run start` serves the last build for smoke tests.
|
||||
- `npm run lint` runs the Next.js ESLint suite.
|
||||
- `npm run offline` builds, then zips `out/` for offline distribution.
|
||||
|
||||
## Coding Style & Naming Conventions
|
||||
Use TypeScript with 2-space indentation and ES module imports. Keep React components and files in `components/` PascalCase, helpers camelCase, and Markdown files kebab-case so search slugs stay predictable. Favor function components, hooks, and Tailwind utility classes; let ESLint autofix formatting issues and keep shared constants in `util/`.
|
||||
|
||||
## Testing Guidelines
|
||||
No unit-test runner ships with this project, so treat `npm run lint` and `npm run build` as required gates. When adding interactive behavior, create targeted Playwright or Cypress checks under a `__tests__/` directory and describe how to run them in the PR. Always smoke-test the search panel locally after updating Markdown to confirm newly generated `docs.json` entries render.
|
||||
|
||||
## Commit & Pull Request Guidelines
|
||||
History favors concise, imperative subjects (e.g., "Update workflows to use go v1.25.x"). Group related changes, reference issues with `#1234`, and avoid drive-by refactors. Pull requests should state purpose, call out UI diffs with screenshots or GIFs, confirm that `npm run lint` and `npm run build` both pass, and note any new content sources. Request a docs reviewer whenever Markdown copy changes.
|
||||
|
||||
## Content Authoring Tips
|
||||
Edit or add docs in `pages/docs/md`; keep files flat so the generator exports clean slugs. After content updates, run `npm run build` to refresh `public/docs.json`, then spot-check sidebar headings in `npm run dev`. Tutorials follow the same workflow via `prebuild/generate-tutorials.js`, so align metadata fields to keep search results balanced.
|
||||
@@ -59,7 +59,7 @@ const CodeViewer = (props: CodeViewerProps) => {
|
||||
const [scriptSourceCode, setScriptSourceCode] = React.useState(
|
||||
props.script.source_code
|
||||
);
|
||||
const [fontSize, setFontSize] = React.useState(props.fontSize || 14);
|
||||
const [fontSize, setFontSize] = React.useState(props.fontSize || 13);
|
||||
const editorContainerClassName = React.useMemo(() => {
|
||||
return theme === Themes.DARK
|
||||
? "col-span-12 mt-4 rounded-2xl overflow-hidden"
|
||||
|
||||
@@ -1,11 +1,26 @@
|
||||
import CodeViewer, { CodeSchema } from "@/components/code";
|
||||
import { Themes } from "@/util/themes";
|
||||
import { useTheme } from "next-themes";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/router";
|
||||
import {
|
||||
ComponentPropsWithoutRef,
|
||||
ReactNode,
|
||||
createElement,
|
||||
isValidElement,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
} from "react";
|
||||
import Markdown from "react-markdown";
|
||||
import remarkGfm from "remark-gfm";
|
||||
import { useTheme } from "next-themes";
|
||||
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
|
||||
import {
|
||||
oneDark,
|
||||
oneLight,
|
||||
} from "react-syntax-highlighter/dist/cjs/styles/prism";
|
||||
import AsciinemaPlayer from "./asciinema";
|
||||
import Youtube from "./youtube";
|
||||
|
||||
@@ -21,29 +36,238 @@ type MarkdownAsciiCast = {
|
||||
idleTimeLimit?: number;
|
||||
};
|
||||
|
||||
type HeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;
|
||||
|
||||
type HeadingProps = ComponentPropsWithoutRef<"h1"> & {
|
||||
node?: unknown;
|
||||
};
|
||||
|
||||
const mergeClassNames = (
|
||||
...classes: Array<string | false | null | undefined>
|
||||
) => {
|
||||
return classes.filter(Boolean).join(" ");
|
||||
};
|
||||
|
||||
const extractText = (node: ReactNode): string => {
|
||||
if (node === null || node === undefined) {
|
||||
return "";
|
||||
}
|
||||
if (typeof node === "string" || typeof node === "number") {
|
||||
return String(node);
|
||||
}
|
||||
if (Array.isArray(node)) {
|
||||
return node.map(extractText).join("");
|
||||
}
|
||||
if (isValidElement(node)) {
|
||||
const { children } = node.props as { children?: ReactNode };
|
||||
return extractText(children);
|
||||
}
|
||||
return "";
|
||||
};
|
||||
|
||||
const slugify = (value: string) => {
|
||||
return value
|
||||
.toLowerCase()
|
||||
.trim()
|
||||
.normalize("NFD")
|
||||
.replace(/[\u0300-\u036f]/g, "")
|
||||
.replace(/[^a-z0-9\s-]/g, "")
|
||||
.replace(/\s+/g, "-")
|
||||
.replace(/-+/g, "-")
|
||||
.replace(/^-|-$/g, "");
|
||||
};
|
||||
|
||||
const headingClassNames: Record<HeadingLevel, string> = {
|
||||
1: "mt-12 text-3xl font-semibold tracking-tight text-slate-900 first:mt-0 dark:text-slate-100",
|
||||
2: "mt-10 text-2xl font-semibold tracking-tight text-slate-900 dark:text-slate-100",
|
||||
3: "mt-8 text-xl font-semibold tracking-tight text-slate-900 dark:text-slate-100",
|
||||
4: "mt-6 text-lg font-semibold tracking-tight text-slate-900 dark:text-slate-100",
|
||||
5: "mt-6 text-base font-semibold tracking-tight text-slate-900 dark:text-slate-100",
|
||||
6: "mt-6 text-base font-semibold uppercase tracking-wide text-slate-700 dark:text-slate-300",
|
||||
};
|
||||
|
||||
const MarkdownViewer = (props: MarkdownProps) => {
|
||||
const { theme } = useTheme();
|
||||
const router = useRouter();
|
||||
|
||||
return (
|
||||
<div
|
||||
className={
|
||||
theme === Themes.DARK ? "prose dark:prose-invert" : "prose prose-slate"
|
||||
const slugCounterRef = useRef<Map<string, number>>(new Map());
|
||||
|
||||
useEffect(() => {
|
||||
slugCounterRef.current = new Map();
|
||||
}, [props.markdown]);
|
||||
|
||||
useEffect(() => {
|
||||
if (typeof window === "undefined" || !props.markdown) {
|
||||
return;
|
||||
}
|
||||
|
||||
const hash = router.asPath.split("#")[1];
|
||||
|
||||
if (!hash) {
|
||||
return;
|
||||
}
|
||||
|
||||
const scrollToHash = () => {
|
||||
const target = document.getElementById(hash);
|
||||
if (target) {
|
||||
target.scrollIntoView({ behavior: "auto", block: "start" });
|
||||
return true;
|
||||
}
|
||||
>
|
||||
<Markdown
|
||||
key={props.key || `${Math.random()}`}
|
||||
remarkPlugins={[remarkGfm]}
|
||||
components={{
|
||||
a(props) {
|
||||
const { href, children, ...rest } = props;
|
||||
return false;
|
||||
};
|
||||
|
||||
if (scrollToHash()) {
|
||||
return;
|
||||
}
|
||||
|
||||
let cancelled = false;
|
||||
let frameId: number | null = null;
|
||||
const maxAttempts = 10;
|
||||
let attempts = 0;
|
||||
|
||||
const tryScroll = () => {
|
||||
if (cancelled) {
|
||||
return;
|
||||
}
|
||||
if (scrollToHash()) {
|
||||
return;
|
||||
}
|
||||
if (attempts >= maxAttempts) {
|
||||
return;
|
||||
}
|
||||
attempts += 1;
|
||||
frameId = window.requestAnimationFrame(tryScroll);
|
||||
};
|
||||
|
||||
const timeoutId = window.setTimeout(() => {
|
||||
tryScroll();
|
||||
}, 0);
|
||||
|
||||
return () => {
|
||||
cancelled = true;
|
||||
window.clearTimeout(timeoutId);
|
||||
if (frameId !== null) {
|
||||
window.cancelAnimationFrame(frameId);
|
||||
}
|
||||
};
|
||||
}, [props.markdown, router.asPath]);
|
||||
|
||||
const getAnchor = useCallback((rawValue: string) => {
|
||||
const baseSlug = slugify(rawValue);
|
||||
const safeBase = baseSlug || `section-${slugCounterRef.current.size + 1}`;
|
||||
const usage = slugCounterRef.current.get(safeBase) ?? 0;
|
||||
slugCounterRef.current.set(safeBase, usage + 1);
|
||||
return usage === 0 ? safeBase : `${safeBase}-${usage}`;
|
||||
}, []);
|
||||
|
||||
const headingComponents = useMemo(() => {
|
||||
const createHeadingComponent = (level: HeadingLevel) => {
|
||||
const HeadingComponent = ({
|
||||
children,
|
||||
className,
|
||||
...rest
|
||||
}: HeadingProps) => {
|
||||
const textContent = extractText(children);
|
||||
const anchorRef = useRef<string | null>(null);
|
||||
|
||||
if (!anchorRef.current) {
|
||||
anchorRef.current = getAnchor(textContent);
|
||||
}
|
||||
|
||||
const anchor = anchorRef.current;
|
||||
const HeadingTag = `h${level}`;
|
||||
|
||||
return createElement(
|
||||
HeadingTag,
|
||||
{
|
||||
...rest,
|
||||
id: anchor || undefined,
|
||||
className: mergeClassNames(
|
||||
headingClassNames[level],
|
||||
"scroll-mt-[70px]",
|
||||
className
|
||||
),
|
||||
},
|
||||
<span className="group inline-flex items-baseline gap-2">
|
||||
<span className="font-inherit">{children}</span>
|
||||
{anchor && (
|
||||
<a
|
||||
href={`#${anchor}`}
|
||||
aria-label="Copy link to section"
|
||||
className="inline-flex h-6 w-6 items-center justify-center rounded-md text-slate-400 transition focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/40 focus-visible:ring-offset-2 hover:text-primary dark:text-slate-500"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
className="h-3.5 w-3.5"
|
||||
viewBox="0 0 16 16"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M7.25 2.75a2.5 2.5 0 0 1 4.243-1.768l1.525 1.525a2.5 2.5 0 0 1 0 3.536l-1.232 1.232"
|
||||
stroke="currentColor"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
/>
|
||||
<path
|
||||
d="M8.75 13.25a2.5 2.5 0 0 1-4.243 1.768l-1.525-1.525a2.5 2.5 0 0 1 0-3.536l1.232-1.232"
|
||||
stroke="currentColor"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
/>
|
||||
<path
|
||||
d="M6 10l4-4"
|
||||
stroke="currentColor"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
/>
|
||||
</svg>
|
||||
</a>
|
||||
)}
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
HeadingComponent.displayName = `MarkdownHeading${level}`;
|
||||
return HeadingComponent;
|
||||
};
|
||||
|
||||
return {
|
||||
h1: createHeadingComponent(1),
|
||||
h2: createHeadingComponent(2),
|
||||
h3: createHeadingComponent(3),
|
||||
h4: createHeadingComponent(4),
|
||||
h5: createHeadingComponent(5),
|
||||
h6: createHeadingComponent(6),
|
||||
};
|
||||
}, [getAnchor]);
|
||||
|
||||
const proseClassName = mergeClassNames(
|
||||
"markdown-body prose max-w-none leading-7",
|
||||
theme === Themes.DARK ? "dark:prose-invert prose-slate" : "prose-slate",
|
||||
"prose-pre:bg-slate-950/90 prose-pre:text-slate-100 prose-code:font-mono prose-img:rounded-xl"
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="relative">
|
||||
<div className={proseClassName}>
|
||||
<Markdown
|
||||
key={props.key || `${Math.random()}`}
|
||||
remarkPlugins={[remarkGfm]}
|
||||
components={{
|
||||
...headingComponents,
|
||||
a(anchorProps) {
|
||||
const { href, children, className, ...rest } = anchorProps;
|
||||
|
||||
if (href?.startsWith("/")) {
|
||||
return (
|
||||
// @ts-ignore
|
||||
<a
|
||||
{...rest}
|
||||
href={href}
|
||||
className="text-primary hover:text-primary-dark"
|
||||
className={mergeClassNames(
|
||||
"font-medium text-primary transition-colors duration-150 hover:text-primary-dark",
|
||||
className
|
||||
)}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
router.push(href);
|
||||
@@ -53,94 +277,340 @@ const MarkdownViewer = (props: MarkdownProps) => {
|
||||
</a>
|
||||
);
|
||||
}
|
||||
const url = new URL(href || "");
|
||||
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
||||
return <></>;
|
||||
|
||||
if (!href) {
|
||||
return <>{children}</>;
|
||||
}
|
||||
|
||||
let url: URL | null = null;
|
||||
try {
|
||||
const base =
|
||||
typeof window !== "undefined"
|
||||
? window.location.origin
|
||||
: "https://sliver.sh";
|
||||
url = /^https?:/i.test(href)
|
||||
? new URL(href)
|
||||
: new URL(href, base);
|
||||
} catch (error) {
|
||||
return <>{children}</>;
|
||||
}
|
||||
|
||||
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
||||
return <>{children}</>;
|
||||
}
|
||||
|
||||
const anchorClassName = mergeClassNames(
|
||||
"font-medium text-primary transition-colors duration-150 underline-offset-4 hover:text-primary-dark",
|
||||
className
|
||||
);
|
||||
|
||||
if (url.host === "sliver.sh") {
|
||||
return (
|
||||
// @ts-ignore
|
||||
<Link
|
||||
{...rest}
|
||||
href={url.toString()}
|
||||
className="text-primary hover:text-primary-dark"
|
||||
>
|
||||
<Link {...rest} href={url.toString()} className={anchorClassName}>
|
||||
{children}
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<a
|
||||
{...rest}
|
||||
href={url.toString()}
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
className="text-primary hover:text-primary-dark"
|
||||
className={mergeClassNames(
|
||||
anchorClassName,
|
||||
"after:ml-1 after:text-xs after:content-[\"\\2197\"]"
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</a>
|
||||
);
|
||||
},
|
||||
|
||||
pre(props) {
|
||||
p(paragraphProps) {
|
||||
const { className, children, ...rest } = paragraphProps;
|
||||
return (
|
||||
<p
|
||||
{...rest}
|
||||
className={mergeClassNames(
|
||||
"my-6 text-base leading-7 text-slate-700 dark:text-slate-300",
|
||||
className
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</p>
|
||||
);
|
||||
},
|
||||
|
||||
ul(listProps) {
|
||||
const { className, children, ...rest } = listProps;
|
||||
return (
|
||||
<ul
|
||||
{...rest}
|
||||
className={mergeClassNames(
|
||||
"my-6 list-disc space-y-2 pl-6 text-slate-700 marker:text-primary dark:text-slate-300",
|
||||
className
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</ul>
|
||||
);
|
||||
},
|
||||
|
||||
ol(listProps) {
|
||||
const { className, children, ...rest } = listProps;
|
||||
return (
|
||||
<ol
|
||||
{...rest}
|
||||
className={mergeClassNames(
|
||||
"my-6 list-decimal space-y-2 pl-6 text-slate-700 marker:text-primary dark:text-slate-300",
|
||||
className
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</ol>
|
||||
);
|
||||
},
|
||||
|
||||
li(listItemProps) {
|
||||
const { className, children, ...rest } = listItemProps;
|
||||
return (
|
||||
<li
|
||||
{...rest}
|
||||
className={mergeClassNames(
|
||||
"leading-6 text-slate-700 dark:text-slate-300",
|
||||
className
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</li>
|
||||
);
|
||||
},
|
||||
|
||||
blockquote(blockquoteProps) {
|
||||
const { className, children, ...rest } = blockquoteProps;
|
||||
return (
|
||||
<blockquote
|
||||
{...rest}
|
||||
className={mergeClassNames(
|
||||
"my-8 border-l-4 border-slate-200 bg-slate-50 px-6 py-4 text-base italic text-slate-700 shadow-sm dark:border-slate-700 dark:bg-slate-900/50 dark:text-slate-300",
|
||||
className
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</blockquote>
|
||||
);
|
||||
},
|
||||
|
||||
hr(hrProps) {
|
||||
const { className, ...rest } = hrProps;
|
||||
return (
|
||||
<hr
|
||||
{...rest}
|
||||
className={mergeClassNames(
|
||||
"my-12 border-t border-slate-200 dark:border-slate-800",
|
||||
className
|
||||
)}
|
||||
/>
|
||||
);
|
||||
},
|
||||
|
||||
table(tableProps) {
|
||||
const { className, children, ...rest } = tableProps;
|
||||
return (
|
||||
<div className="my-8 overflow-hidden rounded-xl border border-slate-200 bg-white shadow-sm dark:border-slate-800 dark:bg-slate-950/40">
|
||||
<table
|
||||
{...rest}
|
||||
className={mergeClassNames(
|
||||
"w-full min-w-max divide-y divide-slate-200 text-left text-sm dark:divide-slate-800",
|
||||
className
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
|
||||
thead(theadProps) {
|
||||
const { className, children, ...rest } = theadProps;
|
||||
return (
|
||||
<thead
|
||||
{...rest}
|
||||
className={mergeClassNames(
|
||||
"bg-slate-50 text-sm font-semibold uppercase tracking-wide text-slate-600 dark:bg-slate-900/60 dark:text-slate-300",
|
||||
className
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</thead>
|
||||
);
|
||||
},
|
||||
|
||||
tbody(tbodyProps) {
|
||||
const { className, children, ...rest } = tbodyProps;
|
||||
return (
|
||||
<tbody
|
||||
{...rest}
|
||||
className={mergeClassNames(
|
||||
"divide-y divide-slate-200 dark:divide-slate-800",
|
||||
className
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</tbody>
|
||||
);
|
||||
},
|
||||
|
||||
tr(trProps) {
|
||||
const { className, children, ...rest } = trProps;
|
||||
return (
|
||||
<tr
|
||||
{...rest}
|
||||
className={mergeClassNames(
|
||||
"transition-colors hover:bg-slate-50 dark:hover:bg-slate-900/60",
|
||||
className
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</tr>
|
||||
);
|
||||
},
|
||||
|
||||
th(thProps) {
|
||||
const { className, children, ...rest } = thProps;
|
||||
return (
|
||||
<th
|
||||
{...rest}
|
||||
className={mergeClassNames(
|
||||
"px-4 py-3 text-left text-sm font-semibold text-slate-600 dark:text-slate-200",
|
||||
className
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</th>
|
||||
);
|
||||
},
|
||||
|
||||
td(tdProps) {
|
||||
const { className, children, ...rest } = tdProps;
|
||||
return (
|
||||
<td
|
||||
{...rest}
|
||||
className={mergeClassNames(
|
||||
"px-4 py-3 align-top text-sm text-slate-700 dark:text-slate-300",
|
||||
className
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</td>
|
||||
);
|
||||
},
|
||||
|
||||
strong(strongProps) {
|
||||
const { className, children, ...rest } = strongProps;
|
||||
return (
|
||||
<strong
|
||||
{...rest}
|
||||
className={mergeClassNames(
|
||||
"font-semibold text-slate-900 dark:text-slate-100",
|
||||
className
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</strong>
|
||||
);
|
||||
},
|
||||
|
||||
em(emProps) {
|
||||
const { className, children, ...rest } = emProps;
|
||||
return (
|
||||
<em
|
||||
{...rest}
|
||||
className={mergeClassNames(
|
||||
"text-slate-700 dark:text-slate-300",
|
||||
className
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</em>
|
||||
);
|
||||
},
|
||||
|
||||
pre(preProps) {
|
||||
// We need to look at the child nodes to avoid wrapping
|
||||
// a monaco code block in a <pre> tag
|
||||
const { children, className, node, ...rest } = props;
|
||||
const { children, className, node, ...rest } = preProps as any;
|
||||
const childClass = (children as any)?.props?.className;
|
||||
if (
|
||||
childClass &&
|
||||
childClass.startsWith("language-") &&
|
||||
childClass !== "language-plaintext"
|
||||
) {
|
||||
// @ts-ignore
|
||||
return <div {...rest}>{children}</div>;
|
||||
}
|
||||
|
||||
const textContent = extractText(children);
|
||||
|
||||
return (
|
||||
<pre {...rest} className={className}>
|
||||
{children}
|
||||
<pre
|
||||
{...rest}
|
||||
className={mergeClassNames(
|
||||
"my-6 overflow-x-auto rounded-xl border border-slate-200 bg-slate-50 p-4 text-[13px] leading-6 text-slate-900 shadow-inner dark:border-slate-800 dark:bg-slate-950/90 dark:text-slate-100",
|
||||
className
|
||||
)}
|
||||
>
|
||||
{textContent || children}
|
||||
</pre>
|
||||
);
|
||||
},
|
||||
|
||||
img(props) {
|
||||
const { src, alt, ...rest } = props;
|
||||
img(imageProps) {
|
||||
const { src, alt, className, ...rest } = imageProps;
|
||||
const imageSrc = typeof src === "string" ? src : "";
|
||||
return (
|
||||
// @ts-ignore
|
||||
<Image
|
||||
{...rest}
|
||||
src={src || ""}
|
||||
src={imageSrc}
|
||||
alt={alt || ""}
|
||||
width={500}
|
||||
height={500}
|
||||
className="w-full rounded-medium"
|
||||
width={1200}
|
||||
height={720}
|
||||
className={mergeClassNames(
|
||||
"my-8 w-full rounded-xl border border-slate-200 object-contain shadow-sm dark:border-slate-800",
|
||||
className
|
||||
)}
|
||||
/>
|
||||
);
|
||||
},
|
||||
|
||||
code(props) {
|
||||
const { children, className, node, ...rest } = props;
|
||||
const langTag = /language-(\w+)/.exec(className || "");
|
||||
const lang = langTag ? langTag[1] : "plaintext";
|
||||
if (lang === "plaintext") {
|
||||
return (
|
||||
<span className="prose-sm">
|
||||
<code {...rest} className={className}>
|
||||
{children}
|
||||
</code>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
code(codeProps) {
|
||||
const { inline, children, className, node, ...rest } =
|
||||
codeProps as any;
|
||||
|
||||
if (lang === "youtube") {
|
||||
const embedId = (children as string) || "";
|
||||
const languageClass =
|
||||
typeof className === "string"
|
||||
? className
|
||||
.split(" ")
|
||||
.find((cls: string) => cls.startsWith("language-"))
|
||||
: undefined;
|
||||
|
||||
const lang = languageClass
|
||||
? languageClass.replace("language-", "")
|
||||
: "plaintext";
|
||||
const normalizedLang = lang.toLowerCase();
|
||||
const childValue = Array.isArray(children)
|
||||
? children.join("")
|
||||
: children;
|
||||
const sourceCode = typeof childValue === "string" ? childValue : "";
|
||||
|
||||
if (normalizedLang === "youtube") {
|
||||
const embedId = sourceCode || "";
|
||||
return <Youtube embedId={embedId.trim()} />;
|
||||
}
|
||||
|
||||
if (lang === "asciinema") {
|
||||
const asciiCast: MarkdownAsciiCast = JSON.parse(
|
||||
children as string
|
||||
);
|
||||
if (normalizedLang === "asciinema") {
|
||||
const asciiCast: MarkdownAsciiCast = JSON.parse(sourceCode);
|
||||
const src = asciiCast.src?.startsWith("/")
|
||||
? `${window.location.origin}${asciiCast.src}`
|
||||
: asciiCast.src || "";
|
||||
@@ -161,32 +631,101 @@ const MarkdownViewer = (props: MarkdownProps) => {
|
||||
);
|
||||
}
|
||||
|
||||
const sourceCode = (children as string) || "";
|
||||
const lines = sourceCode.split("\n").length;
|
||||
if (inline || normalizedLang === "plaintext") {
|
||||
return (
|
||||
<code
|
||||
{...rest}
|
||||
className={mergeClassNames(
|
||||
"rounded-md bg-slate-100 px-1.5 py-0.5 font-mono text-[13px] text-slate-700 dark:bg-slate-800/80 dark:text-slate-200",
|
||||
className
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</code>
|
||||
);
|
||||
}
|
||||
|
||||
const baseTheme = theme === Themes.DARK ? oneDark : oneLight;
|
||||
const themeOverrides = baseTheme as Record<string, Record<string, unknown>>;
|
||||
const preStyles = themeOverrides['pre[class*="language-"]'] || {};
|
||||
const codeStyles = themeOverrides['code[class*="language-"]'] || {};
|
||||
const syntaxTheme = {
|
||||
...baseTheme,
|
||||
'pre[class*="language-"]': {
|
||||
...preStyles,
|
||||
background: "transparent",
|
||||
backgroundColor: "transparent",
|
||||
},
|
||||
'code[class*="language-"]': {
|
||||
...codeStyles,
|
||||
background: "transparent",
|
||||
backgroundColor: "transparent",
|
||||
},
|
||||
};
|
||||
|
||||
if (normalizedLang.startsWith("monaco")) {
|
||||
const rawScriptType = lang.includes(":")
|
||||
? lang.substring(lang.indexOf(":") + 1)
|
||||
: lang === "monaco"
|
||||
? "plaintext"
|
||||
: lang;
|
||||
const scriptType = (rawScriptType || "plaintext").trim() || "plaintext";
|
||||
const lines = sourceCode.split("\n").length;
|
||||
return (
|
||||
<CodeViewer
|
||||
className={
|
||||
lines < 7
|
||||
? "min-h-[120px]"
|
||||
: lines < 17
|
||||
? "min-h-[260px]"
|
||||
: "min-h-[480px]"
|
||||
}
|
||||
fontSize={13}
|
||||
script={
|
||||
{
|
||||
script_type: scriptType,
|
||||
source_code: sourceCode,
|
||||
} as CodeSchema
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const formattedSourceCode = sourceCode.replace(/\n$/, "");
|
||||
|
||||
const preWrapperClassName = mergeClassNames(
|
||||
"not-prose mt-4 overflow-x-auto rounded-2xl border border-slate-200 bg-slate-50 px-4 py-4 text-[13px] leading-6 text-slate-900 shadow-sm dark:border-slate-800 dark:bg-slate-950/90 dark:text-slate-100",
|
||||
className
|
||||
);
|
||||
|
||||
return (
|
||||
<CodeViewer
|
||||
className={
|
||||
lines < 7
|
||||
? "min-h-[100px]"
|
||||
: lines < 17
|
||||
? "min-h-[250px]"
|
||||
: "min-h-[450px]"
|
||||
}
|
||||
key={`${Math.random()}`}
|
||||
fontSize={11}
|
||||
script={
|
||||
{
|
||||
script_type: lang,
|
||||
source_code: sourceCode,
|
||||
} as CodeSchema
|
||||
}
|
||||
/>
|
||||
<pre className={preWrapperClassName}>
|
||||
<SyntaxHighlighter
|
||||
language={lang}
|
||||
style={syntaxTheme}
|
||||
PreTag="code"
|
||||
customStyle={{
|
||||
background: "transparent",
|
||||
color: "inherit",
|
||||
margin: 0,
|
||||
padding: 0,
|
||||
fontFamily:
|
||||
"Fira Code, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace",
|
||||
fontSize: "inherit",
|
||||
lineHeight: "inherit",
|
||||
}}
|
||||
wrapLongLines={false}
|
||||
>
|
||||
{formattedSourceCode}
|
||||
</SyntaxHighlighter>
|
||||
</pre>
|
||||
);
|
||||
},
|
||||
}}
|
||||
>
|
||||
{props.markdown}
|
||||
</Markdown>
|
||||
>
|
||||
{props.markdown}
|
||||
</Markdown>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -5,10 +5,12 @@ import { useSearchContext } from "@/util/search-context";
|
||||
import { Themes } from "@/util/themes";
|
||||
import { faGithub } from "@fortawesome/free-brands-svg-icons";
|
||||
import {
|
||||
faBars,
|
||||
faHome,
|
||||
faMoon,
|
||||
faSearch,
|
||||
faSun,
|
||||
faXmark,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import {
|
||||
@@ -20,7 +22,7 @@ import {
|
||||
NavbarContent,
|
||||
NavbarItem,
|
||||
Tooltip,
|
||||
} from "@nextui-org/react";
|
||||
} from "@heroui/react";
|
||||
import { useTheme } from "next-themes";
|
||||
import { useRouter } from "next/router";
|
||||
import React from "react";
|
||||
@@ -31,20 +33,62 @@ export default function TopNavbar(props: TopNavbarProps) {
|
||||
const router = useRouter();
|
||||
const search = useSearchContext();
|
||||
const { theme, setTheme } = useTheme();
|
||||
const lightDarkModeIcon = React.useMemo(
|
||||
() => (theme === Themes.DARK ? faSun : faMoon),
|
||||
[theme]
|
||||
);
|
||||
const [mounted, setMounted] = React.useState(false);
|
||||
|
||||
React.useEffect(() => {
|
||||
setMounted(true);
|
||||
}, []);
|
||||
|
||||
const lightDarkModeIcon = React.useMemo(() => {
|
||||
if (!mounted) {
|
||||
return faMoon;
|
||||
}
|
||||
return theme === Themes.DARK ? faSun : faMoon;
|
||||
}, [mounted, theme]);
|
||||
|
||||
const [query, setQuery] = React.useState("");
|
||||
const [isMobileMenuOpen, setIsMobileMenuOpen] = React.useState(false);
|
||||
|
||||
React.useEffect(() => {
|
||||
setIsMobileMenuOpen(false);
|
||||
}, [router.pathname]);
|
||||
|
||||
const handleSearchSubmit = React.useCallback(() => {
|
||||
if (query.trim().length === 0) {
|
||||
return;
|
||||
}
|
||||
router.push({ pathname: "/search/", query: { search: query } });
|
||||
setQuery("");
|
||||
}, [query, router]);
|
||||
|
||||
const renderSearchInput = (wrapperClassName?: string) => (
|
||||
<div className={wrapperClassName}>
|
||||
<Tooltip content="Press enter to search" isOpen={query.length > 0}>
|
||||
<Input
|
||||
size="sm"
|
||||
placeholder="Search..."
|
||||
value={query}
|
||||
onChange={(e) => setQuery(e.target.value)}
|
||||
onClear={() => setQuery("")}
|
||||
startContent={<FontAwesomeIcon icon={faSearch} />}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter") {
|
||||
handleSearchSubmit();
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</Tooltip>
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<Navbar
|
||||
isBordered
|
||||
maxWidth="full"
|
||||
classNames={{
|
||||
item: [
|
||||
"flex",
|
||||
<>
|
||||
<Navbar
|
||||
isBordered
|
||||
maxWidth="full"
|
||||
classNames={{
|
||||
item: [
|
||||
"flex",
|
||||
"relative",
|
||||
"h-full",
|
||||
"items-center",
|
||||
@@ -66,7 +110,7 @@ export default function TopNavbar(props: TopNavbarProps) {
|
||||
</span>
|
||||
</NavbarBrand>
|
||||
|
||||
<NavbarContent>
|
||||
<NavbarContent className="hidden md:flex">
|
||||
<NavbarItem isActive={router.pathname === "/"}>
|
||||
<Button
|
||||
variant="light"
|
||||
@@ -101,29 +145,14 @@ export default function TopNavbar(props: TopNavbarProps) {
|
||||
</NavbarItem>
|
||||
</NavbarContent>
|
||||
|
||||
<NavbarContent as="div" justify="end">
|
||||
<Tooltip content="Press enter to search" isOpen={query.length > 0}>
|
||||
<Input
|
||||
size="sm"
|
||||
placeholder="Search..."
|
||||
value={query}
|
||||
onChange={(e) => setQuery(e.target.value)}
|
||||
onClear={() => setQuery("")}
|
||||
startContent={<FontAwesomeIcon icon={faSearch} />}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter") {
|
||||
router.push({ pathname: `/search/`, query: { search: query } });
|
||||
setQuery("");
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</Tooltip>
|
||||
|
||||
<NavbarContent as="div" justify="end" className="hidden md:flex">
|
||||
{renderSearchInput("w-64")}
|
||||
<Button
|
||||
variant="ghost"
|
||||
onPress={() => {
|
||||
setTheme(theme === Themes.DARK ? Themes.LIGHT : Themes.DARK);
|
||||
}}
|
||||
isDisabled={!mounted}
|
||||
>
|
||||
<FontAwesomeIcon icon={lightDarkModeIcon} />
|
||||
</Button>
|
||||
@@ -137,6 +166,74 @@ export default function TopNavbar(props: TopNavbarProps) {
|
||||
<FontAwesomeIcon icon={faGithub} />
|
||||
</Button>
|
||||
</NavbarContent>
|
||||
|
||||
<div className="flex items-center gap-2 md:hidden">
|
||||
<Button
|
||||
variant="ghost"
|
||||
onPress={() => {
|
||||
setTheme(theme === Themes.DARK ? Themes.LIGHT : Themes.DARK);
|
||||
}}
|
||||
isDisabled={!mounted}
|
||||
>
|
||||
<FontAwesomeIcon icon={lightDarkModeIcon} />
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
aria-label={isMobileMenuOpen ? "Close menu" : "Open menu"}
|
||||
onPress={() => setIsMobileMenuOpen((current) => !current)}
|
||||
>
|
||||
<FontAwesomeIcon icon={isMobileMenuOpen ? faXmark : faBars} />
|
||||
</Button>
|
||||
</div>
|
||||
</Navbar>
|
||||
|
||||
{isMobileMenuOpen ? (
|
||||
<div className="md:hidden border-b border-default-200 dark:border-default-100/40 bg-content1 px-4 pb-4 shadow-sm">
|
||||
<div className="mt-3">{renderSearchInput("w-full")}</div>
|
||||
<div className="mt-4 flex flex-col gap-2">
|
||||
<Button
|
||||
variant={router.pathname === "/" ? "solid" : "light"}
|
||||
color={router.pathname === "/" ? "primary" : "default"}
|
||||
onPress={() => {
|
||||
router.push("/");
|
||||
setIsMobileMenuOpen(false);
|
||||
}}
|
||||
startContent={<FontAwesomeIcon fixedWidth icon={faHome} />}
|
||||
>
|
||||
Home
|
||||
</Button>
|
||||
<Button
|
||||
variant={router.pathname.startsWith("/tutorials") ? "solid" : "light"}
|
||||
color={router.pathname.startsWith("/tutorials") ? "primary" : "default"}
|
||||
onPress={() => {
|
||||
router.push("/tutorials");
|
||||
setIsMobileMenuOpen(false);
|
||||
}}
|
||||
>
|
||||
Tutorials
|
||||
</Button>
|
||||
<Button
|
||||
variant={router.pathname.startsWith("/docs") ? "solid" : "light"}
|
||||
color={router.pathname.startsWith("/docs") ? "primary" : "default"}
|
||||
onPress={() => {
|
||||
router.push("/docs");
|
||||
setIsMobileMenuOpen(false);
|
||||
}}
|
||||
>
|
||||
Docs
|
||||
</Button>
|
||||
<Button
|
||||
variant="light"
|
||||
onPress={() => {
|
||||
window.open("https://github.com/BishopFox/sliver", "_blank");
|
||||
}}
|
||||
startContent={<FontAwesomeIcon icon={faGithub} />}
|
||||
>
|
||||
GitHub
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Button, Card, CardFooter, CardHeader } from "@nextui-org/react";
|
||||
import { Button, Card, CardFooter, CardHeader } from "@heroui/react";
|
||||
import AsciinemaPlayer from "./asciinema";
|
||||
|
||||
import { faChevronRight } from "@fortawesome/free-solid-svg-icons";
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
const { spawnSync } = require('child_process');
|
||||
const path = require('path');
|
||||
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {
|
||||
output: 'export',
|
||||
@@ -10,8 +13,13 @@ const nextConfig = {
|
||||
},
|
||||
webpack: (config, { isServer }) => {
|
||||
if (isServer) {
|
||||
require('./prebuild/generate-docs');
|
||||
require('./prebuild/generate-tutorials');
|
||||
const result = spawnSync(process.execPath, [path.join(__dirname, 'prebuild/run-prebuild.js')], {
|
||||
stdio: 'inherit',
|
||||
});
|
||||
|
||||
if (result.status !== 0) {
|
||||
throw new Error('[prebuild] webpack hook failed');
|
||||
}
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
Generated
+7304
-4093
File diff suppressed because it is too large.
Load diff
@@ -3,42 +3,50 @@
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"dev": "npm run prebuild && concurrently -k -n prebuild,dev \"npm run prebuild:watch -- --skip-initial\" \"next dev\"",
|
||||
"build": "npm run prebuild && next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint",
|
||||
"offline": "next build && zip -r www.zip ./out"
|
||||
"prebuild": "node ./prebuild/run-prebuild.js",
|
||||
"prebuild:watch": "node ./prebuild/watch.js",
|
||||
"offline": "npm run build && zip -r www.zip ./out",
|
||||
"postinstall": "node ./prebuild/run-prebuild.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fontsource/fira-code": "^5.0.16",
|
||||
"@fortawesome/free-brands-svg-icons": "^6.5.1",
|
||||
"@fortawesome/free-solid-svg-icons": "^6.5.1",
|
||||
"@fortawesome/react-fontawesome": "^0.2.0",
|
||||
"@monaco-editor/react": "^4.6.0",
|
||||
"@nextui-org/react": "^2.2.9",
|
||||
"@tanstack/react-query": "^5.13.4",
|
||||
"asciinema-player": "^3.6.3",
|
||||
"framer-motion": "^10.16.16",
|
||||
"fuse.js": "^7.0.0",
|
||||
"@fontsource/fira-code": "^5.2.7",
|
||||
"@fortawesome/fontawesome-svg-core": "^7.1.0",
|
||||
"@fortawesome/free-brands-svg-icons": "^7.1.0",
|
||||
"@fortawesome/free-solid-svg-icons": "^7.1.0",
|
||||
"@fortawesome/react-fontawesome": "^3.1.0",
|
||||
"@heroui/react": "^2.8.5",
|
||||
"@monaco-editor/react": "^4.7.0",
|
||||
"@tailwindcss/postcss": "^4.1.14",
|
||||
"@tanstack/react-query": "^5.90.2",
|
||||
"asciinema-player": "^3.11.0",
|
||||
"framer-motion": "^12.23.22",
|
||||
"fuse.js": "^7.1.0",
|
||||
"lunr": "^2.3.9",
|
||||
"next": "^14.2.22",
|
||||
"next-themes": "^0.2.1",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"react-markdown": "^9.0.1",
|
||||
"remark-gfm": "^4.0.0"
|
||||
"next": "^15.5.7",
|
||||
"next-themes": "^0.4.6",
|
||||
"react": "^19.2.0",
|
||||
"react-dom": "^19.2.0",
|
||||
"react-markdown": "^10.1.0",
|
||||
"react-syntax-highlighter": "^15.6.6",
|
||||
"remark-gfm": "^4.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/typography": "^0.5.10",
|
||||
"@tailwindcss/typography": "^0.5.19",
|
||||
"@types/lunr": "^2.3.7",
|
||||
"@types/node": "^20",
|
||||
"@types/react": "^18",
|
||||
"@types/react-dom": "^18",
|
||||
"autoprefixer": "^10.0.1",
|
||||
"eslint": "^8",
|
||||
"eslint-config-next": "14.0.4",
|
||||
"postcss": "^8",
|
||||
"tailwindcss": "^3.3.0",
|
||||
"typescript": "^5"
|
||||
"@types/node": "^24.6.2",
|
||||
"@types/react": "^19.2.0",
|
||||
"@types/react-dom": "^19.2.0",
|
||||
"@types/react-syntax-highlighter": "^15.5.13",
|
||||
"autoprefixer": "^10.4.21",
|
||||
"concurrently": "^9.1.0",
|
||||
"eslint": "^9.37.0",
|
||||
"eslint-config-next": "^15.5.4",
|
||||
"postcss": "^8.5.6",
|
||||
"tailwindcss": "^4.1.14",
|
||||
"typescript": "^5.9.3"
|
||||
}
|
||||
}
|
||||
+112
-59
@@ -1,96 +1,149 @@
|
||||
import Navbar from "@/components/navbar";
|
||||
import "@/styles/globals.css";
|
||||
import { Docs } from "@/util/docs";
|
||||
import { PREBUILD_VERSION } from "@/util/__generated__/prebuild-version";
|
||||
import { Tutorials } from "@/util/tutorials";
|
||||
import { SearchContext, SearchCtx } from "@/util/search-context";
|
||||
import { fetchDocs as fetchDocsContent, fetchTutorials as fetchTutorialsContent } from "@/util/content-fetchers";
|
||||
import { Themes } from "@/util/themes";
|
||||
import { faExternalLink } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { NextUIProvider } from "@nextui-org/react";
|
||||
import { HeroUIProvider } from "@heroui/react";
|
||||
import {
|
||||
HydrationBoundary,
|
||||
QueryClient,
|
||||
QueryClientProvider,
|
||||
} from "@tanstack/react-query";
|
||||
import { ThemeProvider as NextThemesProvider, useTheme } from "next-themes";
|
||||
import { ThemeProvider as NextThemesProvider } from "next-themes";
|
||||
import type { AppProps } from "next/app";
|
||||
import React from "react";
|
||||
|
||||
export default function App({ Component, pageProps }: AppProps) {
|
||||
// Initialize theme
|
||||
const { theme, setTheme } = useTheme();
|
||||
function getThemeState(): Themes {
|
||||
if (typeof window !== "undefined") {
|
||||
const loadedTheme = localStorage.getItem("theme");
|
||||
const currentTheme = loadedTheme ? (loadedTheme as Themes) : Themes.DARK;
|
||||
setTheme(currentTheme);
|
||||
}
|
||||
return Themes.DARK;
|
||||
}
|
||||
|
||||
// Initialize search
|
||||
const [search, setSearch] = React.useState(new SearchCtx());
|
||||
const [search] = React.useState(() => new SearchCtx());
|
||||
|
||||
// Initialize query client
|
||||
const [queryClient] = React.useState(() => new QueryClient());
|
||||
queryClient.prefetchQuery({
|
||||
queryKey: ["docs"],
|
||||
queryFn: async (): Promise<Docs> => {
|
||||
const res = await fetch("/docs.json");
|
||||
const docs: Docs = await res.json();
|
||||
search.addDocs(docs);
|
||||
return docs;
|
||||
},
|
||||
});
|
||||
const versionRef = React.useRef(PREBUILD_VERSION);
|
||||
|
||||
queryClient.prefetchQuery({
|
||||
queryKey: ["tutorials"],
|
||||
queryFn: async (): Promise<Tutorials> => {
|
||||
const res = await fetch("/tutorials.json");
|
||||
const tutorials: Tutorials = await res.json();
|
||||
search.addTutorials(tutorials);
|
||||
return tutorials;
|
||||
},
|
||||
React.useEffect(() => {
|
||||
const docsFetcher = () => fetchDocsContent(versionRef.current);
|
||||
const tutorialsFetcher = () => fetchTutorialsContent(versionRef.current);
|
||||
|
||||
queryClient.setQueryDefaults(["docs"], {
|
||||
queryFn: docsFetcher,
|
||||
});
|
||||
queryClient.setQueryDefaults(["tutorials"], {
|
||||
queryFn: tutorialsFetcher,
|
||||
});
|
||||
}, [queryClient]);
|
||||
|
||||
React.useEffect(() => {
|
||||
const syncSearch = () => {
|
||||
const docsQueries = queryClient.getQueriesData<Docs>({ queryKey: ["docs"] });
|
||||
docsQueries.forEach(([, data]) => {
|
||||
if (data) {
|
||||
search.addDocs(data);
|
||||
}
|
||||
});
|
||||
|
||||
const tutorialQueries = queryClient.getQueriesData<Tutorials>({ queryKey: ["tutorials"] });
|
||||
tutorialQueries.forEach(([, data]) => {
|
||||
if (data) {
|
||||
search.addTutorials(data);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
syncSearch();
|
||||
const unsubscribe = queryClient.getQueryCache().subscribe(syncSearch);
|
||||
return unsubscribe;
|
||||
}, [queryClient, search]);
|
||||
|
||||
React.useEffect(() => {
|
||||
const docsFetcher = () => fetchDocsContent(versionRef.current);
|
||||
const tutorialsFetcher = () => fetchTutorialsContent(versionRef.current);
|
||||
|
||||
void queryClient.prefetchQuery({
|
||||
queryKey: ["docs", versionRef.current],
|
||||
queryFn: docsFetcher,
|
||||
});
|
||||
void queryClient.prefetchQuery({
|
||||
queryKey: ["tutorials", versionRef.current],
|
||||
queryFn: tutorialsFetcher,
|
||||
});
|
||||
}, [queryClient]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (versionRef.current !== PREBUILD_VERSION) {
|
||||
versionRef.current = PREBUILD_VERSION;
|
||||
queryClient.invalidateQueries({ queryKey: ["docs"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["tutorials"] });
|
||||
|
||||
const docsFetcher = () => fetchDocsContent(versionRef.current);
|
||||
const tutorialsFetcher = () => fetchTutorialsContent(versionRef.current);
|
||||
void queryClient.prefetchQuery({
|
||||
queryKey: ["docs", versionRef.current],
|
||||
queryFn: docsFetcher,
|
||||
});
|
||||
void queryClient.prefetchQuery({
|
||||
queryKey: ["tutorials", versionRef.current],
|
||||
queryFn: tutorialsFetcher,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<NextUIProvider>
|
||||
<NextThemesProvider attribute="class" defaultTheme={getThemeState()}>
|
||||
<HeroUIProvider>
|
||||
<NextThemesProvider
|
||||
attribute="class"
|
||||
defaultTheme={Themes.DARK}
|
||||
enableSystem={false}
|
||||
storageKey="theme"
|
||||
>
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<HydrationBoundary state={pageProps.dehydratedState}>
|
||||
<SearchContext.Provider value={search}>
|
||||
<Navbar />
|
||||
<Component {...pageProps} />
|
||||
<div className="mb-12"></div>
|
||||
<footer className="fixed bottom-0 left-0 z-20 w-full p-2 bg-white border-t border-gray-200 shadow md:flex md:items-center md:justify-between md:p-6 dark:bg-black dark:border-gray-600">
|
||||
<span className="text-sm text-gray-500 sm:text-center dark:text-gray-400">
|
||||
© {new Date().getFullYear()}{" "}
|
||||
<a
|
||||
href="https://bishopfox.com/"
|
||||
className="hover:underline"
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
Bishop Fox
|
||||
</a>
|
||||
{" - "}
|
||||
<a
|
||||
href="https://github.com/BishopFox/sliver/pulls"
|
||||
rel="noreferrer"
|
||||
className="hover:underline"
|
||||
target="_blank"
|
||||
>
|
||||
You can help improve this documentation by opening a pull
|
||||
request on Github <FontAwesomeIcon icon={faExternalLink} />
|
||||
</a>
|
||||
</span>
|
||||
<ul className="flex flex-wrap items-center mt-3 text-sm font-medium text-gray-500 dark:text-gray-400 sm:mt-0">
|
||||
<div className="mb-16 md:mb-20"></div>
|
||||
<footer className="z-20 w-full border-t border-gray-200 bg-white px-3 py-4 text-center shadow dark:bg-black dark:border-gray-600 md:fixed md:bottom-0 md:left-0 md:flex md:items-center md:justify-between md:px-6 md:py-4">
|
||||
<div className="flex flex-col items-center gap-2 text-xs leading-snug text-gray-500 sm:text-sm md:flex-row md:items-center md:gap-3 md:text-left dark:text-gray-400">
|
||||
<span>
|
||||
© {new Date().getFullYear()}
|
||||
<a
|
||||
href="https://bishopfox.com/"
|
||||
className="hover:underline"
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
Bishop Fox
|
||||
</a>
|
||||
</span>
|
||||
<span className="hidden md:inline" aria-hidden="true">
|
||||
·
|
||||
</span>
|
||||
<span className="max-w-xs md:max-w-none">
|
||||
<a
|
||||
href="https://github.com/BishopFox/sliver/pulls"
|
||||
rel="noreferrer"
|
||||
className="hover:underline"
|
||||
target="_blank"
|
||||
>
|
||||
Help improve this documentation
|
||||
<span className="ml-1 inline-block">
|
||||
<FontAwesomeIcon icon={faExternalLink} />
|
||||
</span>
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
<ul className="mt-3 flex flex-wrap items-center justify-center gap-3 text-xs font-medium text-gray-500 md:mt-0 md:gap-6 md:text-sm dark:text-gray-400">
|
||||
<li>
|
||||
<a
|
||||
href="https://github.com/BishopFox/sliver/blob/master/LICENSE"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="hover:underline me-4 md:me-6"
|
||||
className="hover:underline"
|
||||
>
|
||||
GPLv3 License
|
||||
</a>
|
||||
@@ -101,6 +154,6 @@ export default function App({ Component, pageProps }: AppProps) {
|
||||
</HydrationBoundary>
|
||||
</QueryClientProvider>
|
||||
</NextThemesProvider>
|
||||
</NextUIProvider>
|
||||
</HeroUIProvider>
|
||||
);
|
||||
}
|
||||
Loaded 100 of 4488 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user