mirror of
https://github.com/BishopFox/sliver.git
synced 2026-11-08 01:38:17 -10:00
Compare commits
77
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
069d57b5e5 | ||
|
|
e023211c02 | ||
|
|
a48006640d | ||
|
|
764fd0eddf | ||
|
|
db45c4aaf9 | ||
|
|
198913d6f8 | ||
|
|
cd85824185 | ||
|
|
63797ac79c | ||
|
|
4633409623 | ||
|
|
13c2d33449 | ||
|
|
8cf478d7b0 | ||
|
|
f55215ff93 | ||
|
|
a32d81252c | ||
|
|
a1537535c4 | ||
|
|
61dd34e989 | ||
|
|
2b67cb917b | ||
|
|
ceead92ec5 | ||
|
|
df9ed94635 | ||
|
|
e891613f6f | ||
|
|
f60a0e91d3 | ||
|
|
2308314529 | ||
|
|
04bc82bca3 | ||
|
|
acdfa33231 | ||
|
|
a03592de81 | ||
|
|
5cf9d088e8 | ||
|
|
db3294b926 | ||
|
|
1847b8c24b | ||
|
|
79e4259081 | ||
|
|
9ff9b55352 | ||
|
|
9767e24edd | ||
|
|
bb572f3846 | ||
|
|
01c5b5cee4 | ||
|
|
1049dc4a98 | ||
|
|
d1b0ba13c4 | ||
|
|
2d98f14149 | ||
|
|
19e82064b1 | ||
|
|
3b72374685 | ||
|
|
20fb8c4975 | ||
|
|
68829c0a40 | ||
|
|
2c18062f4d | ||
|
|
f17ce0afbe | ||
|
|
116b12885c | ||
|
|
3d9860db6c | ||
|
|
1a6579e954 | ||
|
|
2659d848d7 | ||
|
|
df6571f63f | ||
|
|
aab1470e08 | ||
|
|
19d43fdc37 | ||
|
|
3b09e5ea80 | ||
|
|
b904d29b25 | ||
|
|
8e2b069a7d | ||
|
|
096c418d27 | ||
|
|
d9e241ccb5 | ||
|
|
086da95525 | ||
|
|
27ed557e55 | ||
|
|
af7c823508 | ||
|
|
f2a3d8ee6d | ||
|
|
de7215d2c0 | ||
|
|
2d555b16d9 | ||
|
|
597a2571fc | ||
|
|
409b4c8fdb | ||
|
|
2e72bc96b9 | ||
|
|
fa9557348e | ||
|
|
4768e36074 | ||
|
|
e53f66de72 | ||
|
|
1d33b89ec5 | ||
|
|
7b0f420290 | ||
|
|
00824d1b83 | ||
|
|
99ad05b7b7 | ||
|
|
2cdefc7369 | ||
|
|
80c752a422 | ||
|
|
8a8a9dc498 | ||
|
|
5f8540b3c4 | ||
|
|
4eef868047 | ||
|
|
5ebfecd822 | ||
|
|
9762560228 | ||
|
|
6310c7d6a0 |
No files matched your search
@@ -52,10 +52,10 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Go 1.26.2
|
||||
- name: Go 1.26.6
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: "1.26.2"
|
||||
go-version: "1.26.6"
|
||||
|
||||
- name: Install Minisign
|
||||
run: sudo apt-get update --fix-missing && sudo apt-get -y install minisign
|
||||
|
||||
@@ -16,10 +16,10 @@ jobs:
|
||||
|
||||
steps:
|
||||
# Setup go environment
|
||||
- name: Go 1.26.2
|
||||
- name: Go 1.26.6
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: "1.26.2"
|
||||
go-version: "1.26.6"
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
name: golangci-lint
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
paths:
|
||||
- ".golangci.yml"
|
||||
- ".github/workflows/golangci-lint.yml"
|
||||
- "go.mod"
|
||||
- "go.sum"
|
||||
- "go.work"
|
||||
- "go.work.sum"
|
||||
- "Makefile"
|
||||
- "vendor/**"
|
||||
- "**/*.go"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
name: golangci-lint (${{ matrix.goos }})
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
goos:
|
||||
- linux
|
||||
- darwin
|
||||
- windows
|
||||
env:
|
||||
GOOS: ${{ matrix.goos }}
|
||||
GOARCH: amd64
|
||||
CGO_ENABLED: "0"
|
||||
steps:
|
||||
- name: Check Out Code
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Go 1.26.6
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: "1.26.6"
|
||||
|
||||
- name: Run golangci-lint
|
||||
uses: golangci/golangci-lint-action@v9
|
||||
with:
|
||||
version: v2.12.2
|
||||
# Keep legacy findings visible without making them blockers.
|
||||
only-new-issues: true
|
||||
args: ./client/... ./server/... ./util/... ./protobuf/... ./docs ./implant/...
|
||||
@@ -25,10 +25,10 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 180
|
||||
steps:
|
||||
- name: Go 1.26.2
|
||||
- name: Go 1.26.6
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: "1.26.2"
|
||||
go-version: "1.26.6"
|
||||
|
||||
- name: OS Packages
|
||||
run: |
|
||||
@@ -71,10 +71,10 @@ jobs:
|
||||
runs-on: windows-latest
|
||||
timeout-minutes: 180
|
||||
steps:
|
||||
- name: Go 1.26.2
|
||||
- name: Go 1.26.6
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: "1.26.2"
|
||||
go-version: "1.26.6"
|
||||
|
||||
- name: Install make
|
||||
run: choco install make -y --no-progress
|
||||
@@ -115,10 +115,10 @@ jobs:
|
||||
runs-on: macos-latest
|
||||
timeout-minutes: 180
|
||||
steps:
|
||||
- name: Go 1.26.2
|
||||
- name: Go 1.26.6
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: "1.26.2"
|
||||
go-version: "1.26.6"
|
||||
|
||||
- name: Check Out Code
|
||||
uses: actions/checkout@v6
|
||||
@@ -153,10 +153,10 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 90
|
||||
steps:
|
||||
- name: Go 1.26.2
|
||||
- name: Go 1.26.6
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: "1.26.2"
|
||||
go-version: "1.26.6"
|
||||
|
||||
- name: Check Out Code
|
||||
uses: actions/checkout@v6
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
version: "2"
|
||||
|
||||
run:
|
||||
timeout: 10m
|
||||
modules-download-mode: vendor
|
||||
build-tags:
|
||||
- client
|
||||
- server
|
||||
- osusergo
|
||||
- netgo
|
||||
- go_sqlite
|
||||
# Raw implant entry points are Go templates; lint their supporting packages.
|
||||
- sliver_lint
|
||||
|
||||
linters:
|
||||
default: standard
|
||||
enable:
|
||||
- gocyclo
|
||||
- misspell
|
||||
- revive
|
||||
settings:
|
||||
gocyclo:
|
||||
min-complexity: 15
|
||||
|
||||
formatters:
|
||||
enable:
|
||||
- gofmt
|
||||
@@ -2,18 +2,31 @@
|
||||
# Makefile for Sliver
|
||||
#
|
||||
|
||||
.DEFAULT_GOAL := default
|
||||
|
||||
GO ?= go
|
||||
ARTIFACT_SUFFIX ?=
|
||||
ENV =
|
||||
TAGS ?= -tags go_sqlite
|
||||
CGO_ENABLED = 0
|
||||
GOLANGCI_LINT ?= golangci-lint
|
||||
# The tree has legacy lint findings, so gate issues introduced by this change.
|
||||
GOLANGCI_LINT_BASE ?= master
|
||||
GOLANGCI_LINT_ARGS ?= --new-from-merge-base=$(GOLANGCI_LINT_BASE)
|
||||
GOLANGCI_LINT_PACKAGES = \
|
||||
./client/... \
|
||||
./server/... \
|
||||
./util/... \
|
||||
./protobuf/... \
|
||||
./docs \
|
||||
./implant/...
|
||||
|
||||
ifneq (,$(findstring cgo_sqlite,$(TAGS)))
|
||||
CGO_ENABLED = 1
|
||||
endif
|
||||
|
||||
MIN_SUPPORTED_GO_MAJOR_VERSION = 1
|
||||
MIN_SUPPORTED_GO_MINOR_VERSION = 25
|
||||
MIN_SUPPORTED_GO_MINOR_VERSION = 26
|
||||
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)
|
||||
|
||||
SLIVER_PUBLIC_KEY ?= RWTZPg959v3b7tLG7VzKHRB1/QT+d3c71Uzetfa44qAoX5rH7mGoQTTR
|
||||
@@ -23,6 +36,10 @@ CLIENT_ASSETS_PKG = github.com/bishopfox/sliver/client/assets
|
||||
SLIVER_UPDATE_PKG = github.com/bishopfox/sliver/client/command/update
|
||||
PB_COMPILERS = protoc protoc-gen-go protoc-gen-go-grpc
|
||||
|
||||
.PHONY: lint
|
||||
lint:
|
||||
$(GOLANGCI_LINT) run $(GOLANGCI_LINT_ARGS) $(GOLANGCI_LINT_PACKAGES)
|
||||
|
||||
ifneq ($(OS),Windows_NT)
|
||||
|
||||
#
|
||||
|
||||
@@ -4,7 +4,7 @@ Sliver is an open source cross-platform adversary emulation/red team framework,
|
||||
|
||||
The server and client support MacOS, Windows, and Linux. Implants are supported on MacOS, Windows, and Linux (and possibly every Golang compiler target but we've not tested them all).
|
||||
|
||||
[](https://github.com/BishopFox/sliver/actions/workflows/autorelease.yml) [](https://goreportcard.com/report/github.com/BishopFox/sliver) [](https://www.gnu.org/licenses/gpl-3.0)
|
||||
[](https://github.com/BishopFox/sliver/actions/workflows/autorelease.yml) [](https://github.com/BishopFox/sliver/actions/workflows/golangci-lint.yml) [](https://www.gnu.org/licenses/gpl-3.0)
|
||||
|
||||
Visit [https://sliver.sh/](https://sliver.sh/) for tutorials and documentation.
|
||||
|
||||
|
||||
@@ -0,0 +1,251 @@
|
||||
package alias
|
||||
|
||||
/*
|
||||
Sliver Implant Framework
|
||||
Copyright (C) 2021 Bishop Fox
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// Alias commands run with cobra's DisableFlagParsing enabled (see LoadAlias),
|
||||
// the same treatment extension commands received for their arguments. Before
|
||||
// that, an unknown flag such as the payload's own `-pid` was rejected outright
|
||||
// by pflag ("unknown flag"), and operators had to inject cobra's "--"
|
||||
// separator (documented on the wiki) to pass arguments through at all (#2264).
|
||||
//
|
||||
// With flag parsing disabled cobra hands Run the raw, unstripped slice, and we
|
||||
// extract the Sliver-owned flags ourselves here. Everything we do not own is
|
||||
// passed to the payload untouched, so all of these now work:
|
||||
//
|
||||
// amsi-bypass -pid 6969
|
||||
// fakealias --process notepad.exe arg1 arg2
|
||||
// fakealias -- --anything still-here (existing workaround, unchanged)
|
||||
type ownedFlagKind int
|
||||
|
||||
const (
|
||||
ownedBool ownedFlagKind = iota
|
||||
ownedString
|
||||
ownedUint32
|
||||
ownedInt64
|
||||
)
|
||||
|
||||
// ownedFlagSpec describes one Sliver-owned flag that splitAliasArgs extracts
|
||||
// from the raw argument slice before the rest is handed to the alias payload.
|
||||
type ownedFlagSpec struct {
|
||||
long string // canonical pflag name, e.g. "process-arguments"
|
||||
short string // shorthand letter, e.g. "A" ("" if the flag has none)
|
||||
kind ownedFlagKind // how the value is consumed and validated
|
||||
}
|
||||
|
||||
// baseAliasOwnedFlags are registered for every alias command.
|
||||
var baseAliasOwnedFlags = []ownedFlagSpec{
|
||||
{long: "process", short: "p", kind: ownedString},
|
||||
{long: "process-arguments", short: "A", kind: ownedString},
|
||||
{long: "ppid", short: "P", kind: ownedUint32},
|
||||
{long: "save", short: "s", kind: ownedBool},
|
||||
{long: "timeout", short: "t", kind: ownedInt64},
|
||||
}
|
||||
|
||||
// assemblyAliasOwnedFlags are only owned when the alias wraps a .NET assembly;
|
||||
// for every other alias they are unknown tokens and pass through to the payload.
|
||||
var assemblyAliasOwnedFlags = []ownedFlagSpec{
|
||||
{long: "method", short: "m", kind: ownedString},
|
||||
{long: "class", short: "c", kind: ownedString},
|
||||
{long: "app-domain", short: "d", kind: ownedString},
|
||||
{long: "arch", short: "a", kind: ownedString},
|
||||
{long: "in-process", short: "i", kind: ownedBool},
|
||||
{long: "runtime", short: "r", kind: ownedString},
|
||||
{long: "amsi-bypass", short: "M", kind: ownedBool},
|
||||
{long: "etw-bypass", short: "E", kind: ownedBool},
|
||||
}
|
||||
|
||||
// aliasOwnedFlagSpecs returns the flag set owned by a particular alias.
|
||||
func aliasOwnedFlagSpecs(isAssembly bool) []ownedFlagSpec {
|
||||
if !isAssembly {
|
||||
return baseAliasOwnedFlags
|
||||
}
|
||||
specs := make([]ownedFlagSpec, 0, len(baseAliasOwnedFlags)+len(assemblyAliasOwnedFlags))
|
||||
specs = append(specs, baseAliasOwnedFlags...)
|
||||
return append(specs, assemblyAliasOwnedFlags...)
|
||||
}
|
||||
|
||||
// ownedFlagMatch is a raw token that spelled one of the Sliver-owned flags.
|
||||
type ownedFlagMatch struct {
|
||||
spec ownedFlagSpec
|
||||
value string // value from a "--flag=value" / "-f=value" spelling
|
||||
inline bool // whether the token carried its value inline
|
||||
}
|
||||
|
||||
// splitAliasArgs separates the Sliver-owned flags from the alias payload's own
|
||||
// arguments in a raw (DisableFlagParsing) argument slice. It accepts the long
|
||||
// forms --flag, --flag=value, --flag value and the shorthand forms -f, -f=value,
|
||||
// -f value, mirroring pflag. Two deliberate differences from pflag:
|
||||
//
|
||||
// - a glued shorthand value (-pnotepad) does NOT match --process: tokens
|
||||
// like the payload's own "-pid" must survive intact (#2264);
|
||||
// - after a literal "--" every token is copied through verbatim, preserving
|
||||
// the long-standing separator workaround.
|
||||
//
|
||||
// The returned map holds the raw string value of each flag that was provided;
|
||||
// callers re-publish the values with applyOwnedAliasFlags.
|
||||
func splitAliasArgs(raw []string, specs []ownedFlagSpec) (map[string]string, bool, []string, error) {
|
||||
values := make(map[string]string)
|
||||
extArgs := make([]string, 0, len(raw))
|
||||
byLong, byShort := ownedFlagTables(specs)
|
||||
|
||||
passthrough := false
|
||||
for i := 0; i < len(raw); i++ {
|
||||
tok := raw[i]
|
||||
|
||||
// Once we have seen "--", copy everything through untouched.
|
||||
if passthrough {
|
||||
extArgs = append(extArgs, tok)
|
||||
continue
|
||||
}
|
||||
if tok == "--" {
|
||||
passthrough = true
|
||||
continue
|
||||
}
|
||||
if tok == "--help" || tok == "-h" {
|
||||
return values, true, extArgs, nil
|
||||
}
|
||||
|
||||
match, ok := matchOwnedFlag(tok, byLong, byShort)
|
||||
if !ok {
|
||||
// Not one of ours (including glued shorthands and the payload's
|
||||
// own flags): the alias owns the token, pass it through untouched.
|
||||
extArgs = append(extArgs, tok)
|
||||
continue
|
||||
}
|
||||
i = takeOwnedValue(match, raw, i, values)
|
||||
}
|
||||
|
||||
if err := validateOwnedValues(specs, values); err != nil {
|
||||
return nil, false, nil, err
|
||||
}
|
||||
return values, false, extArgs, nil
|
||||
}
|
||||
|
||||
// ownedFlagTables indexes the specs by long name and shorthand.
|
||||
func ownedFlagTables(specs []ownedFlagSpec) (byLong, byShort map[string]ownedFlagSpec) {
|
||||
byLong = make(map[string]ownedFlagSpec, len(specs))
|
||||
byShort = make(map[string]ownedFlagSpec, len(specs))
|
||||
for _, spec := range specs {
|
||||
byLong[spec.long] = spec
|
||||
if spec.short != "" {
|
||||
byShort[spec.short] = spec
|
||||
}
|
||||
}
|
||||
return byLong, byShort
|
||||
}
|
||||
|
||||
// matchOwnedFlag checks whether tok spells one of the Sliver-owned flags, in
|
||||
// the long form (--name, --name=value) or shorthand form (-f, -f=value). A
|
||||
// glued shorthand value (-pnotepad) deliberately does not match: pflag would
|
||||
// read "-pid" as -p with value "id", which is exactly the mangling that broke
|
||||
// #2264, so such tokens must fall through to the payload.
|
||||
func matchOwnedFlag(tok string, byLong, byShort map[string]ownedFlagSpec) (ownedFlagMatch, bool) {
|
||||
var match ownedFlagMatch
|
||||
var name, value string
|
||||
var hasValue, isShort bool
|
||||
|
||||
switch {
|
||||
case strings.HasPrefix(tok, "--"):
|
||||
name, value, hasValue = strings.Cut(tok[2:], "=")
|
||||
case strings.HasPrefix(tok, "-") && len(tok) > 1:
|
||||
name, value, hasValue = strings.Cut(tok[1:], "=")
|
||||
isShort = len(name) == 1
|
||||
default:
|
||||
return match, false
|
||||
}
|
||||
|
||||
spec, ok := byLong[name]
|
||||
if isShort {
|
||||
spec, ok = byShort[name]
|
||||
}
|
||||
if !ok {
|
||||
return match, false
|
||||
}
|
||||
match.spec, match.value, match.inline = spec, value, hasValue
|
||||
return match, true
|
||||
}
|
||||
|
||||
// takeOwnedValue records the flag's value in values and returns the index of
|
||||
// the last raw token it consumed. The "--flag value" / "-f value" spellings
|
||||
// consume the following token; a bool without an inline value defaults to
|
||||
// true; a value flag as the very last token is dropped and keeps its default,
|
||||
// mirroring the extension behaviour.
|
||||
func takeOwnedValue(match ownedFlagMatch, raw []string, i int, values map[string]string) int {
|
||||
switch {
|
||||
case match.spec.kind == ownedBool:
|
||||
if !match.inline {
|
||||
match.value = "true"
|
||||
}
|
||||
values[match.spec.long] = match.value
|
||||
case match.inline:
|
||||
values[match.spec.long] = match.value
|
||||
case i+1 < len(raw):
|
||||
values[match.spec.long] = raw[i+1]
|
||||
return i + 1
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
// validateOwnedValues rejects non-numeric values for the numeric flag kinds,
|
||||
// the way pflag's typed values would have.
|
||||
func validateOwnedValues(specs []ownedFlagSpec, values map[string]string) error {
|
||||
for _, spec := range specs {
|
||||
value, provided := values[spec.long]
|
||||
if !provided {
|
||||
continue
|
||||
}
|
||||
var err error
|
||||
switch spec.kind {
|
||||
case ownedUint32:
|
||||
_, err = strconv.ParseUint(value, 10, 32)
|
||||
case ownedInt64:
|
||||
_, err = strconv.ParseInt(value, 10, 64)
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid value %q for --%s", value, spec.long)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// applyOwnedAliasFlags republishes the manually parsed Sliver-owned flag values
|
||||
// onto the command's flag set. DisableFlagParsing prevents pflag from
|
||||
// populating them, so readers such as runAliasCommand's Get* calls and
|
||||
// ActiveTarget.Request (which derives the gRPC timeout from --timeout) would
|
||||
// otherwise observe only the defaults.
|
||||
func applyOwnedAliasFlags(cmd *cobra.Command, values map[string]string) error {
|
||||
for name, value := range values {
|
||||
flag := cmd.Flags().Lookup(name)
|
||||
if flag == nil {
|
||||
continue // e.g. an assembly flag on a non-assembly alias
|
||||
}
|
||||
if err := flag.Value.Set(value); err != nil {
|
||||
return fmt.Errorf("invalid value %q for --%s: %w", value, name, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,259 @@
|
||||
package alias
|
||||
|
||||
/*
|
||||
Sliver Implant Framework
|
||||
Copyright (C) 2021 Bishop Fox
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
// TestSplitAliasArgs covers the argument passthrough regression from #2264:
|
||||
// the alias payload's own flags must reach the payload intact, while the
|
||||
// Sliver-owned flags are extracted and validated.
|
||||
func TestSplitAliasArgs(t *testing.T) {
|
||||
base := aliasOwnedFlagSpecs(false)
|
||||
assembly := aliasOwnedFlagSpecs(true)
|
||||
|
||||
cases := []struct {
|
||||
name string
|
||||
specs []ownedFlagSpec
|
||||
in []string
|
||||
values map[string]string
|
||||
help bool
|
||||
extArgs []string
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "payload flag without -- separator (#2264 regression)",
|
||||
specs: base,
|
||||
in: []string{"-pid", "6969"},
|
||||
values: map[string]string{},
|
||||
extArgs: []string{"-pid", "6969"},
|
||||
},
|
||||
{
|
||||
name: "glued shorthand is not ours and passes through",
|
||||
specs: base,
|
||||
in: []string{"-pid"},
|
||||
values: map[string]string{},
|
||||
extArgs: []string{"-pid"},
|
||||
},
|
||||
{
|
||||
name: "payload flag with -- separator (existing workaround)",
|
||||
specs: base,
|
||||
in: []string{"--", "--pid", "6969"},
|
||||
values: map[string]string{},
|
||||
extArgs: []string{"--pid", "6969"},
|
||||
},
|
||||
{
|
||||
name: "owned flag after -- belongs to the payload",
|
||||
specs: base,
|
||||
in: []string{"--", "--save"},
|
||||
values: map[string]string{},
|
||||
extArgs: []string{"--save"},
|
||||
},
|
||||
{
|
||||
name: "long flag with separate value, then payload args",
|
||||
specs: base,
|
||||
in: []string{"--process", "notepad.exe", "arg1", "arg2"},
|
||||
values: map[string]string{"process": "notepad.exe"},
|
||||
extArgs: []string{"arg1", "arg2"},
|
||||
},
|
||||
{
|
||||
name: "long flag with equals value",
|
||||
specs: base,
|
||||
in: []string{"--process=notepad.exe", "arg1"},
|
||||
values: map[string]string{"process": "notepad.exe"},
|
||||
extArgs: []string{"arg1"},
|
||||
},
|
||||
{
|
||||
name: "shorthand with separate value",
|
||||
specs: base,
|
||||
in: []string{"-p", "notepad.exe", "arg1"},
|
||||
values: map[string]string{"process": "notepad.exe"},
|
||||
extArgs: []string{"arg1"},
|
||||
},
|
||||
{
|
||||
name: "shorthand with equals value",
|
||||
specs: base,
|
||||
in: []string{"-p=notepad.exe"},
|
||||
values: map[string]string{"process": "notepad.exe"},
|
||||
extArgs: []string{},
|
||||
},
|
||||
{
|
||||
name: "bool shorthand and long false form",
|
||||
specs: base,
|
||||
in: []string{"-s", "--save=false", "arg1"},
|
||||
values: map[string]string{"save": "false"},
|
||||
extArgs: []string{"arg1"},
|
||||
},
|
||||
{
|
||||
name: "quoted value containing spaces stays a single argument",
|
||||
specs: base,
|
||||
in: []string{"-A", "-kalc -kdisable", "arg1"},
|
||||
values: map[string]string{"process-arguments": "-kalc -kdisable"},
|
||||
extArgs: []string{"arg1"},
|
||||
},
|
||||
{
|
||||
name: "valid uint32 and int64 values",
|
||||
specs: base,
|
||||
in: []string{"-P", "1234", "--timeout=90"},
|
||||
values: map[string]string{"ppid": "1234", "timeout": "90"},
|
||||
extArgs: []string{},
|
||||
},
|
||||
{
|
||||
name: "invalid uint32 value errors",
|
||||
specs: base,
|
||||
in: []string{"--ppid", "notanumber"},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "invalid int64 value errors",
|
||||
specs: base,
|
||||
in: []string{"--timeout=x"},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "assembly flags are owned for assembly aliases",
|
||||
specs: assembly,
|
||||
in: []string{"--method", "Run", "--class", "Prog", "-i", "-M", "--arch", "x64", "payloadArg"},
|
||||
values: map[string]string{
|
||||
"method": "Run", "class": "Prog", "in-process": "true",
|
||||
"amsi-bypass": "true", "arch": "x64",
|
||||
},
|
||||
extArgs: []string{"payloadArg"},
|
||||
},
|
||||
{
|
||||
name: "assembly flags pass through for non-assembly aliases",
|
||||
specs: base,
|
||||
in: []string{"--method", "Run"},
|
||||
values: map[string]string{},
|
||||
extArgs: []string{"--method", "Run"},
|
||||
},
|
||||
{
|
||||
name: "help flags are detected",
|
||||
specs: base,
|
||||
in: []string{"--help"},
|
||||
help: true,
|
||||
values: map[string]string{},
|
||||
extArgs: []string{},
|
||||
},
|
||||
{
|
||||
name: "short help is detected",
|
||||
specs: base,
|
||||
in: []string{"-h"},
|
||||
help: true,
|
||||
values: map[string]string{},
|
||||
extArgs: []string{},
|
||||
},
|
||||
{
|
||||
name: "value flag as last token keeps its default",
|
||||
specs: base,
|
||||
in: []string{"arg1", "--process"},
|
||||
values: map[string]string{},
|
||||
extArgs: []string{"arg1"},
|
||||
},
|
||||
{
|
||||
name: "empty input",
|
||||
specs: base,
|
||||
in: nil,
|
||||
values: map[string]string{},
|
||||
extArgs: []string{},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
values, help, extArgs, err := splitAliasArgs(tc.in, tc.specs)
|
||||
|
||||
if tc.wantErr {
|
||||
if err == nil {
|
||||
t.Fatalf("expected error, got values=%#v help=%v extArgs=%#v", values, help, extArgs)
|
||||
}
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
}
|
||||
if help != tc.help {
|
||||
t.Errorf("help: got %v, want %v", help, tc.help)
|
||||
}
|
||||
if !reflect.DeepEqual(values, tc.values) {
|
||||
t.Errorf("values: got %#v, want %#v", values, tc.values)
|
||||
}
|
||||
if !reflect.DeepEqual(extArgs, tc.extArgs) {
|
||||
t.Errorf("extArgs: got %#v, want %#v", extArgs, tc.extArgs)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestApplyOwnedAliasFlags checks that manually parsed values are re-published
|
||||
// on the command's flag set for every value type an alias can own.
|
||||
func TestApplyOwnedAliasFlags(t *testing.T) {
|
||||
cmd := &cobra.Command{}
|
||||
f := pflag.NewFlagSet("alias-test", pflag.ContinueOnError)
|
||||
f.StringP("process", "p", "", "host process")
|
||||
f.StringP("process-arguments", "A", "", "host process arguments")
|
||||
f.Uint32P("ppid", "P", 0, "parent pid")
|
||||
f.BoolP("save", "s", false, "save output")
|
||||
f.Int64P("timeout", "t", 60, "timeout")
|
||||
f.BoolP("amsi-bypass", "M", false, "amsi bypass")
|
||||
cmd.Flags().AddFlagSet(f)
|
||||
|
||||
err := applyOwnedAliasFlags(cmd, map[string]string{
|
||||
"process": "notepad.exe",
|
||||
"process-arguments": "-k foo",
|
||||
"ppid": "1234",
|
||||
"save": "true",
|
||||
"timeout": "90",
|
||||
"amsi-bypass": "true",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
}
|
||||
|
||||
for name, want := range map[string]interface{}{
|
||||
"process": "notepad.exe", "process-arguments": "-k foo",
|
||||
} {
|
||||
got, _ := cmd.Flags().GetString(name)
|
||||
if got != want.(string) {
|
||||
t.Errorf("%s: got %q, want %q", name, got, want)
|
||||
}
|
||||
}
|
||||
if ppid, _ := cmd.Flags().GetUint32("ppid"); ppid != 1234 {
|
||||
t.Errorf("ppid: got %d, want 1234", ppid)
|
||||
}
|
||||
if save, _ := cmd.Flags().GetBool("save"); !save {
|
||||
t.Error("save: got false, want true")
|
||||
}
|
||||
if timeout, _ := cmd.Flags().GetInt64("timeout"); timeout != 90 {
|
||||
t.Errorf("timeout: got %d, want 90", timeout)
|
||||
}
|
||||
if amsi, _ := cmd.Flags().GetBool("amsi-bypass"); !amsi {
|
||||
t.Error("amsi-bypass: got false, want true")
|
||||
}
|
||||
|
||||
// Unset flags keep their defaults.
|
||||
if inProc := cmd.Flags().Lookup("in-process"); inProc != nil {
|
||||
t.Error("in-process should not be registered on this command")
|
||||
}
|
||||
}
|
||||
@@ -215,8 +215,6 @@ func LoadAlias(manifestPath string, cmd *cobra.Command, con *console.SliverClien
|
||||
longHelp.WriteString(fmt.Sprintf("%s (%s):\t%s%s", strings.ToUpper(arg.Name), aType, optStr, arg.Desc))
|
||||
}
|
||||
}
|
||||
longHelp.WriteString("\n\n⚠️ If you're having issues passing arguments to the alias please read:\n")
|
||||
longHelp.WriteString("https://github.com/BishopFox/sliver/wiki/Aliases-&-Extensions#aliases-command-parsing")
|
||||
|
||||
// for each alias command, add a new app command
|
||||
helpMsg := fmt.Sprintf("[%s] %s", aliasManifest.Name, aliasManifest.Help)
|
||||
@@ -227,9 +225,14 @@ func LoadAlias(manifestPath string, cmd *cobra.Command, con *console.SliverClien
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
runAliasCommand(cmd, con, args)
|
||||
},
|
||||
Args: cobra.ArbitraryArgs, // a.StringList("arguments", "arguments", grumble.Default([]string{}))
|
||||
GroupID: consts.AliasHelpGroup,
|
||||
Annotations: makeAliasPlatformFilters(aliasManifest),
|
||||
Args: cobra.ArbitraryArgs, // a.StringList("arguments", "arguments", grumble.Default([]string{}))
|
||||
// DisableFlagParsing keeps the alias payload's own flags (which are
|
||||
// unknown to pflag) from being rejected or swallowed; we split the
|
||||
// Sliver-owned flags out of the raw slice ourselves in
|
||||
// runAliasCommand (#2264, same treatment as extensions).
|
||||
DisableFlagParsing: true,
|
||||
GroupID: consts.AliasHelpGroup,
|
||||
Annotations: makeAliasPlatformFilters(aliasManifest),
|
||||
}
|
||||
|
||||
if aliasManifest.IsAssembly {
|
||||
@@ -333,6 +336,27 @@ func runAliasCommand(cmd *cobra.Command, con *console.SliverClient, args []strin
|
||||
return
|
||||
}
|
||||
aliasManifest := loadedAlias.Manifest
|
||||
|
||||
// The command runs with DisableFlagParsing, so args is the raw, unstripped
|
||||
// slice. Separate the Sliver-owned flags from the payload's own arguments
|
||||
// and re-publish them on the flag set (so the Get* readers below and
|
||||
// Request()'s --timeout still work), then hand only the payload arguments
|
||||
// to the execution paths (#2264, same treatment as extensions in #2323).
|
||||
ownedValues, helpRequested, payloadArgs, err := splitAliasArgs(args, aliasOwnedFlagSpecs(aliasManifest.IsAssembly))
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
if helpRequested {
|
||||
_ = cmd.Help()
|
||||
return
|
||||
}
|
||||
if err := applyOwnedAliasFlags(cmd, ownedValues); err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
args = payloadArgs
|
||||
|
||||
binPath, err := aliasManifest.getFileForTarget(cmd.Name(), goos, goarch)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Fail to find alias file: %s\n", err)
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
package extensions
|
||||
|
||||
/*
|
||||
Sliver Implant Framework
|
||||
Copyright (C) 2021 Bishop Fox
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// splitExtensionArgs separates Sliver-owned flags (--save, --timeout, --help)
|
||||
// from the extension's own arguments in a raw argument slice.
|
||||
//
|
||||
// Extension commands run with cobra's DisableFlagParsing enabled (see
|
||||
// ExtensionRegisterCommand). Without it, pflag parses the command line first
|
||||
// and, because the extension's own flags (e.g. --type, --fqdn) are unknown to
|
||||
// pflag, ParseErrorsWhitelist.UnknownFlags causes pflag to silently drop each
|
||||
// unknown flag together with its value; the BOF argument parser never saw them
|
||||
// unless the operator injected cobra's "--" separator (#2309). Running with
|
||||
// flag parsing disabled hands us the raw, unstripped slice, so we separate the
|
||||
// Sliver-owned flags ourselves here.
|
||||
//
|
||||
// A literal "--" stops Sliver-flag scanning; every token after it is passed
|
||||
// through verbatim, preserving the long-standing workaround syntax. Unknown
|
||||
// tokens (the extension's named flags, their values and positional arguments)
|
||||
// are never consumed or reordered, so both forms work:
|
||||
//
|
||||
// delegationbof --timeout 30 --type 6 --fqdn child.htb.local
|
||||
// delegationbof -- --type 6 --fqdn child.htb.local
|
||||
func splitExtensionArgs(raw []string) (save bool, timeout int64, help bool, extArgs []string) {
|
||||
timeout = defaultTimeout
|
||||
extArgs = make([]string, 0, len(raw))
|
||||
|
||||
passthrough := false
|
||||
for i := 0; i < len(raw); i++ {
|
||||
tok := raw[i]
|
||||
|
||||
// Once we have seen "--", copy everything through untouched so the
|
||||
// existing `ext -- --foo bar` syntax keeps working identically.
|
||||
if passthrough {
|
||||
extArgs = append(extArgs, tok)
|
||||
continue
|
||||
}
|
||||
|
||||
switch {
|
||||
case tok == "--":
|
||||
passthrough = true
|
||||
|
||||
case tok == "--help" || tok == "-h":
|
||||
help = true
|
||||
|
||||
case tok == "--save" || tok == "-s":
|
||||
save = true
|
||||
|
||||
case strings.HasPrefix(tok, "--save="):
|
||||
save = parseBoolValue(tok[len("--save="):], true)
|
||||
|
||||
case tok == "--timeout" || tok == "-t":
|
||||
// Consume the following token as the value, mirroring pflag. If no
|
||||
// token follows, leave the default in place rather than erroring.
|
||||
if i+1 < len(raw) {
|
||||
if n, err := strconv.ParseInt(raw[i+1], 10, 64); err == nil {
|
||||
timeout = n
|
||||
}
|
||||
i++
|
||||
}
|
||||
|
||||
case strings.HasPrefix(tok, "--timeout="):
|
||||
if n, err := strconv.ParseInt(tok[len("--timeout="):], 10, 64); err == nil {
|
||||
timeout = n
|
||||
}
|
||||
|
||||
default:
|
||||
// Not a Sliver-owned flag: hand it to the extension parser untouched.
|
||||
extArgs = append(extArgs, tok)
|
||||
}
|
||||
}
|
||||
|
||||
return save, timeout, help, extArgs
|
||||
}
|
||||
|
||||
// applyOwnedFlags republishes the manually parsed Sliver-owned flag values back
|
||||
// onto the command's flag set. DisableFlagParsing prevents pflag from populating
|
||||
// them, so helpers that read them via cmd.Flags() (notably ActiveTarget.Request,
|
||||
// which derives the gRPC timeout from --timeout) would otherwise observe only the
|
||||
// defaults.
|
||||
func applyOwnedFlags(cmd *cobra.Command, save bool, timeout int64) {
|
||||
if flag := cmd.Flags().Lookup("timeout"); flag != nil {
|
||||
_ = flag.Value.Set(strconv.FormatInt(timeout, 10))
|
||||
}
|
||||
if flag := cmd.Flags().Lookup("save"); flag != nil {
|
||||
_ = flag.Value.Set(strconv.FormatBool(save))
|
||||
}
|
||||
}
|
||||
|
||||
// parseBoolValue parses a --flag=value bool, defaulting to defVal when the value
|
||||
// is empty (the bare-flag form). It accepts the same spellings pflag does.
|
||||
func parseBoolValue(v string, defVal bool) bool {
|
||||
switch strings.ToLower(v) {
|
||||
case "", "true", "t", "1":
|
||||
return true
|
||||
case "false", "f", "0":
|
||||
return false
|
||||
}
|
||||
return defVal
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
package extensions
|
||||
|
||||
/*
|
||||
Sliver Implant Framework
|
||||
Copyright (C) 2021 Bishop Fox
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TestSplitExtensionArgs covers the argument-passthrough regression from #2309:
|
||||
// the extension's own named flags must reach the BOF parser intact regardless of
|
||||
// the cobra "--" separator, while Sliver-owned flags are still honoured.
|
||||
func TestSplitExtensionArgs(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
in []string
|
||||
save bool
|
||||
timeout int64
|
||||
help bool
|
||||
extArgs []string
|
||||
}{
|
||||
{
|
||||
name: "named extension flags without -- separator (#2309 regression)",
|
||||
in: []string{"--type", "6", "--fqdn", "child.htb.local"},
|
||||
timeout: defaultTimeout,
|
||||
extArgs: []string{"--type", "6", "--fqdn", "child.htb.local"},
|
||||
},
|
||||
{
|
||||
name: "named extension flags with -- separator (existing workaround)",
|
||||
in: []string{"--", "--type", "6", "--fqdn", "child.htb.local"},
|
||||
timeout: defaultTimeout,
|
||||
extArgs: []string{"--type", "6", "--fqdn", "child.htb.local"},
|
||||
},
|
||||
{
|
||||
name: "sliver-owned flags precede extension arguments",
|
||||
in: []string{"--timeout", "30", "--save", "--type", "6"},
|
||||
save: true,
|
||||
timeout: 30,
|
||||
extArgs: []string{"--type", "6"},
|
||||
},
|
||||
{
|
||||
name: "quoted value containing spaces stays a single argument",
|
||||
in: []string{"--name", "hello world", "--type", "6"},
|
||||
timeout: defaultTimeout,
|
||||
extArgs: []string{"--name", "hello world", "--type", "6"},
|
||||
},
|
||||
{
|
||||
name: "positional extension arguments are preserved",
|
||||
in: []string{"foo", "bar", "baz"},
|
||||
timeout: defaultTimeout,
|
||||
extArgs: []string{"foo", "bar", "baz"},
|
||||
},
|
||||
{
|
||||
name: "single-dash and double-dash forms are preserved",
|
||||
in: []string{"-type", "6", "--fqdn", "child.htb.local"},
|
||||
timeout: defaultTimeout,
|
||||
extArgs: []string{"-type", "6", "--fqdn", "child.htb.local"},
|
||||
},
|
||||
{
|
||||
name: "equals form for timeout",
|
||||
in: []string{"--timeout=120", "--type", "6"},
|
||||
timeout: 120,
|
||||
extArgs: []string{"--type", "6"},
|
||||
},
|
||||
{
|
||||
name: "short -s save flag",
|
||||
in: []string{"-s", "--type", "6"},
|
||||
save: true,
|
||||
timeout: defaultTimeout,
|
||||
extArgs: []string{"--type", "6"},
|
||||
},
|
||||
{
|
||||
name: "help flag is detected",
|
||||
in: []string{"--help"},
|
||||
help: true,
|
||||
timeout: defaultTimeout,
|
||||
extArgs: []string{},
|
||||
},
|
||||
{
|
||||
name: "empty input",
|
||||
in: nil,
|
||||
timeout: defaultTimeout,
|
||||
extArgs: []string{},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
save, timeout, help, extArgs := splitExtensionArgs(tc.in)
|
||||
|
||||
if save != tc.save {
|
||||
t.Errorf("save: got %v, want %v", save, tc.save)
|
||||
}
|
||||
if timeout != tc.timeout {
|
||||
t.Errorf("timeout: got %d, want %d", timeout, tc.timeout)
|
||||
}
|
||||
if help != tc.help {
|
||||
t.Errorf("help: got %v, want %v", help, tc.help)
|
||||
}
|
||||
if !reflect.DeepEqual(extArgs, tc.extArgs) {
|
||||
t.Errorf("extArgs: got %#v, want %#v", extArgs, tc.extArgs)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestParseBoolValue checks the --flag=value helper used for --save=value.
|
||||
func TestParseBoolValue(t *testing.T) {
|
||||
cases := []struct {
|
||||
in string
|
||||
want bool
|
||||
}{
|
||||
{"", true},
|
||||
{"true", true},
|
||||
{"TRUE", true},
|
||||
{"1", true},
|
||||
{"t", true},
|
||||
{"false", false},
|
||||
{"0", false},
|
||||
{"no", false}, // unsupported spellings keep the default
|
||||
}
|
||||
for _, tc := range cases {
|
||||
got := parseBoolValue(tc.in, true)
|
||||
// "no" is not a pflag spelling, so it falls through to the default (true).
|
||||
want := tc.want
|
||||
if tc.in == "no" {
|
||||
want = true
|
||||
}
|
||||
if got != want {
|
||||
t.Errorf("parseBoolValue(%q): got %v, want %v", tc.in, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -370,8 +370,12 @@ func ExtensionRegisterCommand(extCmd *ExtCommand, cmd *cobra.Command, con *conso
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
runExtensionCmd(cmd, con, args)
|
||||
},
|
||||
GroupID: consts.ExtensionHelpGroup,
|
||||
Annotations: makeCommandPlatformFilters(extCmd),
|
||||
GroupID: consts.ExtensionHelpGroup,
|
||||
// DisableFlagParsing keeps the extension's own flags (which are unknown to
|
||||
// pflag) from being silently stripped together with their values. We split
|
||||
// Sliver-owned flags out of the raw slice ourselves in runExtensionCmd (#2309).
|
||||
DisableFlagParsing: true,
|
||||
Annotations: makeCommandPlatformFilters(extCmd),
|
||||
}
|
||||
|
||||
// Flags
|
||||
@@ -379,7 +383,6 @@ func ExtensionRegisterCommand(extCmd *ExtCommand, cmd *cobra.Command, con *conso
|
||||
f.BoolP("save", "s", false, "Save output to disk")
|
||||
f.Int64P("timeout", "t", defaultTimeout, "command timeout in seconds")
|
||||
extensionCmd.Flags().AddFlagSet(f)
|
||||
extensionCmd.Flags().ParseErrorsWhitelist.UnknownFlags = true
|
||||
|
||||
// Completions
|
||||
comps := carapace.Gen(extensionCmd)
|
||||
@@ -529,6 +532,18 @@ func loadDep(goos string, goarch string, depName string, cmd *cobra.Command, con
|
||||
}
|
||||
|
||||
func runExtensionCmd(cmd *cobra.Command, con *console.SliverClient, args []string) {
|
||||
// The command runs with DisableFlagParsing, so args is the raw, unstripped
|
||||
// slice. Separate Sliver-owned flags from the extension's own arguments and
|
||||
// re-publish them on the flag set (so Request()'s --timeout still works),
|
||||
// then feed only the extension arguments to the BOF/DLL parsers (#2309).
|
||||
save, timeout, helpRequested, extArgs := splitExtensionArgs(args)
|
||||
if helpRequested {
|
||||
_ = cmd.Help()
|
||||
return
|
||||
}
|
||||
applyOwnedFlags(cmd, save, timeout)
|
||||
args = extArgs
|
||||
|
||||
var (
|
||||
err error
|
||||
extensionArgs []byte
|
||||
|
||||
@@ -159,7 +159,7 @@ func Commands(con *console.SliverClient) []*cobra.Command {
|
||||
f.StringP("save", "s", "", "directory/file to the binary to")
|
||||
f.String("shellcode-encoder", "", "shellcode encoder to apply (optional; see `shellcode-encoders`)")
|
||||
f.StringP("name", "n", "", "Implant name")
|
||||
|
||||
f.BoolP("external-builder", "E", false, "use an external builder")
|
||||
})
|
||||
flags.BindFlagCompletions(profilesGenerateCmd, func(comp *carapace.ActionMap) {
|
||||
(*comp)["save"] = carapace.ActionFiles().Tag("directory/file to save implant")
|
||||
@@ -367,7 +367,7 @@ func coreImplantFlags(name string, cmd *cobra.Command) {
|
||||
f.StringP("limit-locale", "L", "", "limit execution to hosts that match this locale")
|
||||
bindSpoofMetadataFlag(f)
|
||||
|
||||
f.StringP("format", "f", "exe", "Specifies the output formats, valid values are: 'exe', 'shared' (for dynamic libraries), 'service' (see: `psexec` for more info) and 'shellcode' (windows, darwin/arm64, linux/amd64, linux/arm64)")
|
||||
f.StringP("format", "f", "exe", "Specifies the output formats, valid values are: 'exe', 'shared' (for dynamic libraries), 'archive' (for Go c-archives), 'service' (see: `psexec` for more info) and 'shellcode' (windows, darwin/arm64, linux/amd64, linux/arm64)")
|
||||
|
||||
// Shellcode generation options:
|
||||
// - Windows: Donut
|
||||
|
||||
@@ -24,6 +24,30 @@ func TestGenerateSaveFlagCompletionRegistered(t *testing.T) {
|
||||
assertFlagHasDefaultFileCompletion(t, beaconCmd, "save")
|
||||
}
|
||||
|
||||
func TestProfilesGenerateExternalBuilderFlagRegistered(t *testing.T) {
|
||||
cmds := Commands(&console.SliverClient{})
|
||||
|
||||
profilesCmd := commandByUse(cmds, consts.ProfilesStr)
|
||||
if profilesCmd == nil {
|
||||
t.Fatalf("missing %q command", consts.ProfilesStr)
|
||||
}
|
||||
profilesGenerateCmd := commandByUse(profilesCmd.Commands(), consts.GenerateStr)
|
||||
if profilesGenerateCmd == nil {
|
||||
t.Fatalf("missing %q subcommand under %q", consts.GenerateStr, consts.ProfilesStr)
|
||||
}
|
||||
|
||||
flag := profilesGenerateCmd.Flags().Lookup("external-builder")
|
||||
if flag == nil {
|
||||
t.Fatalf("%q missing %q flag", profilesGenerateCmd.Use, "external-builder")
|
||||
}
|
||||
if flag.Shorthand != "E" {
|
||||
t.Fatalf("%q %q flag shorthand mismatch: got=%q want=%q", profilesGenerateCmd.Use, "external-builder", flag.Shorthand, "E")
|
||||
}
|
||||
if flag.DefValue != "false" {
|
||||
t.Fatalf("%q %q flag default mismatch: got=%q want=%q", profilesGenerateCmd.Use, "external-builder", flag.DefValue, "false")
|
||||
}
|
||||
}
|
||||
|
||||
func assertFlagHasDefaultFileCompletion(t *testing.T, cmd *cobra.Command, flag string) {
|
||||
t.Helper()
|
||||
|
||||
|
||||
@@ -254,6 +254,8 @@ func nameOfOutputFormat(value clientpb.OutputFormat) string {
|
||||
return "Service"
|
||||
case clientpb.OutputFormat_SHARED_LIB:
|
||||
return "Shared Library"
|
||||
case clientpb.OutputFormat_GO_ARCHIVE:
|
||||
return "Go Archive"
|
||||
case clientpb.OutputFormat_SHELLCODE:
|
||||
return "Shellcode"
|
||||
default:
|
||||
@@ -389,6 +391,9 @@ func parseCompileFlags(cmd *cobra.Command, con *console.SliverClient) (string, *
|
||||
configFormat = clientpb.OutputFormat_SHARED_LIB
|
||||
isSharedLib = true
|
||||
runAtLoad, _ = cmd.Flags().GetBool("run-at-load")
|
||||
case "archive":
|
||||
configFormat = clientpb.OutputFormat_GO_ARCHIVE
|
||||
isSharedLib = true
|
||||
case "shellcode":
|
||||
configFormat = clientpb.OutputFormat_SHELLCODE
|
||||
isShellcode = true
|
||||
|
||||
@@ -197,7 +197,7 @@ func OSCompleter(con *console.SliverClient) carapace.Action {
|
||||
func FormatCompleter() carapace.Action {
|
||||
return carapace.ActionCallback(func(_ carapace.Context) carapace.Action {
|
||||
return carapace.ActionValues([]string{
|
||||
"exe", "shared", "service", "shellcode",
|
||||
"exe", "shared", "archive", "service", "shellcode",
|
||||
}...).Tag("implant format")
|
||||
})
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
package generate
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
)
|
||||
|
||||
func TestNameOfOutputFormatGoArchive(t *testing.T) {
|
||||
if got := nameOfOutputFormat(clientpb.OutputFormat_GO_ARCHIVE); got != "Go Archive" {
|
||||
t.Fatalf("nameOfOutputFormat(GO_ARCHIVE) = %q, want %q", got, "Go Archive")
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,7 @@ package generate
|
||||
*/
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
@@ -81,9 +82,27 @@ func ProfilesGenerateCmd(cmd *cobra.Command, con *console.SliverClient, args []s
|
||||
profile.Config.SGNEnabled = encoder == clientpb.ShellcodeEncoder_SHIKATA_GA_NAI
|
||||
}
|
||||
}
|
||||
_, err := compile(implantName, profile.Config, nil, save, con)
|
||||
if err != nil {
|
||||
return
|
||||
if external, _ := cmd.Flags().GetBool("external-builder"); !external {
|
||||
_, err := compile(implantName, profile.Config, nil, save, con)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
_, err := externalBuild(implantName, profile.Config, nil, save, con)
|
||||
if err != nil {
|
||||
switch err {
|
||||
case ErrNoExternalBuilder:
|
||||
con.PrintErrorf("There are no external builders currently connected to the server\n")
|
||||
con.PrintErrorf("See 'builders' command for more information\n")
|
||||
case ErrNoValidBuilders:
|
||||
con.PrintErrorf("There are external builders connected to the server, but none can build the target you specified\n")
|
||||
con.PrintErrorf("Invalid target %s\n", fmt.Sprintf("%s:%s/%s", profile.Config.Format, profile.Config.GOOS, profile.Config.GOARCH))
|
||||
con.PrintErrorf("See 'builders' command for more information\n")
|
||||
default:
|
||||
con.PrintErrorf("%s\n", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
} else {
|
||||
con.PrintErrorf("No profile with name '%s'", name)
|
||||
|
||||
@@ -263,6 +263,8 @@ func populateProfileProperties(config *clientpb.ImplantConfig) map[string]string
|
||||
properties["format"] = "Executable"
|
||||
case clientpb.OutputFormat_SHARED_LIB:
|
||||
properties["format"] = "Shared Library"
|
||||
case clientpb.OutputFormat_GO_ARCHIVE:
|
||||
properties["format"] = "Go Archive"
|
||||
case clientpb.OutputFormat_SERVICE:
|
||||
properties["format"] = "Service"
|
||||
case clientpb.OutputFormat_SHELLCODE:
|
||||
|
||||
@@ -79,6 +79,7 @@ func GenerateProfilesNewForm() (*GenerateProfilesNewFormResult, error) {
|
||||
options := []huh.Option[string]{
|
||||
huh.NewOption("Executable", "exe"),
|
||||
huh.NewOption("Shared library", "shared"),
|
||||
huh.NewOption("Go archive", "archive"),
|
||||
}
|
||||
if result.OS == "windows" {
|
||||
options = append(options,
|
||||
|
||||
@@ -84,6 +84,7 @@ func GenerateProfilesNewBeaconForm() (*GenerateProfilesNewBeaconFormResult, erro
|
||||
options := []huh.Option[string]{
|
||||
huh.NewOption("Executable", "exe"),
|
||||
huh.NewOption("Shared library", "shared"),
|
||||
huh.NewOption("Go archive", "archive"),
|
||||
}
|
||||
if result.OS == "windows" {
|
||||
options = append(options,
|
||||
|
||||
@@ -22,6 +22,7 @@ type targetOptionBindings struct {
|
||||
var formatOptionOrder = []formatOption{
|
||||
{format: clientpb.OutputFormat_EXECUTABLE, label: "Executable", value: "exe"},
|
||||
{format: clientpb.OutputFormat_SHARED_LIB, label: "Shared library", value: "shared"},
|
||||
{format: clientpb.OutputFormat_GO_ARCHIVE, label: "Go archive", value: "archive"},
|
||||
{format: clientpb.OutputFormat_SERVICE, label: "Service", value: "service"},
|
||||
{format: clientpb.OutputFormat_SHELLCODE, label: "Shellcode", value: "shellcode"},
|
||||
}
|
||||
@@ -59,6 +60,7 @@ func commonFormatOptions(goos string) []huh.Option[string] {
|
||||
options := []huh.Option[string]{
|
||||
huh.NewOption("Executable", "exe"),
|
||||
huh.NewOption("Shared library", "shared"),
|
||||
huh.NewOption("Go archive", "archive"),
|
||||
}
|
||||
if goos == "windows" {
|
||||
options = append(options,
|
||||
|
||||
@@ -3,6 +3,8 @@ import React from "react";
|
||||
|
||||
type AsciinemaPlayerProps = {
|
||||
src: string;
|
||||
className?: string;
|
||||
hideControls?: boolean;
|
||||
|
||||
cols?: string;
|
||||
rows?: string;
|
||||
@@ -18,10 +20,67 @@ type AsciinemaPlayerProps = {
|
||||
fontSize?: string;
|
||||
};
|
||||
|
||||
function AsciinemaPlayer({ src, ...asciinemaOptions }: AsciinemaPlayerProps) {
|
||||
function AsciinemaPlayer({
|
||||
src,
|
||||
className,
|
||||
hideControls,
|
||||
cols,
|
||||
rows,
|
||||
autoPlay,
|
||||
preload,
|
||||
loop,
|
||||
startAt,
|
||||
speed,
|
||||
idleTimeLimit,
|
||||
theme,
|
||||
poster,
|
||||
fit,
|
||||
fontSize,
|
||||
}: AsciinemaPlayerProps) {
|
||||
const ref = React.useRef<HTMLDivElement>(null);
|
||||
const [prefersReducedMotion, setPrefersReducedMotion] = React.useState(false);
|
||||
const [player, setPlayer] =
|
||||
React.useState<typeof import("asciinema-player")>();
|
||||
const asciinemaOptions = React.useMemo(
|
||||
() => ({
|
||||
autoPlay: prefersReducedMotion ? false : autoPlay,
|
||||
cols,
|
||||
controls: hideControls ? false : undefined,
|
||||
fit,
|
||||
fontSize,
|
||||
idleTimeLimit,
|
||||
loop: prefersReducedMotion ? false : loop,
|
||||
poster,
|
||||
preload,
|
||||
rows,
|
||||
speed,
|
||||
startAt,
|
||||
theme,
|
||||
}),
|
||||
[
|
||||
autoPlay,
|
||||
cols,
|
||||
fit,
|
||||
fontSize,
|
||||
hideControls,
|
||||
idleTimeLimit,
|
||||
loop,
|
||||
poster,
|
||||
preload,
|
||||
prefersReducedMotion,
|
||||
rows,
|
||||
speed,
|
||||
startAt,
|
||||
theme,
|
||||
],
|
||||
);
|
||||
React.useEffect(() => {
|
||||
const mediaQuery = window.matchMedia("(prefers-reduced-motion: reduce)");
|
||||
const syncPreference = () => setPrefersReducedMotion(mediaQuery.matches);
|
||||
syncPreference();
|
||||
mediaQuery.addEventListener("change", syncPreference);
|
||||
return () => mediaQuery.removeEventListener("change", syncPreference);
|
||||
}, []);
|
||||
React.useEffect(() => {
|
||||
import("asciinema-player").then((p) => {
|
||||
setPlayer(p);
|
||||
@@ -35,7 +94,17 @@ function AsciinemaPlayer({ src, ...asciinemaOptions }: AsciinemaPlayerProps) {
|
||||
};
|
||||
}, [src, player, asciinemaOptions]);
|
||||
|
||||
return <div ref={ref} />;
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
className={[
|
||||
className,
|
||||
hideControls ? "sliver-asciinema-controls-hidden" : undefined,
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(" ")}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default AsciinemaPlayer;
|
||||
@@ -60,11 +60,8 @@ const CodeViewer = (props: CodeViewerProps) => {
|
||||
props.script.source_code
|
||||
);
|
||||
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"
|
||||
: "col-span-12 mt-4 rounded-2xl overflow-hidden border border-gray-300";
|
||||
}, [theme]);
|
||||
const editorContainerClassName =
|
||||
"col-span-12 mt-4 overflow-hidden rounded-2xl border border-separator bg-surface-secondary";
|
||||
|
||||
return (
|
||||
<div className={editorContainerClassName}>
|
||||
|
||||
@@ -3,9 +3,9 @@ import React from "react";
|
||||
|
||||
const LoadingState: React.FC = () => {
|
||||
return (
|
||||
<div className="flex min-h-screen w-full items-center justify-center gap-3 text-foreground">
|
||||
<div className="flex min-h-[55vh] w-full items-center justify-center gap-3 text-muted">
|
||||
<Spinner aria-label="Loading" />
|
||||
<span>Loading...</span>
|
||||
<span className="text-sm">Loading documentation…</span>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -27,6 +27,7 @@ import Youtube from "./youtube";
|
||||
|
||||
export type MarkdownProps = {
|
||||
markdown: string;
|
||||
demoteTopLevelHeading?: boolean;
|
||||
};
|
||||
|
||||
type MarkdownAsciiCast = {
|
||||
@@ -121,12 +122,12 @@ const slugify = (value: string) => {
|
||||
};
|
||||
|
||||
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",
|
||||
1: "mt-12 text-3xl font-semibold tracking-tight text-foreground first:mt-0",
|
||||
2: "mt-12 text-2xl font-semibold tracking-tight text-foreground",
|
||||
3: "mt-9 text-xl font-semibold tracking-tight text-foreground",
|
||||
4: "mt-8 text-lg font-semibold tracking-tight text-foreground",
|
||||
5: "mt-7 text-base font-semibold tracking-tight text-foreground",
|
||||
6: "mt-7 text-base font-semibold tracking-tight text-foreground",
|
||||
};
|
||||
|
||||
const MarkdownViewer = (props: MarkdownProps) => {
|
||||
@@ -218,7 +219,9 @@ const MarkdownViewer = (props: MarkdownProps) => {
|
||||
}
|
||||
|
||||
const anchor = anchorRef.current;
|
||||
const HeadingTag = `h${level}`;
|
||||
const renderedLevel =
|
||||
level === 1 && props.demoteTopLevelHeading ? 2 : level;
|
||||
const HeadingTag = `h${renderedLevel}`;
|
||||
|
||||
return createElement(
|
||||
HeadingTag,
|
||||
@@ -226,7 +229,7 @@ const MarkdownViewer = (props: MarkdownProps) => {
|
||||
...rest,
|
||||
id: anchor || undefined,
|
||||
className: mergeClassNames(
|
||||
headingClassNames[level],
|
||||
headingClassNames[renderedLevel],
|
||||
"scroll-mt-[70px]",
|
||||
className
|
||||
),
|
||||
@@ -236,8 +239,8 @@ const MarkdownViewer = (props: MarkdownProps) => {
|
||||
{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"
|
||||
aria-label={`Link to ${textContent}`}
|
||||
className="-my-2 inline-flex size-10 items-center justify-center rounded-xl text-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent/40 hover:bg-surface-secondary hover:text-accent"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
@@ -283,12 +286,12 @@ const MarkdownViewer = (props: MarkdownProps) => {
|
||||
h5: createHeadingComponent(5),
|
||||
h6: createHeadingComponent(6),
|
||||
};
|
||||
}, [getAnchor]);
|
||||
}, [getAnchor, props.demoteTopLevelHeading]);
|
||||
|
||||
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"
|
||||
"prose-code:font-mono prose-img:rounded-2xl"
|
||||
);
|
||||
|
||||
return (
|
||||
@@ -307,7 +310,7 @@ const MarkdownViewer = (props: MarkdownProps) => {
|
||||
{...rest}
|
||||
href={href}
|
||||
className={mergeClassNames(
|
||||
"font-medium text-primary transition-colors duration-150 hover:text-primary-dark",
|
||||
"font-medium text-accent underline-offset-4 hover:underline",
|
||||
className
|
||||
)}
|
||||
onClick={(e) => {
|
||||
@@ -342,7 +345,7 @@ const MarkdownViewer = (props: MarkdownProps) => {
|
||||
}
|
||||
|
||||
const anchorClassName = mergeClassNames(
|
||||
"font-medium text-primary transition-colors duration-150 underline-offset-4 hover:text-primary-dark",
|
||||
"font-medium text-accent underline-offset-4 hover:underline",
|
||||
className
|
||||
);
|
||||
|
||||
@@ -376,7 +379,7 @@ const MarkdownViewer = (props: MarkdownProps) => {
|
||||
<p
|
||||
{...rest}
|
||||
className={mergeClassNames(
|
||||
"my-6 text-base leading-7 text-slate-700 dark:text-slate-300",
|
||||
"my-6 text-base leading-7 text-foreground/80",
|
||||
className
|
||||
)}
|
||||
>
|
||||
@@ -391,7 +394,7 @@ const MarkdownViewer = (props: MarkdownProps) => {
|
||||
<ul
|
||||
{...rest}
|
||||
className={mergeClassNames(
|
||||
"my-6 list-disc space-y-2 pl-6 text-slate-700 marker:text-primary dark:text-slate-300",
|
||||
"my-6 list-disc space-y-2 pl-6 text-foreground/80 marker:text-accent",
|
||||
className
|
||||
)}
|
||||
>
|
||||
@@ -406,7 +409,7 @@ const MarkdownViewer = (props: MarkdownProps) => {
|
||||
<ol
|
||||
{...rest}
|
||||
className={mergeClassNames(
|
||||
"my-6 list-decimal space-y-2 pl-6 text-slate-700 marker:text-primary dark:text-slate-300",
|
||||
"my-6 list-decimal space-y-2 pl-6 text-foreground/80 marker:text-accent",
|
||||
className
|
||||
)}
|
||||
>
|
||||
@@ -421,7 +424,7 @@ const MarkdownViewer = (props: MarkdownProps) => {
|
||||
<li
|
||||
{...rest}
|
||||
className={mergeClassNames(
|
||||
"leading-6 text-slate-700 dark:text-slate-300",
|
||||
"leading-6 text-foreground/80",
|
||||
className
|
||||
)}
|
||||
>
|
||||
@@ -436,7 +439,7 @@ const MarkdownViewer = (props: MarkdownProps) => {
|
||||
<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",
|
||||
"my-8 rounded-r-2xl border-l-4 border-accent/40 bg-surface-secondary px-6 py-4 text-base italic text-foreground/80",
|
||||
className
|
||||
)}
|
||||
>
|
||||
@@ -451,7 +454,7 @@ const MarkdownViewer = (props: MarkdownProps) => {
|
||||
<hr
|
||||
{...rest}
|
||||
className={mergeClassNames(
|
||||
"my-12 border-t border-slate-200 dark:border-slate-800",
|
||||
"my-12 border-t border-separator",
|
||||
className
|
||||
)}
|
||||
/>
|
||||
@@ -461,11 +464,11 @@ const MarkdownViewer = (props: MarkdownProps) => {
|
||||
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">
|
||||
<div className="sliver-scrollbar my-8 overflow-x-auto rounded-2xl border border-separator bg-surface">
|
||||
<table
|
||||
{...rest}
|
||||
className={mergeClassNames(
|
||||
"w-full min-w-max divide-y divide-slate-200 text-left text-sm dark:divide-slate-800",
|
||||
"w-full min-w-max divide-y divide-separator text-left text-sm",
|
||||
className
|
||||
)}
|
||||
>
|
||||
@@ -481,7 +484,7 @@ const MarkdownViewer = (props: MarkdownProps) => {
|
||||
<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",
|
||||
"bg-surface-secondary text-sm font-semibold text-muted",
|
||||
className
|
||||
)}
|
||||
>
|
||||
@@ -496,7 +499,7 @@ const MarkdownViewer = (props: MarkdownProps) => {
|
||||
<tbody
|
||||
{...rest}
|
||||
className={mergeClassNames(
|
||||
"divide-y divide-slate-200 dark:divide-slate-800",
|
||||
"divide-y divide-separator",
|
||||
className
|
||||
)}
|
||||
>
|
||||
@@ -511,7 +514,7 @@ const MarkdownViewer = (props: MarkdownProps) => {
|
||||
<tr
|
||||
{...rest}
|
||||
className={mergeClassNames(
|
||||
"transition-colors hover:bg-slate-50 dark:hover:bg-slate-900/60",
|
||||
"bg-transparent",
|
||||
className
|
||||
)}
|
||||
>
|
||||
@@ -526,7 +529,7 @@ const MarkdownViewer = (props: MarkdownProps) => {
|
||||
<th
|
||||
{...rest}
|
||||
className={mergeClassNames(
|
||||
"px-4 py-3 text-left text-sm font-semibold text-slate-600 dark:text-slate-200",
|
||||
"px-4 py-3 text-left text-sm font-semibold text-foreground",
|
||||
className
|
||||
)}
|
||||
>
|
||||
@@ -541,7 +544,7 @@ const MarkdownViewer = (props: MarkdownProps) => {
|
||||
<td
|
||||
{...rest}
|
||||
className={mergeClassNames(
|
||||
"px-4 py-3 align-top text-sm text-slate-700 dark:text-slate-300",
|
||||
"px-4 py-3 align-top text-sm text-foreground/80",
|
||||
className
|
||||
)}
|
||||
>
|
||||
@@ -556,7 +559,7 @@ const MarkdownViewer = (props: MarkdownProps) => {
|
||||
<strong
|
||||
{...rest}
|
||||
className={mergeClassNames(
|
||||
"font-semibold text-slate-900 dark:text-slate-100",
|
||||
"font-semibold text-foreground",
|
||||
className
|
||||
)}
|
||||
>
|
||||
@@ -571,7 +574,7 @@ const MarkdownViewer = (props: MarkdownProps) => {
|
||||
<em
|
||||
{...rest}
|
||||
className={mergeClassNames(
|
||||
"text-slate-700 dark:text-slate-300",
|
||||
"text-foreground/80",
|
||||
className
|
||||
)}
|
||||
>
|
||||
@@ -605,7 +608,7 @@ const MarkdownViewer = (props: MarkdownProps) => {
|
||||
<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",
|
||||
"sliver-scrollbar my-6 overflow-x-auto rounded-2xl border border-separator bg-surface-secondary p-4 text-[13px] leading-6 text-foreground",
|
||||
className
|
||||
)}
|
||||
>
|
||||
@@ -625,7 +628,7 @@ const MarkdownViewer = (props: MarkdownProps) => {
|
||||
width={1200}
|
||||
height={720}
|
||||
className={mergeClassNames(
|
||||
"my-8 w-full rounded-xl border border-slate-200 object-contain shadow-sm dark:border-slate-800",
|
||||
"my-8 w-full rounded-2xl border border-separator/70 object-contain",
|
||||
className
|
||||
)}
|
||||
/>
|
||||
@@ -655,7 +658,11 @@ const MarkdownViewer = (props: MarkdownProps) => {
|
||||
|
||||
if (normalizedLang === "youtube") {
|
||||
const embedId = sourceCode || "";
|
||||
return <Youtube embedId={embedId.trim()} />;
|
||||
return (
|
||||
<div className="not-prose my-8 overflow-hidden rounded-2xl">
|
||||
<Youtube embedId={embedId.trim()} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (normalizedLang === "asciinema") {
|
||||
@@ -668,15 +675,18 @@ const MarkdownViewer = (props: MarkdownProps) => {
|
||||
return <></>;
|
||||
}
|
||||
return (
|
||||
<AsciinemaPlayer
|
||||
src={srcUrl.toString()}
|
||||
rows={asciiCast.rows || "18"}
|
||||
cols={asciiCast.cols || "75"}
|
||||
idleTimeLimit={asciiCast.idleTimeLimit || 2}
|
||||
preload={true}
|
||||
autoPlay={true}
|
||||
loop={true}
|
||||
/>
|
||||
<div className="sliver-terminal-frame not-prose my-8 w-full max-w-full overflow-x-auto rounded-2xl bg-[#111315]">
|
||||
<AsciinemaPlayer
|
||||
className="min-w-[42rem]"
|
||||
src={srcUrl.toString()}
|
||||
rows={asciiCast.rows || "18"}
|
||||
cols={asciiCast.cols || "75"}
|
||||
idleTimeLimit={asciiCast.idleTimeLimit || 2}
|
||||
preload={true}
|
||||
autoPlay={true}
|
||||
loop={true}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -694,7 +704,7 @@ const MarkdownViewer = (props: MarkdownProps) => {
|
||||
<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",
|
||||
"rounded-md bg-surface-secondary px-1.5 py-0.5 font-mono text-[13px] text-foreground",
|
||||
className
|
||||
)}
|
||||
>
|
||||
@@ -752,7 +762,7 @@ const MarkdownViewer = (props: MarkdownProps) => {
|
||||
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",
|
||||
"sliver-scrollbar not-prose mt-4 overflow-x-auto rounded-2xl border border-separator bg-surface-secondary px-4 py-4 text-[13px] leading-6 text-foreground",
|
||||
className
|
||||
);
|
||||
|
||||
|
||||
@@ -115,7 +115,7 @@ const Mermaid = ({ diagram, minHeight }: MermaidProps) => {
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
<div className="not-prose my-6 text-sm text-rose-700 dark:text-rose-300">
|
||||
<div className="not-prose my-6 rounded-2xl bg-danger-soft p-4 text-sm text-danger-soft-foreground">
|
||||
Failed to render Mermaid diagram: {error}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -5,24 +5,28 @@ import { Themes } from "@/util/themes";
|
||||
import { faDiscord, 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 { Button, SearchField, Tooltip } from "@heroui/react";
|
||||
import { Button, Drawer, SearchField, Tooltip } from "@heroui/react";
|
||||
import { useTheme } from "next-themes";
|
||||
import NextLink from "next/link";
|
||||
import { useRouter } from "next/router";
|
||||
import React from "react";
|
||||
|
||||
const routes = [
|
||||
{ href: "/docs", label: "Docs" },
|
||||
{ href: "/tutorials", label: "Tutorials" },
|
||||
{ href: "/talks", label: "Talks" },
|
||||
{ href: "/docs", label: "Docs" },
|
||||
];
|
||||
|
||||
const discordUrl =
|
||||
"https://discord.com/channels/791066041198968873/1339996286514106409";
|
||||
const githubUrl = "https://github.com/BishopFox/sliver";
|
||||
|
||||
export default function TopNavbar() {
|
||||
const router = useRouter();
|
||||
const { theme, setTheme } = useTheme();
|
||||
@@ -30,9 +34,28 @@ export default function TopNavbar() {
|
||||
const [isMobileMenuOpen, setIsMobileMenuOpen] = React.useState(false);
|
||||
|
||||
const activeTheme = theme || Themes.DARK;
|
||||
const lightDarkModeIcon = React.useMemo(() => {
|
||||
return activeTheme === Themes.DARK ? faSun : faMoon;
|
||||
}, [activeTheme]);
|
||||
const isDarkTheme = activeTheme === Themes.DARK;
|
||||
const lightDarkModeIcon = isDarkTheme ? faSun : faMoon;
|
||||
const themeToggleLabel = isDarkTheme
|
||||
? "Switch to light mode"
|
||||
: "Switch to dark mode";
|
||||
|
||||
const toggleTheme = React.useCallback(() => {
|
||||
setTheme(isDarkTheme ? Themes.LIGHT : Themes.DARK);
|
||||
}, [isDarkTheme, setTheme]);
|
||||
|
||||
React.useEffect(() => {
|
||||
const desktopBreakpoint = window.matchMedia("(min-width: 768px)");
|
||||
const closeMobileMenu = (event: MediaQueryListEvent) => {
|
||||
if (event.matches) {
|
||||
setIsMobileMenuOpen(false);
|
||||
}
|
||||
};
|
||||
|
||||
desktopBreakpoint.addEventListener("change", closeMobileMenu);
|
||||
return () =>
|
||||
desktopBreakpoint.removeEventListener("change", closeMobileMenu);
|
||||
}, []);
|
||||
|
||||
const handleSearchSubmit = React.useCallback(
|
||||
(value = query) => {
|
||||
@@ -41,7 +64,11 @@ export default function TopNavbar() {
|
||||
if (searchQuery.length === 0) {
|
||||
return;
|
||||
}
|
||||
router.push({ pathname: "/search/", query: { search: searchQuery } });
|
||||
|
||||
void router.push({
|
||||
pathname: "/search/",
|
||||
query: { search: searchQuery },
|
||||
});
|
||||
setQuery("");
|
||||
setIsMobileMenuOpen(false);
|
||||
},
|
||||
@@ -58,12 +85,13 @@ export default function TopNavbar() {
|
||||
[],
|
||||
);
|
||||
|
||||
const renderSearchInput = (wrapperClassName?: string) => (
|
||||
const renderSearchInput = (className?: string) => (
|
||||
<SearchField
|
||||
aria-label="Search documentation"
|
||||
className={wrapperClassName}
|
||||
className={className}
|
||||
fullWidth
|
||||
value={query}
|
||||
variant="secondary"
|
||||
onChange={setQuery}
|
||||
onSubmit={handleSearchSubmit}
|
||||
>
|
||||
@@ -71,8 +99,10 @@ export default function TopNavbar() {
|
||||
<SearchField.SearchIcon>
|
||||
<FontAwesomeIcon icon={faSearch} />
|
||||
</SearchField.SearchIcon>
|
||||
<SearchField.Input placeholder="Search..." />
|
||||
{query.length > 0 ? <SearchField.ClearButton aria-label="Clear search" /> : null}
|
||||
<SearchField.Input placeholder="Search documentation…" />
|
||||
{query.length > 0 ? (
|
||||
<SearchField.ClearButton aria-label="Clear search" />
|
||||
) : null}
|
||||
</SearchField.Group>
|
||||
</SearchField>
|
||||
);
|
||||
@@ -82,82 +112,80 @@ export default function TopNavbar() {
|
||||
|
||||
return (
|
||||
<li key={href}>
|
||||
<Button
|
||||
variant={isActive ? "secondary" : "ghost"}
|
||||
onPress={() => router.push(href)}
|
||||
<NextLink
|
||||
href={href}
|
||||
aria-current={isActive ? "page" : undefined}
|
||||
className={`inline-flex h-10 items-center justify-center rounded-xl px-4 text-sm font-medium no-underline outline-none focus-visible:ring-2 focus-visible:ring-accent/40 ${
|
||||
isActive
|
||||
? "bg-surface-secondary text-foreground shadow-surface"
|
||||
: "text-muted hover:bg-surface-secondary hover:text-foreground"
|
||||
}`}
|
||||
>
|
||||
{label}
|
||||
</Button>
|
||||
</NextLink>
|
||||
</li>
|
||||
);
|
||||
};
|
||||
|
||||
const renderMobileRoute = (href: string, label: string) => {
|
||||
const isActive = href === "/" ? router.pathname === "/" : router.pathname.startsWith(href);
|
||||
const isActive =
|
||||
href === "/"
|
||||
? router.pathname === "/"
|
||||
: router.pathname.startsWith(href);
|
||||
|
||||
return (
|
||||
<Button
|
||||
<NextLink
|
||||
key={href}
|
||||
fullWidth
|
||||
variant={isActive ? "primary" : "ghost"}
|
||||
onPress={() => {
|
||||
router.push(href);
|
||||
setIsMobileMenuOpen(false);
|
||||
}}
|
||||
href={href}
|
||||
aria-current={isActive ? "page" : undefined}
|
||||
className={`inline-flex min-h-10 w-full items-center rounded-xl px-3 py-2 text-sm font-medium no-underline outline-none focus-visible:ring-2 focus-visible:ring-accent/40 ${
|
||||
isActive
|
||||
? "bg-surface-secondary text-foreground shadow-surface"
|
||||
: "text-muted hover:bg-surface-secondary hover:text-foreground"
|
||||
}`}
|
||||
onClick={() => setIsMobileMenuOpen(false)}
|
||||
>
|
||||
{href === "/" ? <FontAwesomeIcon fixedWidth icon={faHome} /> : null}
|
||||
{label}
|
||||
</Button>
|
||||
</NextLink>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<nav className="sliver-navbar-glass sticky top-0 z-40 px-4 shadow-sm md:px-6">
|
||||
<div className="flex h-16 items-center gap-4">
|
||||
<button
|
||||
type="button"
|
||||
className="flex items-center gap-2 text-foreground"
|
||||
onClick={() => {
|
||||
router.push("/");
|
||||
setIsMobileMenuOpen(false);
|
||||
}}
|
||||
aria-label="Sliver C2 home"
|
||||
<nav
|
||||
aria-label="Primary navigation"
|
||||
className="sticky top-0 z-40 h-16 border-b border-separator bg-background/85 backdrop-blur-xl"
|
||||
>
|
||||
<div className="mx-auto flex h-16 w-full max-w-[1440px] items-center gap-3 px-4 sm:px-6 lg:px-8">
|
||||
<NextLink
|
||||
href="/"
|
||||
aria-label="Sliver documentation home"
|
||||
className="-ml-2 inline-flex h-10 shrink-0 items-center gap-2 rounded-xl px-2 text-sm font-semibold text-foreground no-underline outline-none hover:bg-surface-secondary focus-visible:ring-2 focus-visible:ring-accent/40"
|
||||
>
|
||||
<SliversIcon />
|
||||
<span className="hidden font-bold text-inherit sm:block">
|
||||
Sliver C2
|
||||
<span className="flex size-8 items-center justify-center rounded-xl bg-accent text-accent-foreground">
|
||||
<SliversIcon height={18} />
|
||||
</span>
|
||||
</button>
|
||||
<span className="hidden items-baseline gap-1.5 sm:flex">
|
||||
<span>Sliver C2</span>
|
||||
</span>
|
||||
</NextLink>
|
||||
|
||||
<ul className="hidden items-center gap-2 md:flex">
|
||||
<li>
|
||||
{renderTooltip(
|
||||
"Home",
|
||||
<Button
|
||||
isIconOnly
|
||||
aria-label="Home"
|
||||
variant={router.pathname === "/" ? "secondary" : "ghost"}
|
||||
onPress={() => router.push("/")}
|
||||
>
|
||||
<FontAwesomeIcon fixedWidth icon={faHome} />
|
||||
</Button>,
|
||||
)}
|
||||
</li>
|
||||
{routes.map((route) => renderDesktopRoute(route.href, route.label))}
|
||||
<ul className="hidden items-center gap-1 md:flex">
|
||||
{routes.map((route) =>
|
||||
renderDesktopRoute(route.href, route.label),
|
||||
)}
|
||||
</ul>
|
||||
|
||||
<div className="ml-auto hidden items-center gap-2 md:flex">
|
||||
{renderSearchInput("w-64")}
|
||||
<div className="ml-auto hidden items-center gap-1 md:flex">
|
||||
{renderSearchInput("mr-2 w-56 xl:w-72")}
|
||||
|
||||
{renderTooltip(
|
||||
activeTheme === Themes.DARK ? "Switch to light mode" : "Switch to dark mode",
|
||||
themeToggleLabel,
|
||||
<Button
|
||||
isIconOnly
|
||||
aria-label={activeTheme === Themes.DARK ? "Switch to light mode" : "Switch to dark mode"}
|
||||
aria-label={themeToggleLabel}
|
||||
variant="ghost"
|
||||
onPress={() => {
|
||||
setTheme(activeTheme === Themes.DARK ? Themes.LIGHT : Themes.DARK);
|
||||
}}
|
||||
onPress={toggleTheme}
|
||||
>
|
||||
<FontAwesomeIcon icon={lightDarkModeIcon} />
|
||||
</Button>,
|
||||
@@ -165,62 +193,55 @@ export default function TopNavbar() {
|
||||
|
||||
{renderTooltip(
|
||||
"Join Discord",
|
||||
<Button
|
||||
isIconOnly
|
||||
<a
|
||||
href={discordUrl}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
aria-label="Join Discord"
|
||||
variant="ghost"
|
||||
onPress={() => {
|
||||
window.open(
|
||||
"https://discord.com/channels/791066041198968873/1339996286514106409",
|
||||
"_blank",
|
||||
"noopener,noreferrer",
|
||||
);
|
||||
}}
|
||||
className="inline-flex size-10 items-center justify-center rounded-xl text-muted no-underline outline-none hover:bg-surface-secondary hover:text-foreground focus-visible:ring-2 focus-visible:ring-accent/40"
|
||||
>
|
||||
<FontAwesomeIcon icon={faDiscord} />
|
||||
</Button>,
|
||||
</a>,
|
||||
)}
|
||||
|
||||
{renderTooltip(
|
||||
"View on GitHub",
|
||||
<Button
|
||||
isIconOnly
|
||||
<a
|
||||
href={githubUrl}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
aria-label="View on GitHub"
|
||||
variant="ghost"
|
||||
onPress={() => {
|
||||
window.open(
|
||||
"https://github.com/BishopFox/sliver",
|
||||
"_blank",
|
||||
"noopener,noreferrer",
|
||||
);
|
||||
}}
|
||||
className="inline-flex size-10 items-center justify-center rounded-xl text-muted no-underline outline-none hover:bg-surface-secondary hover:text-foreground focus-visible:ring-2 focus-visible:ring-accent/40"
|
||||
>
|
||||
<FontAwesomeIcon icon={faGithub} />
|
||||
</Button>,
|
||||
</a>,
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="ml-auto flex items-center gap-2 md:hidden">
|
||||
<div className="ml-auto flex items-center gap-1 md:hidden">
|
||||
{renderTooltip(
|
||||
activeTheme === Themes.DARK ? "Switch to light mode" : "Switch to dark mode",
|
||||
themeToggleLabel,
|
||||
<Button
|
||||
isIconOnly
|
||||
aria-label={activeTheme === Themes.DARK ? "Switch to light mode" : "Switch to dark mode"}
|
||||
aria-label={themeToggleLabel}
|
||||
variant="ghost"
|
||||
onPress={() => {
|
||||
setTheme(activeTheme === Themes.DARK ? Themes.LIGHT : Themes.DARK);
|
||||
}}
|
||||
onPress={toggleTheme}
|
||||
>
|
||||
<FontAwesomeIcon icon={lightDarkModeIcon} />
|
||||
</Button>,
|
||||
)}
|
||||
|
||||
{renderTooltip(
|
||||
isMobileMenuOpen ? "Close menu" : "Open menu",
|
||||
<Button
|
||||
isIconOnly
|
||||
variant="ghost"
|
||||
aria-controls="mobile-navigation"
|
||||
aria-expanded={isMobileMenuOpen}
|
||||
aria-label={isMobileMenuOpen ? "Close menu" : "Open menu"}
|
||||
onPress={() => setIsMobileMenuOpen((current) => !current)}
|
||||
variant="ghost"
|
||||
onPress={() =>
|
||||
setIsMobileMenuOpen((current) => !current)
|
||||
}
|
||||
>
|
||||
<FontAwesomeIcon icon={isMobileMenuOpen ? faXmark : faBars} />
|
||||
</Button>,
|
||||
@@ -229,43 +250,56 @@ export default function TopNavbar() {
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
{isMobileMenuOpen ? (
|
||||
<div className="sliver-navbar-glass px-4 pb-4 shadow-sm md:hidden">
|
||||
<div className="mt-3">{renderSearchInput("w-full")}</div>
|
||||
<div className="mt-4 flex flex-col gap-2">
|
||||
{renderMobileRoute("/", "Home")}
|
||||
{routes.map((route) => renderMobileRoute(route.href, route.label))}
|
||||
<Button
|
||||
fullWidth
|
||||
variant="ghost"
|
||||
onPress={() => {
|
||||
window.open(
|
||||
"https://discord.com/channels/791066041198968873/1339996286514106409",
|
||||
"_blank",
|
||||
"noopener,noreferrer",
|
||||
);
|
||||
}}
|
||||
>
|
||||
<FontAwesomeIcon icon={faDiscord} />
|
||||
Discord
|
||||
</Button>
|
||||
<Button
|
||||
fullWidth
|
||||
variant="ghost"
|
||||
onPress={() => {
|
||||
window.open(
|
||||
"https://github.com/BishopFox/sliver",
|
||||
"_blank",
|
||||
"noopener,noreferrer",
|
||||
);
|
||||
}}
|
||||
>
|
||||
<FontAwesomeIcon icon={faGithub} />
|
||||
GitHub
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
<Drawer.Backdrop
|
||||
isOpen={isMobileMenuOpen}
|
||||
variant="blur"
|
||||
onOpenChange={setIsMobileMenuOpen}
|
||||
>
|
||||
<Drawer.Content placement="right">
|
||||
<Drawer.Dialog
|
||||
id="mobile-navigation"
|
||||
className="w-[min(24rem,calc(100vw-1.5rem))]"
|
||||
>
|
||||
<Drawer.CloseTrigger />
|
||||
<Drawer.Header>
|
||||
<Drawer.Heading>Navigate Sliver Docs</Drawer.Heading>
|
||||
</Drawer.Header>
|
||||
<Drawer.Body className="flex flex-col gap-5 pt-2">
|
||||
{renderSearchInput("w-full")}
|
||||
|
||||
<nav
|
||||
aria-label="Mobile navigation"
|
||||
className="flex flex-col gap-1"
|
||||
>
|
||||
{renderMobileRoute("/", "Home")}
|
||||
{routes.map((route) =>
|
||||
renderMobileRoute(route.href, route.label),
|
||||
)}
|
||||
</nav>
|
||||
</Drawer.Body>
|
||||
<Drawer.Footer className="grid grid-cols-2 gap-2">
|
||||
<a
|
||||
href={discordUrl}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="inline-flex h-10 w-full items-center justify-center gap-2 rounded-xl border border-separator px-4 text-sm font-medium text-foreground no-underline outline-none hover:bg-surface-secondary focus-visible:ring-2 focus-visible:ring-accent/40"
|
||||
>
|
||||
<FontAwesomeIcon icon={faDiscord} />
|
||||
Discord
|
||||
</a>
|
||||
<a
|
||||
href={githubUrl}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="inline-flex h-10 w-full items-center justify-center gap-2 rounded-xl border border-separator px-4 text-sm font-medium text-foreground no-underline outline-none hover:bg-surface-secondary focus-visible:ring-2 focus-visible:ring-accent/40"
|
||||
>
|
||||
<FontAwesomeIcon icon={faGithub} />
|
||||
GitHub
|
||||
</a>
|
||||
</Drawer.Footer>
|
||||
</Drawer.Dialog>
|
||||
</Drawer.Content>
|
||||
</Drawer.Backdrop>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -3,7 +3,6 @@ import AsciinemaPlayer from "./asciinema";
|
||||
|
||||
import { faChevronRight } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import styles from "./TutorialCard.module.css";
|
||||
|
||||
export type TutorialCardCardProps = {
|
||||
name: string;
|
||||
@@ -13,6 +12,7 @@ export type TutorialCardCardProps = {
|
||||
rows?: string;
|
||||
cols?: string;
|
||||
idleTimeLimit?: number;
|
||||
hideControls?: boolean;
|
||||
|
||||
italicDescription?: boolean;
|
||||
onPress?: () => void;
|
||||
@@ -21,55 +21,48 @@ export type TutorialCardCardProps = {
|
||||
};
|
||||
|
||||
export default function TutorialCard(props: TutorialCardCardProps) {
|
||||
const actionButtonClassName =
|
||||
"ml-auto h-auto min-h-0 shrink-0 px-0 py-0 text-sm font-semibold [--button-bg-hover:transparent] [--button-bg-pressed:transparent] [--button-bg:transparent] [--button-fg:var(--warning)]";
|
||||
|
||||
return (
|
||||
<Card className="relative z-0 gap-0 overflow-hidden p-0">
|
||||
<Card.Header className="absolute left-3 right-3 top-3 z-10 flex-col items-end p-0 text-right">
|
||||
<p className="text-sm font-bold uppercase leading-none text-white/70">
|
||||
{props.name}
|
||||
</p>
|
||||
</Card.Header>
|
||||
|
||||
<div className={`${styles["hide-control-bar"]} overflow-hidden`}>
|
||||
<Card className="relative h-full min-w-0 gap-0 overflow-hidden bg-black p-0 shadow-surface">
|
||||
<div className="sliver-terminal-frame relative w-full max-w-full overflow-x-auto bg-[#111315]">
|
||||
<AsciinemaPlayer
|
||||
className="min-w-[36rem]"
|
||||
src={props.asciiCast}
|
||||
rows={props.rows ? props.rows : "18"}
|
||||
cols={props.cols ? props.cols : "75"}
|
||||
idleTimeLimit={props.idleTimeLimit ? props.idleTimeLimit : 2}
|
||||
hideControls={props.hideControls}
|
||||
rows={props.rows || "18"}
|
||||
cols={props.cols || "75"}
|
||||
idleTimeLimit={props.idleTimeLimit || 2}
|
||||
preload={true}
|
||||
autoPlay={true}
|
||||
loop={true}
|
||||
/>
|
||||
|
||||
<div className="pointer-events-none absolute inset-x-3 top-3 z-10 flex justify-end">
|
||||
<h3 className="max-w-[80%] rounded-xl border border-white/15 bg-black/55 px-3 py-2 text-right text-sm font-semibold text-white/85 shadow-lg backdrop-blur-xl">
|
||||
{props.name}
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Card.Footer className="absolute bottom-0 left-0 right-0 z-10 border-t border-white/20 bg-black/40 p-3 backdrop-blur-md">
|
||||
<div className="flex min-h-10 w-full flex-row items-center gap-4">
|
||||
<p
|
||||
className={
|
||||
props.italicDescription
|
||||
? "min-w-0 flex-1 text-sm leading-snug text-white/80 italic"
|
||||
: "min-w-0 flex-1 text-sm leading-snug text-white/80"
|
||||
}
|
||||
>
|
||||
{props.description}
|
||||
</p>
|
||||
<Card.Footer className="absolute inset-x-3 bottom-10 z-10 flex-row items-center gap-3 rounded-2xl border border-white/15 bg-black/55 px-3 py-2.5 text-white shadow-xl backdrop-blur-xl">
|
||||
<p
|
||||
className={`min-w-0 flex-1 text-sm leading-5 text-white/70 ${
|
||||
props.italicDescription ? "italic" : ""
|
||||
}`}
|
||||
>
|
||||
{props.description}
|
||||
</p>
|
||||
|
||||
{props.showButton ? (
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onPress={props.onPress}
|
||||
className={actionButtonClassName}
|
||||
>
|
||||
{props.buttonText ? props.buttonText : "Read Tutorial"}
|
||||
<FontAwesomeIcon icon={faChevronRight} />
|
||||
</Button>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</div>
|
||||
{props.showButton ? (
|
||||
<Button
|
||||
className="shrink-0 text-white hover:bg-white/10"
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
onPress={props.onPress}
|
||||
>
|
||||
{props.buttonText || "Read tutorial"}
|
||||
<FontAwesomeIcon icon={faChevronRight} />
|
||||
</Button>
|
||||
) : null}
|
||||
</Card.Footer>
|
||||
</Card>
|
||||
);
|
||||
|
||||
Generated
+256
-196
@@ -867,9 +867,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-darwin-arm64": {
|
||||
"version": "0.34.5",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz",
|
||||
"integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==",
|
||||
"version": "0.35.3",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.35.3.tgz",
|
||||
"integrity": "sha512-RMnFX7YQsMoh7lWfcM4NEHHymBX/rLuKNPVM84XE9ONPcaSCDgE7CHIHpSgPcO2xcRthgBy1HfNO319mwhIAkg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -879,19 +879,19 @@
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||
"node": ">=20.9.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-darwin-arm64": "1.2.4"
|
||||
"@img/sharp-libvips-darwin-arm64": "1.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-darwin-x64": {
|
||||
"version": "0.34.5",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz",
|
||||
"integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==",
|
||||
"version": "0.35.3",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.35.3.tgz",
|
||||
"integrity": "sha512-Xo+5uFBtLN0BKqieTxiFzFPQAUlBbbH5iBKyRX/z1JrbnYsHTfKJnUfL8+p2TPXr1pXqao4eeL4Rl144uDpK9w==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -901,19 +901,38 @@
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||
"node": ">=20.9.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-darwin-x64": "1.2.4"
|
||||
"@img/sharp-libvips-darwin-x64": "1.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-freebsd-wasm32": {
|
||||
"version": "0.35.3",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-freebsd-wasm32/-/sharp-freebsd-wasm32-0.35.3.tgz",
|
||||
"integrity": "sha512-lUxcqWIj2wMQ9BrwNjngcr1gWUr5xgaGThBRqPPalIC2n67Cqj1uPh8NnA/ZhAg8hUbKl+kVHKwgUIwe6ZYPrg==",
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"dependencies": {
|
||||
"@img/sharp-wasm32": "0.35.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.9.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-libvips-darwin-arm64": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz",
|
||||
"integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==",
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.3.2.tgz",
|
||||
"integrity": "sha512-9J6ypZFpQBj4YnePGoq/S38w6nz+vqg5WZLrLGY4YuSemdMq47GMLBPO42MzwdGwpg/agZ7xzZcFHa48xlywfg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -927,9 +946,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-libvips-darwin-x64": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz",
|
||||
"integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==",
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.3.2.tgz",
|
||||
"integrity": "sha512-m2pW1n6cns9VaubNwsZ+c3CRYjxNQWgJ5gPlnL1nbBcpkBvFm6SCFN5o0psFHI8w9n11NKhFkeEDns98tiqbEw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -943,9 +962,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-libvips-linux-arm": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz",
|
||||
"integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==",
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.3.2.tgz",
|
||||
"integrity": "sha512-1eMLzy92I4J6rmi4mAT8yC3HxOtniyGELlzGbNMLLeqe052ahFQ0h6LFq+lh5DsDIdYViIDst08abvSbcEdLXQ==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -962,9 +981,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-libvips-linux-arm64": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz",
|
||||
"integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==",
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.3.2.tgz",
|
||||
"integrity": "sha512-dqVSFynCox4C/J8kT16V7SIFAns0IjgLwkvYT7p8LQVmJ5OS5b6tI9IGflxTeuBS//zXeFIUbwt5dwxyZ17cnA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -981,9 +1000,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-libvips-linux-ppc64": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz",
|
||||
"integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==",
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.3.2.tgz",
|
||||
"integrity": "sha512-3z0NHDxD6n5I9gc05U1eW1AyRm+Gznzq3naMrthPNqE6oYykcogW0l/jfpJdjYnuNl8R7yI9pNbE1XiUeyq0Aw==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
@@ -1000,9 +1019,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-libvips-linux-riscv64": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz",
|
||||
"integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==",
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.3.2.tgz",
|
||||
"integrity": "sha512-bsb4rI+NldGOsXuej2r8OdSS8+zXDVaCWxyWrcv6kneTOlgAHtZABRzBBCwdsPiD90J4myNJuHpg6kA20ImW/w==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
@@ -1019,9 +1038,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-libvips-linux-s390x": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz",
|
||||
"integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==",
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.3.2.tgz",
|
||||
"integrity": "sha512-/ABshyj8gCpyIrNXnHn4LorDJ0HHm1VhXPBlxZ8zAtfVPAaSafXPGn+sUSIRiwaSBy0mmFjSjiXI5mkcwdChKQ==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
@@ -1038,9 +1057,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-libvips-linux-x64": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz",
|
||||
"integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==",
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.3.2.tgz",
|
||||
"integrity": "sha512-ITPEtgffGJ0S6G9dRyw/366tJQqFRcHWPHhC+Stpg3Z8AEMrDrTr2lhdz4f/Y/HMbRh//7Z5mBzEpVdi62Oc3w==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1057,9 +1076,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-libvips-linuxmusl-arm64": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz",
|
||||
"integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==",
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.3.2.tgz",
|
||||
"integrity": "sha512-zE9EdiUzUmg5mDT5a1rk5fYJ6GWPloTwWBYDS14naqHsL+EaMpDj1AWnpLgh3u0YCORv2Tt50wrcrpYqkP97Kw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1076,9 +1095,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-libvips-linuxmusl-x64": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz",
|
||||
"integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==",
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.3.2.tgz",
|
||||
"integrity": "sha512-m0lrLiUt+lBYnCFr8qV/65yMR4E/c7/wf78I5eKTdkEakFAlZ9QlzEM3QIhhAwVeUhLAHLcCq7a7Vszq/oFNZQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1095,9 +1114,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-linux-arm": {
|
||||
"version": "0.34.5",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz",
|
||||
"integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==",
|
||||
"version": "0.35.3",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.35.3.tgz",
|
||||
"integrity": "sha512-affVWCTLooy8TSxbDx2qkzuDeaWLNVBA+P//FNBirHsXpP2fuBhk5AuboYUnrDnzoXes8GFjpTx0SBFOCRg+FA==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -1110,19 +1129,19 @@
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||
"node": ">=20.9.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-linux-arm": "1.2.4"
|
||||
"@img/sharp-libvips-linux-arm": "1.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-linux-arm64": {
|
||||
"version": "0.34.5",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz",
|
||||
"integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==",
|
||||
"version": "0.35.3",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.35.3.tgz",
|
||||
"integrity": "sha512-QgKDspHPnrU+GQ55XPhGwyhC8acLVOOSyAvo1oVfFmrIXLkDNmGWzAfDZ4xK8oSA1qBQrALcHX0G5UZni/SuFQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1135,19 +1154,19 @@
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||
"node": ">=20.9.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-linux-arm64": "1.2.4"
|
||||
"@img/sharp-libvips-linux-arm64": "1.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-linux-ppc64": {
|
||||
"version": "0.34.5",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz",
|
||||
"integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==",
|
||||
"version": "0.35.3",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.35.3.tgz",
|
||||
"integrity": "sha512-sMd8rDxmpLOwv/7N44klFjOD5DUO7FLdjiXDI0hoxYaf7Ar262dQIEkosE98bps+5HPLtp/EvNqeqQtOycP/IA==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
@@ -1160,19 +1179,19 @@
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||
"node": ">=20.9.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-linux-ppc64": "1.2.4"
|
||||
"@img/sharp-libvips-linux-ppc64": "1.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-linux-riscv64": {
|
||||
"version": "0.34.5",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz",
|
||||
"integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==",
|
||||
"version": "0.35.3",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.35.3.tgz",
|
||||
"integrity": "sha512-0Eob78yjlYPfL5vMNWAW55l3R9Y6BQS/gOfe0ZcP9mEz9ohhKSt4im1hayiknXgf8AWrFqMvJcKIdmLmEe7yeQ==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
@@ -1185,19 +1204,19 @@
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||
"node": ">=20.9.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-linux-riscv64": "1.2.4"
|
||||
"@img/sharp-libvips-linux-riscv64": "1.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-linux-s390x": {
|
||||
"version": "0.34.5",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz",
|
||||
"integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==",
|
||||
"version": "0.35.3",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.35.3.tgz",
|
||||
"integrity": "sha512-KgAxQ0DxpNOq1rG2t5cgTgShJFGSuU7XO45cqC+1NVOuZnP6tlgZRuSYOfNupGkHID0o3cJOsw4DVeJpMovcGw==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
@@ -1210,19 +1229,19 @@
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||
"node": ">=20.9.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-linux-s390x": "1.2.4"
|
||||
"@img/sharp-libvips-linux-s390x": "1.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-linux-x64": {
|
||||
"version": "0.34.5",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz",
|
||||
"integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==",
|
||||
"version": "0.35.3",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.35.3.tgz",
|
||||
"integrity": "sha512-8pqvxubL2PGdhlPy6GLqzDYMUjyRmKAwKHYKixpdJYBUK7PJ0C029XdsnpFIdgRZG68fZiGdHVWcKPvtiPB4cA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1235,19 +1254,19 @@
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||
"node": ">=20.9.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-linux-x64": "1.2.4"
|
||||
"@img/sharp-libvips-linux-x64": "1.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-linuxmusl-arm64": {
|
||||
"version": "0.34.5",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz",
|
||||
"integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==",
|
||||
"version": "0.35.3",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.35.3.tgz",
|
||||
"integrity": "sha512-Vz0iQjzzcSX3HCbfwFfCSG/9SCIqyO0mH2sXyiHaAYfBk0cRsCWXRyQYX0ovCK/PAQBbTzQ0dsPQHh5MAFL59w==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1260,19 +1279,19 @@
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||
"node": ">=20.9.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-linuxmusl-arm64": "1.2.4"
|
||||
"@img/sharp-libvips-linuxmusl-arm64": "1.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-linuxmusl-x64": {
|
||||
"version": "0.34.5",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz",
|
||||
"integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==",
|
||||
"version": "0.35.3",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.35.3.tgz",
|
||||
"integrity": "sha512-6O1NPKcDVj9QEdg7Hx549EX8U0rp6yXQERqru6yRN7fGBn32UvIRJUlWnk+8xDCiG76hXVBbX82NZ/ZKr0euIg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1285,38 +1304,64 @@
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||
"node": ">=20.9.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-linuxmusl-x64": "1.2.4"
|
||||
"@img/sharp-libvips-linuxmusl-x64": "1.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-wasm32": {
|
||||
"version": "0.34.5",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz",
|
||||
"integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==",
|
||||
"cpu": [
|
||||
"wasm32"
|
||||
],
|
||||
"version": "0.35.3",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.35.3.tgz",
|
||||
"integrity": "sha512-cZ0XkcYGpHZkqW6iCkqTcmUC0CD9DhD5d/qeZlZkfRBn6GnHniZXLUo5+9xw8Iv76YE6LQFN9YNBlKREcCG76w==",
|
||||
"license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@emnapi/runtime": "^1.7.0"
|
||||
"@emnapi/runtime": "^1.11.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||
"node": ">=20.9.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-wasm32/node_modules/@emnapi/runtime": {
|
||||
"version": "1.11.3",
|
||||
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.3.tgz",
|
||||
"integrity": "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"tslib": "^2.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-webcontainers-wasm32": {
|
||||
"version": "0.35.3",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-webcontainers-wasm32/-/sharp-webcontainers-wasm32-0.35.3.tgz",
|
||||
"integrity": "sha512-2rnq7bX3NzeR2T4YWgz8qiG4h3TSdMe+vN1iQXpJleSJ3SM5zQ8Fy2SyyXAWlbxpEZ2Y+Z4u1BePgJEYbSy80Q==",
|
||||
"cpu": [
|
||||
"wasm32"
|
||||
],
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@img/sharp-wasm32": "0.35.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.9.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-win32-arm64": {
|
||||
"version": "0.34.5",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz",
|
||||
"integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==",
|
||||
"version": "0.35.3",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.35.3.tgz",
|
||||
"integrity": "sha512-4bPwFdMbeC4JQ8L8LOyWp6nsHcboP5fxkp6iPOXz2Vg49R42TuMs2whkJ5OAP4/Ul035qOzy0AecOF9VOscn4w==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1326,16 +1371,16 @@
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||
"node": ">=20.9.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-win32-ia32": {
|
||||
"version": "0.34.5",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz",
|
||||
"integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==",
|
||||
"version": "0.35.3",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.35.3.tgz",
|
||||
"integrity": "sha512-r53mXsBN6lFUDiST764SvgwUdHAqM4rPAiDzAmf4fLoB6X/rkfyTrLCg6+g17wJJiCmB3JYgHuUldCWUIRFSXw==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
@@ -1345,16 +1390,16 @@
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||
"node": "^20.9.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-win32-x64": {
|
||||
"version": "0.34.5",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz",
|
||||
"integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==",
|
||||
"version": "0.35.3",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.35.3.tgz",
|
||||
"integrity": "sha512-D4y1vNeZrIIJCN+uHaWVtH86B+aCrdMYYjicy9pXHvbGZeGYLLSd3wdVuC37FxVXlU1ARsk84eKWfWMXGYEqvA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1364,7 +1409,7 @@
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||
"node": ">=20.9.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
@@ -1503,9 +1548,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/env": {
|
||||
"version": "16.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@next/env/-/env-16.2.6.tgz",
|
||||
"integrity": "sha512-gd8HoHN4ufj73WmR3JmVolrpJR47ILK6LouP5xElPglaVxir6e1a7VzvTvDWkOoPXT9rkkTzyCxBu4yeZfZwcw==",
|
||||
"version": "16.2.11",
|
||||
"resolved": "https://registry.npmjs.org/@next/env/-/env-16.2.11.tgz",
|
||||
"integrity": "sha512-0do5A3BJ2gxWr0ZCMcD6BhW+e595jyxdTl3rXTS6lOtD8ektMiW6CO+EPwt1Eca1DBnm90r/7GdiKWBKxH++DA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@next/eslint-plugin-next": {
|
||||
@@ -1519,9 +1564,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-darwin-arm64": {
|
||||
"version": "16.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.2.6.tgz",
|
||||
"integrity": "sha512-ZJGkkcNfYgrrMkqOdZ7zoLa1TOy0qpcMfk/z4Mh/FKUz40gVO+HNQWqmLxf67Z5WB64DRp0dhEbyHfel+6sJUg==",
|
||||
"version": "16.2.11",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.2.11.tgz",
|
||||
"integrity": "sha512-wryL4pjKmDwGv2ox6+GZDFxvmtSRLqApBR8kL1j4+vhB7Z5vJC/zAnXpiR9Xkfzl0AS8WLMnsuGV/UKI67/rrw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1535,9 +1580,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-darwin-x64": {
|
||||
"version": "16.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.2.6.tgz",
|
||||
"integrity": "sha512-v/YLBHIY132Ced3puBJ7YJKw1lqsCrgcNo2aRJlCEyQrrCeRJlvGlnmxhPxNQI3KE3N1DN5r9TPNPvka3nq5RQ==",
|
||||
"version": "16.2.11",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.2.11.tgz",
|
||||
"integrity": "sha512-aZl2j4f/fLyjQvOhv0Oe9UaMAQHolYpKhctsoYzplSumKJKPUmgjcf6545aBtysLTcu994TREd0+pSgNE4ohmg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1551,9 +1596,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-arm64-gnu": {
|
||||
"version": "16.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.2.6.tgz",
|
||||
"integrity": "sha512-RPOvqlYBbcQjkz9VQQDZ2T2bARIjXZV1KFlt+V2Mr6SW/e4I9fcKsaA0hdyf2FHoTlsV2xnBd5Y912rP/1Ce6w==",
|
||||
"version": "16.2.11",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.2.11.tgz",
|
||||
"integrity": "sha512-5jEriyEnH/LWFy27L2ZG0XaLlyEJIjhsImEsiS9P563PKEVp2BVups/xfOucIrsvVntp11oNcZwjHvaDPYVB5g==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1570,9 +1615,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-arm64-musl": {
|
||||
"version": "16.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.2.6.tgz",
|
||||
"integrity": "sha512-URUTu1+dMkxJsPFgm+OeEvq9wf5sujw0EvgYy80TDGHTSLTnIHeqb0Eu8A3sC95IRgjejQL+kC4mw+4yPxiAXA==",
|
||||
"version": "16.2.11",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.2.11.tgz",
|
||||
"integrity": "sha512-eIjcpx2fnnFSSkZDbTxy74KnokUXDjfoLClpWelfgHLf621aTqswhwXQ7GkD5K5rplrS6LZ/Bj+mVuvzluBOEg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1589,9 +1634,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-x64-gnu": {
|
||||
"version": "16.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.2.6.tgz",
|
||||
"integrity": "sha512-DOj182mPV8G3UkrayLoREM5YEYI+Dk5wv7Ox9xl1fFibAELEsFD0lDPfHIeILlutMMfdyhlzYPELG3peuKaurw==",
|
||||
"version": "16.2.11",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.2.11.tgz",
|
||||
"integrity": "sha512-8WgzpaWMs46qJT9kiV47cje86L0x/Mu9t8/Gwj+pnbgW3rETVfCnaScPjlYUwNScpOozdcIMHWmAvuZJUonR2w==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1608,9 +1653,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-x64-musl": {
|
||||
"version": "16.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.2.6.tgz",
|
||||
"integrity": "sha512-HKQ5SP/V/ub73UvF7n/zeJlxk2kLmtL7Wzrg4WfmkjmNos5onJ2tKu7yZOPdL18A6Svfn3max29ym+ry7NkK4g==",
|
||||
"version": "16.2.11",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.2.11.tgz",
|
||||
"integrity": "sha512-I3UgPds7G4ZYnTb/H+5GBGuUT2DhAk6j0mL6A4s63RjFs74wB2hOWP0vaxsK+3NJraExt3eYEPQ/UtT0x/64Nw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1627,9 +1672,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-win32-arm64-msvc": {
|
||||
"version": "16.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.2.6.tgz",
|
||||
"integrity": "sha512-LZXpTlPyS5v7HhSmnvsLGP3iIYgYOBnc8r8ArlT55sGHV89bR2HlDdBjWQ+PY6SJMmk8TuVGFuxalnP3k/0Dwg==",
|
||||
"version": "16.2.11",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.2.11.tgz",
|
||||
"integrity": "sha512-n89CjtcThnjrwgJMAiI5xbqwLY51zvwC9tSlArmVndAJLYVl9T9UAdlkXTmZvE++idoXe8KdglQlhNRdUp1c6g==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1643,9 +1688,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-win32-x64-msvc": {
|
||||
"version": "16.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.2.6.tgz",
|
||||
"integrity": "sha512-F0+4i0h9J6C4eE3EAPWsoCk7UW/dbzOjyzxY0qnDUOYFu6FFmdZ6l97/XdV3/Nz3VYyO7UWjyEJUXkGqcoXfMA==",
|
||||
"version": "16.2.11",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.2.11.tgz",
|
||||
"integrity": "sha512-md8CLNggS1Dx9pUgApzps5uAf+N8GN9xywzmNx9vHAWo94HtBwCCqkSnhIrdfQe83Dhz8Lfo/20Nb1Zxal092w==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -2977,16 +3022,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
|
||||
"version": "5.0.6",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz",
|
||||
"integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==",
|
||||
"version": "5.0.8",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.8.tgz",
|
||||
"integrity": "sha512-JZyDyq3D4AUifKTPOB7DELf6XsB3WdPuNxCtob1vFXPsSXhdAiHBWJ/tJ8HAc9aH84BK+5JFZLNkJKx3G9kzQg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"balanced-match": "^4.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": "18 || 20 || >=22"
|
||||
"node": "20 || >=22"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": {
|
||||
@@ -3818,9 +3863,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/brace-expansion": {
|
||||
"version": "1.1.15",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz",
|
||||
"integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==",
|
||||
"version": "1.1.16",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz",
|
||||
"integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -4895,9 +4940,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/dompurify": {
|
||||
"version": "3.4.7",
|
||||
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.7.tgz",
|
||||
"integrity": "sha512-2jBxDJY4RR06tQNy4w5FlFH7kfxsQZlufd0sbv+chfHCxeJwrFw2baUDsSwvBISD4K4RDbd0PTfy3uNXsR6siA==",
|
||||
"version": "3.4.13",
|
||||
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.13.tgz",
|
||||
"integrity": "sha512-2vmYIoqjze2d+kakP8S/nS5shfsl587kzwEjcGlTdiksUVgFHnFCsLYDVj/JNqJVOQZGSYBTmuycv0PodwmnMQ==",
|
||||
"license": "(MPL-2.0 OR Apache-2.0)",
|
||||
"optionalDependencies": {
|
||||
"@types/trusted-types": "^2.0.7"
|
||||
@@ -6821,10 +6866,20 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/js-yaml": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
|
||||
"integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.0.tgz",
|
||||
"integrity": "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/puzrin"
|
||||
},
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/nodeca"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"argparse": "^2.0.1"
|
||||
@@ -8311,9 +8366,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/nanoid": {
|
||||
"version": "3.3.12",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz",
|
||||
"integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==",
|
||||
"version": "3.3.16",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.16.tgz",
|
||||
"integrity": "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
@@ -8352,12 +8407,12 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/next": {
|
||||
"version": "16.2.6",
|
||||
"resolved": "https://registry.npmjs.org/next/-/next-16.2.6.tgz",
|
||||
"integrity": "sha512-qOVgKJg1+At15NpeUP+eJgCHvTCgXsogweq87Ri/Ix7PkqQHg4sdaXmSFqKlgaIXE4kW0g25LE68W87UANlHtw==",
|
||||
"version": "16.2.11",
|
||||
"resolved": "https://registry.npmjs.org/next/-/next-16.2.11.tgz",
|
||||
"integrity": "sha512-B339zaqbyK8cmxhoAvLrcwoabwCP1wz21zSzfqxqXAemTu2BXnH7tQnfcglKv1vnMUIDBc+Hth7XODQriTZiRQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@next/env": "16.2.6",
|
||||
"@next/env": "16.2.11",
|
||||
"@swc/helpers": "0.5.15",
|
||||
"baseline-browser-mapping": "^2.9.19",
|
||||
"caniuse-lite": "^1.0.30001579",
|
||||
@@ -8371,14 +8426,14 @@
|
||||
"node": ">=20.9.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@next/swc-darwin-arm64": "16.2.6",
|
||||
"@next/swc-darwin-x64": "16.2.6",
|
||||
"@next/swc-linux-arm64-gnu": "16.2.6",
|
||||
"@next/swc-linux-arm64-musl": "16.2.6",
|
||||
"@next/swc-linux-x64-gnu": "16.2.6",
|
||||
"@next/swc-linux-x64-musl": "16.2.6",
|
||||
"@next/swc-win32-arm64-msvc": "16.2.6",
|
||||
"@next/swc-win32-x64-msvc": "16.2.6",
|
||||
"@next/swc-darwin-arm64": "16.2.11",
|
||||
"@next/swc-darwin-x64": "16.2.11",
|
||||
"@next/swc-linux-arm64-gnu": "16.2.11",
|
||||
"@next/swc-linux-arm64-musl": "16.2.11",
|
||||
"@next/swc-linux-x64-gnu": "16.2.11",
|
||||
"@next/swc-linux-x64-musl": "16.2.11",
|
||||
"@next/swc-win32-arm64-msvc": "16.2.11",
|
||||
"@next/swc-win32-x64-msvc": "16.2.11",
|
||||
"sharp": "^0.34.5"
|
||||
},
|
||||
"peerDependencies": {
|
||||
@@ -8765,9 +8820,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.5.15",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz",
|
||||
"integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==",
|
||||
"version": "8.5.23",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.23.tgz",
|
||||
"integrity": "sha512-g50586zr4bZmwFiTlflMu8E0bDTb5I5gertgwAKmsdUlTQIhZtunzUlD1WSzwcVWPoAVpsrA6vlfCD7oXvRwgg==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
@@ -8784,7 +8839,7 @@
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"nanoid": "^3.3.12",
|
||||
"nanoid": "^3.3.16",
|
||||
"picocolors": "^1.1.1",
|
||||
"source-map-js": "^1.2.1"
|
||||
},
|
||||
@@ -9427,54 +9482,59 @@
|
||||
}
|
||||
},
|
||||
"node_modules/sharp": {
|
||||
"version": "0.34.5",
|
||||
"resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz",
|
||||
"integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==",
|
||||
"hasInstallScript": true,
|
||||
"version": "0.35.3",
|
||||
"resolved": "https://registry.npmjs.org/sharp/-/sharp-0.35.3.tgz",
|
||||
"integrity": "sha512-ej0zVHuZGHCiABXcNxeYhpRnPNPAcvbG8RMdBAhDAxLKkCRVSpK3Iyu7qbqw3JMzoj0REeM6f3tJLtVwl0023Q==",
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@img/colour": "^1.0.0",
|
||||
"@img/colour": "^1.1.0",
|
||||
"detect-libc": "^2.1.2",
|
||||
"semver": "^7.7.3"
|
||||
"semver": "^7.8.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||
"node": ">=20.9.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-darwin-arm64": "0.34.5",
|
||||
"@img/sharp-darwin-x64": "0.34.5",
|
||||
"@img/sharp-libvips-darwin-arm64": "1.2.4",
|
||||
"@img/sharp-libvips-darwin-x64": "1.2.4",
|
||||
"@img/sharp-libvips-linux-arm": "1.2.4",
|
||||
"@img/sharp-libvips-linux-arm64": "1.2.4",
|
||||
"@img/sharp-libvips-linux-ppc64": "1.2.4",
|
||||
"@img/sharp-libvips-linux-riscv64": "1.2.4",
|
||||
"@img/sharp-libvips-linux-s390x": "1.2.4",
|
||||
"@img/sharp-libvips-linux-x64": "1.2.4",
|
||||
"@img/sharp-libvips-linuxmusl-arm64": "1.2.4",
|
||||
"@img/sharp-libvips-linuxmusl-x64": "1.2.4",
|
||||
"@img/sharp-linux-arm": "0.34.5",
|
||||
"@img/sharp-linux-arm64": "0.34.5",
|
||||
"@img/sharp-linux-ppc64": "0.34.5",
|
||||
"@img/sharp-linux-riscv64": "0.34.5",
|
||||
"@img/sharp-linux-s390x": "0.34.5",
|
||||
"@img/sharp-linux-x64": "0.34.5",
|
||||
"@img/sharp-linuxmusl-arm64": "0.34.5",
|
||||
"@img/sharp-linuxmusl-x64": "0.34.5",
|
||||
"@img/sharp-wasm32": "0.34.5",
|
||||
"@img/sharp-win32-arm64": "0.34.5",
|
||||
"@img/sharp-win32-ia32": "0.34.5",
|
||||
"@img/sharp-win32-x64": "0.34.5"
|
||||
"@img/sharp-darwin-arm64": "0.35.3",
|
||||
"@img/sharp-darwin-x64": "0.35.3",
|
||||
"@img/sharp-freebsd-wasm32": "0.35.3",
|
||||
"@img/sharp-libvips-darwin-arm64": "1.3.2",
|
||||
"@img/sharp-libvips-darwin-x64": "1.3.2",
|
||||
"@img/sharp-libvips-linux-arm": "1.3.2",
|
||||
"@img/sharp-libvips-linux-arm64": "1.3.2",
|
||||
"@img/sharp-libvips-linux-ppc64": "1.3.2",
|
||||
"@img/sharp-libvips-linux-riscv64": "1.3.2",
|
||||
"@img/sharp-libvips-linux-s390x": "1.3.2",
|
||||
"@img/sharp-libvips-linux-x64": "1.3.2",
|
||||
"@img/sharp-libvips-linuxmusl-arm64": "1.3.2",
|
||||
"@img/sharp-libvips-linuxmusl-x64": "1.3.2",
|
||||
"@img/sharp-linux-arm": "0.35.3",
|
||||
"@img/sharp-linux-arm64": "0.35.3",
|
||||
"@img/sharp-linux-ppc64": "0.35.3",
|
||||
"@img/sharp-linux-riscv64": "0.35.3",
|
||||
"@img/sharp-linux-s390x": "0.35.3",
|
||||
"@img/sharp-linux-x64": "0.35.3",
|
||||
"@img/sharp-linuxmusl-arm64": "0.35.3",
|
||||
"@img/sharp-linuxmusl-x64": "0.35.3",
|
||||
"@img/sharp-webcontainers-wasm32": "0.35.3",
|
||||
"@img/sharp-win32-arm64": "0.35.3",
|
||||
"@img/sharp-win32-ia32": "0.35.3",
|
||||
"@img/sharp-win32-x64": "0.35.3"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/node": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/sharp/node_modules/semver": {
|
||||
"version": "7.8.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz",
|
||||
"integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==",
|
||||
"version": "7.8.5",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz",
|
||||
"integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==",
|
||||
"license": "ISC",
|
||||
"optional": true,
|
||||
"bin": {
|
||||
@@ -9508,9 +9568,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/shell-quote": {
|
||||
"version": "1.8.3",
|
||||
"resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz",
|
||||
"integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==",
|
||||
"version": "1.10.0",
|
||||
"resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.10.0.tgz",
|
||||
"integrity": "sha512-w1aiOKwKuRgtwAReIIj89puqg+I7GvX4IbLrvmhXbzQsj1+Zwi4VO3+fa6ZF91TWSjIxoEkKnMeHcLEODK5ZXA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
|
||||
@@ -51,8 +51,10 @@
|
||||
"typescript": "^6.0.3"
|
||||
},
|
||||
"overrides": {
|
||||
"dompurify": "^3.4.2",
|
||||
"dompurify": "^3.4.13",
|
||||
"postcss": "^8.5.13",
|
||||
"sharp": "^0.35.3",
|
||||
"shell-quote": "^1.8.4",
|
||||
"uuid": "^14.0.0"
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import { fetchDocs as fetchDocsContent, fetchTutorials as fetchTutorialsContent
|
||||
import { Themes } from "@/util/themes";
|
||||
import { faExternalLink } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { RouterProvider } from "@heroui/react";
|
||||
import {
|
||||
HydrationBoundary,
|
||||
QueryClient,
|
||||
@@ -15,9 +16,19 @@ import {
|
||||
} from "@tanstack/react-query";
|
||||
import { ThemeProvider as NextThemesProvider } from "next-themes";
|
||||
import type { AppProps } from "next/app";
|
||||
import { useRouter } from "next/router";
|
||||
import React from "react";
|
||||
|
||||
export default function App({ Component, pageProps }: AppProps) {
|
||||
const router = useRouter();
|
||||
|
||||
const navigate = React.useCallback(
|
||||
(path: string) => {
|
||||
void router.push(path);
|
||||
},
|
||||
[router],
|
||||
);
|
||||
|
||||
// Initialize search
|
||||
const [search] = React.useState(() => new SearchCtx());
|
||||
|
||||
@@ -101,54 +112,50 @@ export default function App({ Component, pageProps }: AppProps) {
|
||||
>
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<HydrationBoundary state={pageProps.dehydratedState}>
|
||||
<SearchContext.Provider value={search}>
|
||||
<Navbar />
|
||||
<Component {...pageProps} />
|
||||
<div className="mb-16 md:mb-20"></div>
|
||||
<footer className="z-20 w-full border-t border-separator bg-surface/80 px-3 py-4 text-center shadow backdrop-blur-md dark:bg-black/75 md:fixed md:bottom-0 md:left-0 md:right-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-muted sm:text-sm md:flex-row md:items-center md:gap-3 md:text-left">
|
||||
<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} />
|
||||
<RouterProvider navigate={navigate}>
|
||||
<SearchContext.Provider value={search}>
|
||||
<div className="flex min-h-dvh flex-col">
|
||||
<Navbar />
|
||||
<main className="sliver-page-content flex-1">
|
||||
<Component {...pageProps} />
|
||||
</main>
|
||||
<footer className="sliver-fixed-footer fixed inset-x-0 bottom-0 z-30 border-t border-separator/70 bg-background/70 backdrop-blur-xl">
|
||||
<div className="mx-auto flex min-h-[var(--sliver-footer-height)] w-full max-w-7xl flex-col items-center justify-center gap-1.5 px-4 py-3 text-center text-sm text-muted sm:px-6 md:flex-row md:justify-between md:text-left lg:px-8">
|
||||
<span>
|
||||
© {new Date().getFullYear()} {" "}
|
||||
<a
|
||||
href="https://bishopfox.com/"
|
||||
className="font-medium text-foreground no-underline hover:text-accent"
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
Bishop Fox
|
||||
</a>
|
||||
</span>
|
||||
</a>
|
||||
</span>
|
||||
<div className="flex flex-wrap items-center justify-center gap-x-5 gap-y-2">
|
||||
<a
|
||||
href="https://github.com/BishopFox/sliver/pulls"
|
||||
rel="noreferrer"
|
||||
className="inline-flex items-center gap-1.5 no-underline hover:text-foreground"
|
||||
target="_blank"
|
||||
>
|
||||
Improve these docs
|
||||
<FontAwesomeIcon className="text-xs" icon={faExternalLink} />
|
||||
</a>
|
||||
<a
|
||||
href="https://github.com/BishopFox/sliver/blob/master/LICENSE"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="no-underline hover:text-foreground"
|
||||
>
|
||||
GPLv3
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
<ul className="mt-3 flex flex-wrap items-center justify-center gap-3 text-xs font-medium text-muted md:mt-0 md:gap-6 md:text-sm">
|
||||
<li>
|
||||
<a
|
||||
href="https://github.com/BishopFox/sliver/blob/master/LICENSE"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="hover:underline"
|
||||
>
|
||||
GPLv3 License
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</footer>
|
||||
</SearchContext.Provider>
|
||||
</SearchContext.Provider>
|
||||
</RouterProvider>
|
||||
</HydrationBoundary>
|
||||
</QueryClientProvider>
|
||||
</NextThemesProvider>
|
||||
|
||||
@@ -3,14 +3,18 @@ import LoadingState from "@/components/loading-state";
|
||||
import { Docs } from "@/util/docs";
|
||||
import { PREBUILD_VERSION } from "@/util/__generated__/prebuild-version";
|
||||
import { fetchDocs as fetchDocsContent } from "@/util/content-fetchers";
|
||||
import { faSearch } from "@fortawesome/free-solid-svg-icons";
|
||||
import {
|
||||
faBookOpen,
|
||||
faChevronRight,
|
||||
faSearch,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
ListBox,
|
||||
ScrollShadow,
|
||||
SearchField,
|
||||
Separator,
|
||||
} from "@heroui/react";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import Fuse from "fuse.js";
|
||||
@@ -20,6 +24,15 @@ import { useSearchParams } from "next/navigation";
|
||||
import { useRouter } from "next/router";
|
||||
import React from "react";
|
||||
|
||||
const featuredDocNames = [
|
||||
"Getting Started",
|
||||
"Compile from Source",
|
||||
"Architecture",
|
||||
"Armory",
|
||||
"Stagers",
|
||||
"Troubleshooting",
|
||||
];
|
||||
|
||||
const DocsIndexPage: NextPage = () => {
|
||||
const router = useRouter();
|
||||
|
||||
@@ -70,13 +83,20 @@ const DocsIndexPage: NextPage = () => {
|
||||
}, [docs, name, visibleDocs]);
|
||||
|
||||
const listboxClasses =
|
||||
"p-0 gap-0 divide-y divide-separator bg-surface overflow-visible rounded-lg shadow-sm";
|
||||
"flex flex-col gap-1 overflow-visible bg-transparent p-0";
|
||||
|
||||
const featuredDocs = React.useMemo(() => {
|
||||
return featuredDocNames
|
||||
.map((featuredName) => docs?.docs.find((doc) => doc.name === featuredName))
|
||||
.filter((doc) => doc !== undefined);
|
||||
}, [docs]);
|
||||
|
||||
const renderFilterInput = (className?: string) => (
|
||||
<SearchField
|
||||
aria-label="Filter documents"
|
||||
className={className}
|
||||
fullWidth
|
||||
variant="secondary"
|
||||
value={filterValue}
|
||||
onChange={setFilterValue}
|
||||
>
|
||||
@@ -99,87 +119,144 @@ const DocsIndexPage: NextPage = () => {
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>Sliver Docs: {name}</title>
|
||||
<title>{name ? `${name} · Sliver Docs` : "Sliver Documentation"}</title>
|
||||
</Head>
|
||||
<div className="px-4 pt-4 lg:hidden">
|
||||
<label
|
||||
htmlFor="docs-mobile-selector"
|
||||
className="block text-sm font-medium text-foreground"
|
||||
>
|
||||
Select a document
|
||||
</label>
|
||||
<div className="mt-2">{renderFilterInput()}</div>
|
||||
<select
|
||||
id="docs-mobile-selector"
|
||||
className="mt-3 w-full rounded-lg border border-separator bg-surface p-2 text-sm"
|
||||
value={name}
|
||||
onChange={(event) => {
|
||||
const selectedName = event.target.value;
|
||||
router.push({
|
||||
pathname: "/docs",
|
||||
query: selectedName ? { name: selectedName } : undefined,
|
||||
});
|
||||
}}
|
||||
>
|
||||
<option value="">Browse documents…</option>
|
||||
{mobileDocs.map((doc) => (
|
||||
<option key={doc.name} value={doc.name}>
|
||||
{doc.name}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 gap-6 lg:grid-cols-12 lg:gap-8">
|
||||
<aside className="hidden lg:block lg:col-span-3">
|
||||
<div className="sticky top-16 ml-4 flex flex-col gap-3">
|
||||
{renderFilterInput("mt-2")}
|
||||
<ScrollShadow className="max-h-[calc(100vh-15rem)] sliver-scrollbar overflow-y-auto pr-1 rounded-lg">
|
||||
<ListBox
|
||||
aria-label="Toolbox Menu"
|
||||
className={listboxClasses}
|
||||
onAction={(key) => {
|
||||
router.push({
|
||||
pathname: "/docs",
|
||||
query: { name: String(key) },
|
||||
});
|
||||
}}
|
||||
>
|
||||
{visibleDocs.map((doc) => (
|
||||
<ListBox.Item
|
||||
key={doc.name}
|
||||
id={doc.name}
|
||||
textValue={doc.name}
|
||||
className="h-12 rounded-none px-3 first:rounded-t-lg last:rounded-b-lg"
|
||||
>
|
||||
{doc.name}
|
||||
</ListBox.Item>
|
||||
))}
|
||||
</ListBox>
|
||||
</ScrollShadow>
|
||||
<div className="mx-auto w-full max-w-[90rem] px-4 pt-8 sm:px-6 lg:px-8 lg:pt-10">
|
||||
<div className="mb-8 lg:hidden">
|
||||
<div className="flex items-center gap-3">
|
||||
<span className="flex size-9 items-center justify-center rounded-2xl bg-surface-secondary text-accent">
|
||||
<FontAwesomeIcon icon={faBookOpen} />
|
||||
</span>
|
||||
<div>
|
||||
<p className="text-sm font-medium text-foreground">Documentation</p>
|
||||
<p className="text-xs text-muted">Browse the reference library</p>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
<div className="px-4 pb-8 lg:col-span-9 lg:px-8">
|
||||
{name !== "" ? (
|
||||
<Card className="mt-2">
|
||||
<Card.Header>
|
||||
<span className="text-3xl">{name}</span>
|
||||
</Card.Header>
|
||||
<Separator />
|
||||
<Card.Content>
|
||||
<div className="mt-5">{renderFilterInput()}</div>
|
||||
<label
|
||||
htmlFor="docs-mobile-selector"
|
||||
className="mt-4 block text-sm font-medium text-foreground"
|
||||
>
|
||||
Document
|
||||
</label>
|
||||
<select
|
||||
id="docs-mobile-selector"
|
||||
className="mt-2 w-full rounded-2xl border border-transparent bg-surface-secondary px-3 py-2.5 text-sm text-foreground outline-none focus:border-accent"
|
||||
value={name}
|
||||
onChange={(event) => {
|
||||
const selectedName = event.target.value;
|
||||
router.push({
|
||||
pathname: "/docs",
|
||||
query: selectedName ? { name: selectedName } : undefined,
|
||||
});
|
||||
}}
|
||||
>
|
||||
<option value="">Browse documents…</option>
|
||||
{mobileDocs.map((doc) => (
|
||||
<option key={doc.name} value={doc.name}>
|
||||
{doc.name}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div className="grid min-w-0 grid-cols-1 gap-8 lg:grid-cols-[17rem_minmax(0,1fr)] lg:gap-10">
|
||||
<aside className="sliver-sticky-sidebar hidden border-r border-separator/70 pr-6 lg:block">
|
||||
<div className="flex h-full min-h-0 flex-col gap-5">
|
||||
<div className="flex items-center gap-3 px-1">
|
||||
<span className="flex size-9 items-center justify-center rounded-2xl bg-surface-secondary text-accent">
|
||||
<FontAwesomeIcon icon={faBookOpen} />
|
||||
</span>
|
||||
<div>
|
||||
<p className="text-sm font-medium text-foreground">Documentation</p>
|
||||
<p className="text-xs text-muted">{docs.docs.length} articles</p>
|
||||
</div>
|
||||
</div>
|
||||
{renderFilterInput()}
|
||||
<ScrollShadow className="sliver-scrollbar min-h-0 flex-1 overscroll-contain overflow-y-auto pr-2">
|
||||
<ListBox
|
||||
aria-label="Documentation"
|
||||
className={listboxClasses}
|
||||
selectedKeys={name ? [name] : []}
|
||||
selectionMode="single"
|
||||
>
|
||||
{visibleDocs.map((doc) => (
|
||||
<ListBox.Item
|
||||
key={doc.name}
|
||||
id={doc.name}
|
||||
href={`/docs/?name=${encodeURIComponent(doc.name)}`}
|
||||
textValue={doc.name}
|
||||
className={`min-h-10 rounded-xl px-3 py-2 text-sm ${
|
||||
doc.name === name
|
||||
? "bg-surface font-medium text-foreground shadow-surface"
|
||||
: "text-muted"
|
||||
}`}
|
||||
>
|
||||
{doc.name}
|
||||
</ListBox.Item>
|
||||
))}
|
||||
</ListBox>
|
||||
</ScrollShadow>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<div
|
||||
key={name || "documentation-overview"}
|
||||
className="min-w-0 pb-16 lg:pr-4"
|
||||
>
|
||||
{name !== "" ? (
|
||||
<article className="mx-auto w-full max-w-4xl">
|
||||
<header className="mb-8 border-b border-separator/70 pb-8">
|
||||
<p className="text-sm font-medium text-accent">Reference</p>
|
||||
<h1 className="mt-2 text-balance text-4xl font-semibold tracking-tight text-foreground sm:text-5xl">
|
||||
{name}
|
||||
</h1>
|
||||
</header>
|
||||
<MarkdownViewer
|
||||
key={name}
|
||||
markdown={markdown || ""}
|
||||
demoteTopLevelHeading
|
||||
/>
|
||||
</Card.Content>
|
||||
</Card>
|
||||
) : (
|
||||
<div className="mt-8 text-center text-2xl text-foreground/90">
|
||||
Welcome to the Sliver Wiki!
|
||||
<div className="mt-2 text-xl text-muted">
|
||||
Please select a document
|
||||
</article>
|
||||
) : (
|
||||
<div className="mx-auto w-full max-w-5xl pt-4 lg:pt-8">
|
||||
<h1 className="text-sm font-medium text-accent">
|
||||
Sliver reference
|
||||
</h1>
|
||||
<p className="mt-4 max-w-2xl text-lg leading-8 text-muted">
|
||||
Browse configuration, transports, extensions, payloads, and
|
||||
troubleshooting guidance for the Sliver framework.
|
||||
</p>
|
||||
|
||||
<div className="mt-10 grid gap-4 sm:grid-cols-2">
|
||||
{featuredDocs.map((doc) => (
|
||||
<Card key={doc.name} className="h-full">
|
||||
<Card.Header>
|
||||
<Card.Title>{doc.name}</Card.Title>
|
||||
<Card.Description>
|
||||
Open this topic in the Sliver reference.
|
||||
</Card.Description>
|
||||
</Card.Header>
|
||||
<Card.Footer className="mt-auto">
|
||||
<Button
|
||||
variant="ghost"
|
||||
onPress={() => {
|
||||
router.push({
|
||||
pathname: "/docs",
|
||||
query: { name: doc.name },
|
||||
});
|
||||
}}
|
||||
>
|
||||
Open article
|
||||
<FontAwesomeIcon icon={faChevronRight} />
|
||||
</Button>
|
||||
</Card.Footer>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
- https://dominicbreuker.com/post/learning_sliver_c2_01_installation/
|
||||
- https://vk9-sec.com/how-to-set-up-use-c2-sliver/
|
||||
- https://0x90-1.gitbook.io/sliver/
|
||||
- https://blog.ecapuano.com/p/so-you-want-to-be-a-soc-analyst-part-ea2
|
||||
- https://blog.ecapuano.com/p/so-you-want-to-be-a-soc-analyst-20
|
||||
- https://wsummerhill.github.io/redteam/2023/07/25/Sliver-C2-Usage-for-Red-Teams.html
|
||||
- https://rootsecdev.medium.com/hacking-active-directory-with-sliver-c2-19d7ceabbf13
|
||||
- https://dev.to/living_syn/sliver-and-cursed-chrome-for-post-exploitation-4gnk
|
||||
|
||||
@@ -2,7 +2,7 @@ You'll want to compile Sliver from a MacOS or Linux machine. Compiling from nati
|
||||
|
||||
To compile from source you'll need:
|
||||
|
||||
- Go v1.25 or later
|
||||
- Go v1.26.6 or later
|
||||
- `make` (on MacOS you may need to install XCode and accompanying cli tools)
|
||||
|
||||
```asciinema
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
Sliver can generate Go c-archive output for use in native link workflows. The archive format returns a ZIP bundle containing the generated static archive (`.a`) and C headers (`.h`) produced by Go's `c-archive` build mode.
|
||||
|
||||
Use this format when you want to link the generated implant entrypoint into another native artifact, such as a DLL or application, and validate that the exported symbol resolves correctly in your own loader or harness.
|
||||
|
||||
## Generate an Archive
|
||||
|
||||
For the example, a Windows archive was generated via the Sliver console:
|
||||
|
||||
```shell
|
||||
sliver > generate --format archive --os windows --arch amd64 --mtls 127.0.0.1
|
||||
```
|
||||
|
||||
The output ZIP contains an archive (`.a`) file and the headers (`.h`).
|
||||
|
||||
```text
|
||||
ARCHITECTURAL_YOKE.a
|
||||
ARCHITECTURAL_YOKE.h
|
||||
main.h
|
||||
```
|
||||
|
||||
If no export symbols are configured, Sliver exports `StartW` by default. The examples below assume the generated implant name is `ARCHITECTURAL_YOKE`; replace that name with the files generated in your environment.
|
||||
|
||||
## Link the Archive into a DLL
|
||||
|
||||
Create a wrapper that calls `StartW` from a worker thread when the DLL loads, which keeps `DllMain` lightweight and avoids doing long-running initialization work while the Windows loader lock is held.
|
||||
|
||||
```cpp
|
||||
#include "ARCHITECTURAL_YOKE.h"
|
||||
#include <windows.h>
|
||||
|
||||
DWORD WINAPI WorkerThread(LPVOID lpParam)
|
||||
{
|
||||
StartW();
|
||||
return 0;
|
||||
}
|
||||
|
||||
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)
|
||||
{
|
||||
if (fdwReason == DLL_PROCESS_ATTACH) {
|
||||
DisableThreadLibraryCalls(hinstDLL);
|
||||
|
||||
HANDLE hThread = CreateThread(NULL, 0, WorkerThread, NULL, 0, NULL);
|
||||
if (hThread != NULL) {
|
||||
CloseHandle(hThread);
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
```
|
||||
|
||||
Compile the wrapper and link it with the generated archive:
|
||||
|
||||
```shell
|
||||
x86_64-w64-mingw32-g++ -std=c++11 -Wall -I. -shared -o beacon.dll wrapper.cpp ARCHITECTURAL_YOKE.a
|
||||
```
|
||||
|
||||
## Validate Symbol Resolution
|
||||
|
||||
Sample minimal loader to confirm the DLL loads and the `StartW` export resolves:
|
||||
|
||||
```c
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main() {
|
||||
HMODULE h = LoadLibraryA("beacon.dll");
|
||||
if (!h) {
|
||||
printf("LoadLibrary failed: %lu\n", GetLastError());
|
||||
return 1;
|
||||
}
|
||||
|
||||
FARPROC p = GetProcAddress(h, "StartW");
|
||||
printf("LoadLibrary OK, StartW=%p\n", p);
|
||||
|
||||
FreeLibrary(h);
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
Build the loader:
|
||||
|
||||
```shell
|
||||
x86_64-w64-mingw32-gcc -Wall -o loader.exe loader.c
|
||||
```
|
||||
|
||||
Run the loader in an authorized local test environment with `beacon.dll` in the same directory.
|
||||
|
||||
## Validate Invocation
|
||||
|
||||
To validate that the resolved entrypoint can be invoked, use a small test application:
|
||||
|
||||
```c
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
|
||||
typedef void (*StartWFn)(void);
|
||||
|
||||
int main() {
|
||||
HMODULE h = LoadLibraryA("beacon.dll");
|
||||
if (!h) {
|
||||
printf("LoadLibrary failed: %lu\n", GetLastError());
|
||||
return 1;
|
||||
}
|
||||
|
||||
StartWFn StartW = (StartWFn)GetProcAddress(h, "StartW");
|
||||
if (!StartW) {
|
||||
printf("GetProcAddress failed: %lu\n", GetLastError());
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("Calling StartW...\n");
|
||||
StartW();
|
||||
|
||||
printf("StartW returned\n");
|
||||
FreeLibrary(h);
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
Build the invocation test:
|
||||
|
||||
```shell
|
||||
x86_64-w64-mingw32-gcc -Wall -o call_startw.exe call_startw.c
|
||||
```
|
||||
|
||||
This validates the archive-to-DLL link path, DLL loading, export lookup, and `StartW` invocation all work as expected.
|
||||
|
||||
@@ -14,7 +14,7 @@ For this to work, we need the following pieces:
|
||||
|
||||
- a staging server (the Sliver server)
|
||||
- a stage 2 payload (usually a Sliver shellcode, but can be in other formats)
|
||||
- stagers (generated by `msfvenom`, the Sliver `generate stager` command, or a custom one)
|
||||
- stagers (generated by `msfvenom` or built by hand, see [Custom Stagers](#custom-stagers) below)
|
||||
|
||||
## Example
|
||||
|
||||
@@ -81,7 +81,11 @@ ID Name Protocol Port
|
||||
|
||||
**Using Metasploit stagers is only supported on Windows.**
|
||||
|
||||
#### Generating an HTTP stager
|
||||
> **Note:** The Sliver `generate stager` command has been removed and will no longer
|
||||
> work. Generate stagers using Metasploit's `msfvenom` (or write your own custom
|
||||
> stager, see [Custom Stagers](#custom-stagers) below).
|
||||
|
||||
#### Generating an HTTP(S) stager
|
||||
If you want to use [stagers generated by the Metasploit Framework with Sliver](https://www.rapid7.com/blog/post/2022/09/16/metasploit-weekly-wrap-up-176/) (using `msfconsole` or `msfvenom`), you will need to pass the additional `--prepend-size` flag to `stage-listener`, like this:
|
||||
|
||||
```
|
||||
|
||||
+190
-122
@@ -1,144 +1,212 @@
|
||||
import AsciinemaPlayer from "@/components/asciinema";
|
||||
import { SliversIcon } from "@/components/icons/slivers";
|
||||
import TutorialCard from "@/components/tutorial-card";
|
||||
import { Themes } from "@/util/themes";
|
||||
import { faDownload, faExternalLink } from "@fortawesome/free-solid-svg-icons";
|
||||
import {
|
||||
faArrowUpRightFromSquare,
|
||||
faDownload,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { Button, Card, Separator } from "@heroui/react";
|
||||
import { useTheme } from "next-themes";
|
||||
import { Button, Card, buttonVariants } from "@heroui/react";
|
||||
import Head from "next/head";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/router";
|
||||
import React from "react";
|
||||
|
||||
export default function Home() {
|
||||
const router = useRouter();
|
||||
const { resolvedTheme } = useTheme();
|
||||
|
||||
const isDarkTheme = React.useMemo(() => {
|
||||
return (resolvedTheme || Themes.DARK) !== Themes.LIGHT;
|
||||
}, [resolvedTheme]);
|
||||
|
||||
return (
|
||||
<div className="mt-6 flex flex-col gap-6 px-4 sm:px-6 lg:grid lg:grid-cols-12 lg:px-12">
|
||||
<div className="lg:col-span-6">
|
||||
<div className="w-full overflow-hidden rounded-xl border border-separator bg-surface shadow-sm">
|
||||
<div className="w-full overflow-x-auto lg:overflow-visible">
|
||||
<AsciinemaPlayer
|
||||
src="/asciinema/intro.cast"
|
||||
rows="18"
|
||||
cols="75"
|
||||
idleTimeLimit={60}
|
||||
preload={true}
|
||||
autoPlay={true}
|
||||
loop={true}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="lg:col-span-6 lg:ml-2">
|
||||
<Card className="mx-auto max-w-3xl lg:mx-0">
|
||||
<Card.Header>
|
||||
<div className="flex items-center">
|
||||
<SliversIcon className="mr-2" height={28} />
|
||||
<span className="text-2xl">Sliver Command & Control</span>
|
||||
<>
|
||||
<Head>
|
||||
<title>Sliver C2 Documentation</title>
|
||||
<meta
|
||||
name="description"
|
||||
content="Documentation, tutorials, and community resources for the Sliver command and control framework."
|
||||
/>
|
||||
</Head>
|
||||
|
||||
<div className="relative overflow-hidden">
|
||||
<div className="sliver-grid-surface pointer-events-none absolute inset-x-0 top-0 h-[34rem] opacity-55" />
|
||||
|
||||
<div className="relative mx-auto w-full max-w-7xl px-4 pb-20 pt-8 sm:px-6 sm:pt-12 lg:px-8 lg:pt-16">
|
||||
<section className="grid min-w-0 grid-cols-1 items-stretch gap-6 lg:grid-cols-12">
|
||||
<div className="min-w-0 lg:col-span-7">
|
||||
<Card className="relative h-full min-w-0 gap-0 overflow-hidden rounded-3xl bg-black p-0 shadow-surface">
|
||||
<div className="absolute right-3 top-3 z-10 max-w-[calc(100%_-_1.5rem)]">
|
||||
<Link
|
||||
href="/tutorials"
|
||||
aria-label="Browse Sliver tutorials"
|
||||
className="inline-flex min-w-0 cursor-pointer items-center gap-2.5 rounded-xl border border-white/15 bg-black/55 px-3 py-2 text-white no-underline shadow-lg outline-none backdrop-blur-xl hover:bg-black/70 focus-visible:ring-2 focus-visible:ring-white/70"
|
||||
>
|
||||
<span className="flex size-7 shrink-0 items-center justify-center rounded-lg bg-white/10 text-white/90">
|
||||
<SliversIcon height={16} />
|
||||
</span>
|
||||
<div className="min-w-0">
|
||||
<p className="truncate text-xs font-semibold">
|
||||
Sliver operator console
|
||||
</p>
|
||||
<p className="truncate text-[11px] text-white/60">
|
||||
Interactive command tour
|
||||
</p>
|
||||
</div>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<div className="sliver-terminal-frame min-h-[20rem] flex-1 overflow-x-auto bg-[#111315] sm:min-h-[24rem]">
|
||||
<AsciinemaPlayer
|
||||
className="sliver-asciinema-bottom-aligned h-full w-full sm:min-w-[35rem]"
|
||||
src="/asciinema/intro.cast"
|
||||
fit="width"
|
||||
hideControls
|
||||
rows="18"
|
||||
cols="75"
|
||||
idleTimeLimit={60}
|
||||
preload={true}
|
||||
autoPlay={true}
|
||||
loop={true}
|
||||
/>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
</Card.Header>
|
||||
<Separator />
|
||||
<Card.Content>
|
||||
<p className={isDarkTheme ? "prose dark:prose-invert" : "prose prose-slate"}>
|
||||
Sliver is a powerful command and control (C2) framework designed
|
||||
to provide advanced capabilities for covertly managing and
|
||||
controlling remote systems. With Sliver, security professionals,
|
||||
red teams, and penetration testers can easily establish a secure
|
||||
and reliable communication channel over Mutual TLS, HTTP(S), DNS,
|
||||
or Wireguard with target machines. Enabling them to execute
|
||||
commands, gather information, and perform various
|
||||
post-exploitation activities. The framework offers a user-friendly
|
||||
console interface, extensive functionality, and support for
|
||||
multiple operating systems as well as multiple CPU architectures,
|
||||
making it an indispensable tool for conducting comprehensive
|
||||
offensive security operations.
|
||||
</p>
|
||||
<div className="mt-4 flex w-full gap-3">
|
||||
|
||||
<Card className="h-full bg-surface/80 shadow-surface backdrop-blur-2xl lg:col-span-5">
|
||||
<Card.Header className="pb-3">
|
||||
<div className="min-w-0">
|
||||
<p className="text-sm font-medium text-accent">
|
||||
Operator documentation
|
||||
</p>
|
||||
<h1 className="mt-1 text-balance text-3xl font-semibold tracking-tight text-foreground sm:text-4xl">
|
||||
Sliver Command & Control
|
||||
</h1>
|
||||
</div>
|
||||
</Card.Header>
|
||||
|
||||
<Card.Content className="pt-2">
|
||||
<p className="text-pretty text-base leading-7 text-muted">
|
||||
Sliver is a cross-platform command and control framework for
|
||||
professional red teams. Operate over mTLS, WireGuard, HTTP(S),
|
||||
and DNS from one console, with broad operating-system and CPU
|
||||
architecture support.
|
||||
</p>
|
||||
<p className="mt-4 text-sm leading-6 text-muted">
|
||||
Start with the operator guide, download the latest release, or
|
||||
extend your workflow with community packages from the Armory.
|
||||
</p>
|
||||
</Card.Content>
|
||||
|
||||
<Card.Footer className="mt-auto flex-col items-stretch gap-3 pt-5">
|
||||
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2">
|
||||
<Button
|
||||
fullWidth
|
||||
variant="primary"
|
||||
onPress={() =>
|
||||
router.push({
|
||||
pathname: "/docs",
|
||||
query: { name: "Getting Started" },
|
||||
})
|
||||
}
|
||||
>
|
||||
Get started
|
||||
</Button>
|
||||
<Button
|
||||
className="[--button-bg-hover:var(--color-purple-700)] [--button-bg-pressed:var(--color-purple-700)] [--button-bg:var(--color-purple-600)] [--button-fg:var(--color-white)]"
|
||||
fullWidth
|
||||
variant="tertiary"
|
||||
onPress={() => {
|
||||
window.open(
|
||||
"https://github.com/BishopFox/sliver/releases/latest",
|
||||
"_blank",
|
||||
"noopener,noreferrer",
|
||||
);
|
||||
}}
|
||||
>
|
||||
<FontAwesomeIcon icon={faDownload} />
|
||||
Latest release
|
||||
</Button>
|
||||
</div>
|
||||
<a
|
||||
className={buttonVariants({
|
||||
fullWidth: true,
|
||||
variant: "secondary",
|
||||
})}
|
||||
href="https://github.com/sliverarmory"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
Browse the Armory
|
||||
<FontAwesomeIcon
|
||||
className="text-xs"
|
||||
icon={faArrowUpRightFromSquare}
|
||||
/>
|
||||
</a>
|
||||
</Card.Footer>
|
||||
</Card>
|
||||
</section>
|
||||
|
||||
<section
|
||||
aria-labelledby="quick-guides-heading"
|
||||
className="mt-12 border-t border-separator/70 pt-10"
|
||||
>
|
||||
<div className="flex flex-col gap-3 sm:flex-row sm:items-end sm:justify-between">
|
||||
<div>
|
||||
<h2
|
||||
id="quick-guides-heading"
|
||||
className="text-sm font-medium text-accent"
|
||||
>
|
||||
Quick guides
|
||||
</h2>
|
||||
<blockquote className="mt-1 max-w-3xl text-xl font-medium italic leading-snug tracking-tight text-foreground sm:text-2xl">
|
||||
Bred as living shields, these slivers have proven unruly—they
|
||||
know they cannot be caught.
|
||||
</blockquote>
|
||||
</div>
|
||||
<Button
|
||||
className="flex-1"
|
||||
variant="primary"
|
||||
onPress={() => {
|
||||
window.open(
|
||||
"https://github.com/BishopFox/sliver/releases/latest",
|
||||
"_blank",
|
||||
"noopener,noreferrer",
|
||||
);
|
||||
}}
|
||||
>
|
||||
<FontAwesomeIcon icon={faDownload} />
|
||||
Download Latest Release
|
||||
</Button>
|
||||
<Button
|
||||
className="sliver-armory-ghost flex-1"
|
||||
variant="ghost"
|
||||
onPress={() => {
|
||||
window.open(
|
||||
"https://github.com/sliverarmory",
|
||||
"_blank",
|
||||
"noopener,noreferrer",
|
||||
);
|
||||
}}
|
||||
onPress={() => router.push("/tutorials")}
|
||||
>
|
||||
Visit the Armory
|
||||
<FontAwesomeIcon icon={faExternalLink} />
|
||||
Browse all tutorials
|
||||
</Button>
|
||||
</div>
|
||||
</Card.Content>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
<div className="col-span-12 mt-8">
|
||||
<Separator />
|
||||
</div>
|
||||
<div className="mt-6 grid min-w-0 grid-cols-1 gap-5 xl:grid-cols-2">
|
||||
<TutorialCard
|
||||
name="Getting Started"
|
||||
description="Install Sliver and open your first operator workflow."
|
||||
asciiCast="/asciinema/install-1.cast"
|
||||
cols="133"
|
||||
rows="32"
|
||||
idleTimeLimit={1}
|
||||
hideControls
|
||||
showButton={true}
|
||||
buttonText="Read guide"
|
||||
onPress={() => {
|
||||
router.push({
|
||||
pathname: "/docs",
|
||||
query: { name: "Getting Started" },
|
||||
});
|
||||
}}
|
||||
/>
|
||||
|
||||
<div className="col-span-12 mt-8">
|
||||
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-9">
|
||||
<div className="sm:col-span-1 lg:col-span-3">
|
||||
<TutorialCard
|
||||
name="Getting Started"
|
||||
description="A quick start guide to get you up and running"
|
||||
asciiCast="/asciinema/install-1.cast"
|
||||
cols="133"
|
||||
rows="32"
|
||||
idleTimeLimit={1}
|
||||
showButton={true}
|
||||
buttonText="Read Docs"
|
||||
onPress={() => {
|
||||
router.push({
|
||||
pathname: "/docs",
|
||||
query: { name: "Getting Started" },
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="sm:col-span-1 lg:col-span-3">
|
||||
<TutorialCard
|
||||
name="Compile From Source"
|
||||
description="How to compile Sliver from source"
|
||||
asciiCast="/asciinema/compile-from-source.cast"
|
||||
cols="133"
|
||||
rows="32"
|
||||
idleTimeLimit={1}
|
||||
showButton={true}
|
||||
buttonText="Read Docs"
|
||||
onPress={() => {
|
||||
router.push({
|
||||
pathname: "/docs",
|
||||
query: { name: "Compile from Source" },
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<TutorialCard
|
||||
name="Compile from Source"
|
||||
description="Build a development copy and understand the toolchain."
|
||||
asciiCast="/asciinema/compile-from-source.cast"
|
||||
cols="133"
|
||||
rows="32"
|
||||
idleTimeLimit={1}
|
||||
hideControls
|
||||
showButton={true}
|
||||
buttonText="Read guide"
|
||||
onPress={() => {
|
||||
router.push({
|
||||
pathname: "/docs",
|
||||
query: { name: "Compile from Source" },
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="col-span-12 mb-8"></div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,66 +1,165 @@
|
||||
import MarkdownViewer from "@/components/markdown";
|
||||
import { useSearchContext } from "@/util/search-context";
|
||||
import { faChevronCircleRight } from "@fortawesome/free-solid-svg-icons";
|
||||
import LoadingState from "@/components/loading-state";
|
||||
import { PREBUILD_VERSION } from "@/util/__generated__/prebuild-version";
|
||||
import { fetchDocs as fetchDocsContent } from "@/util/content-fetchers";
|
||||
import { SearchCtx } from "@/util/search-context";
|
||||
import {
|
||||
faChevronRight,
|
||||
faMagnifyingGlass,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { Button, Card, Separator } from "@heroui/react";
|
||||
import { Button, Card, SearchField } from "@heroui/react";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { NextPage } from "next";
|
||||
import Head from "next/head";
|
||||
import { useSearchParams } from "next/navigation";
|
||||
import { useRouter } from "next/router";
|
||||
import React from "react";
|
||||
|
||||
export type SearchPageProps = {};
|
||||
|
||||
const createExcerpt = (markdown: string) => {
|
||||
return markdown
|
||||
.replace(/```[\s\S]*?```/g, " ")
|
||||
.replace(/!\[[^\]]*\]\([^)]*\)/g, " ")
|
||||
.replace(/\[([^\]]+)\]\([^)]*\)/g, "$1")
|
||||
.replace(/[#>*_`~|-]/g, " ")
|
||||
.replace(/\s+/g, " ")
|
||||
.trim()
|
||||
.slice(0, 240);
|
||||
};
|
||||
|
||||
const SearchPage: NextPage = (props: SearchPageProps) => {
|
||||
const router = useRouter();
|
||||
const search = useSearchContext();
|
||||
const query = useSearchParams().get("search");
|
||||
const query = useSearchParams().get("search")?.trim() || "";
|
||||
const { data: docs, isLoading } = useQuery({
|
||||
queryKey: ["docs", PREBUILD_VERSION],
|
||||
queryFn: () => fetchDocsContent(PREBUILD_VERSION),
|
||||
});
|
||||
|
||||
const docsSearch = React.useMemo(() => {
|
||||
const search = new SearchCtx();
|
||||
if (docs) {
|
||||
search.addDocs(docs);
|
||||
}
|
||||
return search;
|
||||
}, [docs]);
|
||||
|
||||
const searchResults = React.useMemo(() => {
|
||||
if (query) {
|
||||
return search.searchDocs(query);
|
||||
return docsSearch.searchDocs(query);
|
||||
}
|
||||
return [];
|
||||
}, [query, search]);
|
||||
}, [docsSearch, query]);
|
||||
|
||||
if (isLoading || !docs) {
|
||||
return <LoadingState />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="px-4 pb-8 pt-4">
|
||||
<div className="mx-auto flex w-full max-w-5xl flex-col gap-4">
|
||||
<div className="text-3xl">
|
||||
Search: "{query?.slice(0, 50)}"
|
||||
<div className="text-sm text-gray-500">
|
||||
{searchResults.length} Results
|
||||
<>
|
||||
<Head>
|
||||
<title>{query ? `Search: ${query} · Sliver Docs` : "Search · Sliver Docs"}</title>
|
||||
</Head>
|
||||
<div className="mx-auto w-full max-w-5xl px-4 pb-20 pt-12 sm:px-6 lg:px-8 lg:pt-16">
|
||||
<header className="max-w-3xl">
|
||||
<p className="text-sm font-medium text-accent">Search the reference</p>
|
||||
<h1 className="mt-2 text-balance text-4xl font-semibold tracking-tight text-foreground sm:text-5xl">
|
||||
Find exactly what you need.
|
||||
</h1>
|
||||
<p className="mt-4 text-lg leading-8 text-muted">
|
||||
Search configuration, workflows, transports, extensions, and
|
||||
troubleshooting notes across the Sliver documentation.
|
||||
</p>
|
||||
</header>
|
||||
|
||||
<SearchField
|
||||
key={query}
|
||||
aria-label="Search documentation"
|
||||
className="mt-8 max-w-2xl"
|
||||
defaultValue={query}
|
||||
fullWidth
|
||||
onClear={() => router.push("/search")}
|
||||
onSubmit={(value) => {
|
||||
const nextQuery = value.trim();
|
||||
if (nextQuery) {
|
||||
router.push({ pathname: "/search", query: { search: nextQuery } });
|
||||
}
|
||||
}}
|
||||
>
|
||||
<SearchField.Group>
|
||||
<SearchField.SearchIcon>
|
||||
<FontAwesomeIcon icon={faMagnifyingGlass} />
|
||||
</SearchField.SearchIcon>
|
||||
<SearchField.Input placeholder="Search documentation…" />
|
||||
<SearchField.ClearButton aria-label="Clear search" />
|
||||
</SearchField.Group>
|
||||
</SearchField>
|
||||
|
||||
<div className="mt-10 flex items-end justify-between gap-4">
|
||||
<div>
|
||||
<h2 className="text-2xl font-semibold text-foreground">
|
||||
{query ? `Results for “${query.slice(0, 50)}”` : "Search results"}
|
||||
</h2>
|
||||
<p className="mt-1 text-sm tabular-nums text-muted">
|
||||
{searchResults.length} {searchResults.length === 1 ? "result" : "results"}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{searchResults.map((doc) => (
|
||||
<Card key={doc.name}>
|
||||
<Card.Content className="flex flex-col gap-3">
|
||||
<div className="flex flex-col gap-3 sm:flex-row sm:items-center">
|
||||
<span className="text-xl">{doc.name}</span>
|
||||
<div className="flex-1"></div>
|
||||
{searchResults.length > 0 ? (
|
||||
<div className="mt-5 grid gap-4">
|
||||
{searchResults.map((doc) => (
|
||||
<Card key={doc.name}>
|
||||
<Card.Header>
|
||||
<Card.Title>{doc.name}</Card.Title>
|
||||
<Card.Description className="mt-1 max-w-3xl leading-6">
|
||||
{createExcerpt(doc.content) || "Open this article in the Sliver reference."}
|
||||
{doc.content.length > 240 ? "…" : ""}
|
||||
</Card.Description>
|
||||
</Card.Header>
|
||||
<Card.Footer>
|
||||
<Button
|
||||
variant="ghost"
|
||||
onPress={() => {
|
||||
router.push({ pathname: "/docs", query: { name: doc.name } });
|
||||
}}
|
||||
>
|
||||
Open article
|
||||
<FontAwesomeIcon icon={faChevronRight} />
|
||||
</Button>
|
||||
</Card.Footer>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<Card className="mt-5">
|
||||
<Card.Content className="flex flex-col items-start gap-3 p-8">
|
||||
<span className="flex size-10 items-center justify-center rounded-2xl bg-surface-secondary text-accent">
|
||||
<FontAwesomeIcon icon={faMagnifyingGlass} />
|
||||
</span>
|
||||
<div>
|
||||
<h2 className="text-lg font-semibold text-foreground">
|
||||
{query ? "No matching documentation" : "Start with a keyword"}
|
||||
</h2>
|
||||
<p className="mt-1 max-w-xl text-sm leading-6 text-muted">
|
||||
{query
|
||||
? "Try a command name, transport, feature, or a shorter phrase."
|
||||
: "Search for topics like staging, WireGuard, profiles, or extensions."}
|
||||
</p>
|
||||
</div>
|
||||
{query ? (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="secondary"
|
||||
className="w-full sm:w-[150px]"
|
||||
onPress={() => {
|
||||
router.push(`/docs?name=${doc.name}`);
|
||||
}}
|
||||
variant="outline"
|
||||
onPress={() => router.push("/docs")}
|
||||
>
|
||||
Full Doc
|
||||
<FontAwesomeIcon icon={faChevronCircleRight} />
|
||||
Browse all documentation
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<Separator />
|
||||
|
||||
<div className="max-h-[200px] overflow-hidden">
|
||||
<MarkdownViewer markdown={doc.content} />
|
||||
</div>
|
||||
) : null}
|
||||
</Card.Content>
|
||||
</Card>
|
||||
))}
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import Youtube from "@/components/youtube";
|
||||
import { faChevronRight } from "@fortawesome/free-solid-svg-icons";
|
||||
import { faArrowUpRightFromSquare } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { Accordion, Button, Card } from "@heroui/react";
|
||||
import { Accordion, Card } from "@heroui/react";
|
||||
import { NextPage } from "next";
|
||||
import Head from "next/head";
|
||||
import React from "react";
|
||||
@@ -21,7 +21,7 @@ type TalkSection = {
|
||||
|
||||
const workshopTalks: Talk[] = [
|
||||
{
|
||||
title:"Getting Started with Sliver v1.6",
|
||||
title: "Getting Started with Sliver v1.6",
|
||||
description: "Introductory workshop covering basics and new features.",
|
||||
url: "https://www.youtube.com/watch?v=IOiyXYp1lDc",
|
||||
},
|
||||
@@ -47,7 +47,7 @@ const generalTradecraftTalks: Talk[] = [
|
||||
title: "The Sliver C2 Framework",
|
||||
description: "General discussion of C2 design.",
|
||||
url: "https://www.youtube.com/watch?v=tkjMZuZ_8nw",
|
||||
}
|
||||
},
|
||||
];
|
||||
|
||||
const communityTalks: Talk[] = [
|
||||
@@ -100,81 +100,124 @@ const talkSections: TalkSection[] = [
|
||||
];
|
||||
|
||||
const TalksIndexPage: NextPage = () => {
|
||||
const [footerHidden, setFooterHidden] = React.useState<Record<string, boolean>>(
|
||||
{}
|
||||
);
|
||||
const actionButtonClassName =
|
||||
"ml-auto h-auto min-h-0 shrink-0 px-0 py-0 text-sm font-semibold [--button-bg-hover:transparent] [--button-bg-pressed:transparent] [--button-bg:transparent] [--button-fg:var(--warning)]";
|
||||
const [overlayHidden, setOverlayHidden] = React.useState<
|
||||
Record<string, boolean>
|
||||
>({});
|
||||
|
||||
const hideFooterFor = React.useCallback((url: string) => {
|
||||
setFooterHidden((prev) => (prev[url] ? prev : { ...prev, [url]: true }));
|
||||
const hideOverlayFor = React.useCallback((url: string) => {
|
||||
setOverlayHidden((current) =>
|
||||
current[url] ? current : { ...current, [url]: true },
|
||||
);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>Sliver Talks</title>
|
||||
<meta
|
||||
name="description"
|
||||
content="Sliver workshops, technical talks, and community videos."
|
||||
/>
|
||||
</Head>
|
||||
<div className="mt-6 px-4 pb-8 sm:px-6 lg:px-12">
|
||||
<Accordion
|
||||
allowsMultipleExpanded
|
||||
defaultExpandedKeys={["workshops", "general-tradecraft"]}
|
||||
hideSeparator
|
||||
className="px-0"
|
||||
>
|
||||
{talkSections.map((section) => (
|
||||
<Accordion.Item
|
||||
key={section.key}
|
||||
id={section.key}
|
||||
>
|
||||
<Accordion.Heading>
|
||||
<Accordion.Trigger>
|
||||
<span className="flex flex-col items-start text-left">
|
||||
<span className="text-lg font-semibold">{section.title}</span>
|
||||
<span className="text-sm text-muted">{section.description}</span>
|
||||
</span>
|
||||
<Accordion.Indicator className="ml-auto" />
|
||||
</Accordion.Trigger>
|
||||
</Accordion.Heading>
|
||||
<Accordion.Panel>
|
||||
<Accordion.Body>
|
||||
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-9">
|
||||
{section.talks.map((talk) => (
|
||||
<div key={talk.url} className="sm:col-span-1 lg:col-span-3">
|
||||
<Card className="relative z-0 gap-0 overflow-hidden p-0">
|
||||
<Youtube
|
||||
className="w-full"
|
||||
url={talk.url}
|
||||
title={talk.title}
|
||||
onPlay={() => hideFooterFor(talk.url)}
|
||||
/>
|
||||
|
||||
{footerHidden[talk.url] ? null : (
|
||||
<Card.Footer className="absolute bottom-0 left-0 right-0 z-10 border-t border-white/20 bg-black/40 p-3 backdrop-blur-md">
|
||||
<div className="flex min-h-10 w-full items-center gap-4">
|
||||
<p className="min-w-0 flex-1 text-sm leading-snug text-white/80">{talk.description}</p>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className={actionButtonClassName}
|
||||
onPress={() => {
|
||||
window.open(talk.url, "_blank", "noopener,noreferrer");
|
||||
}}
|
||||
>
|
||||
Watch <FontAwesomeIcon icon={faChevronRight} />
|
||||
</Button>
|
||||
</div>
|
||||
</Card.Footer>
|
||||
)}
|
||||
</Card>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</Accordion.Body>
|
||||
</Accordion.Panel>
|
||||
</Accordion.Item>
|
||||
))}
|
||||
</Accordion>
|
||||
<div className="relative overflow-hidden">
|
||||
<div className="sliver-grid-surface pointer-events-none absolute inset-x-0 top-0 h-72 opacity-35" />
|
||||
|
||||
<div className="relative mx-auto w-full max-w-7xl px-4 pb-20 pt-8 sm:px-6 sm:pt-10 lg:px-8 lg:pt-12">
|
||||
<header className="mb-6 max-w-3xl">
|
||||
<p className="text-sm font-medium text-accent">Talks & workshops</p>
|
||||
<h1 className="mt-1 text-balance text-3xl font-semibold tracking-tight text-foreground sm:text-4xl">
|
||||
Watch Sliver in the field.
|
||||
</h1>
|
||||
<p className="mt-3 max-w-2xl text-base leading-7 text-muted">
|
||||
Practical workshops, technical deep dives, and community sessions
|
||||
collected in one compact library.
|
||||
</p>
|
||||
</header>
|
||||
|
||||
<Accordion
|
||||
allowsMultipleExpanded
|
||||
defaultExpandedKeys={["workshops", "general-tradecraft"]}
|
||||
hideSeparator
|
||||
className="w-full px-0"
|
||||
>
|
||||
{talkSections.map((section) => (
|
||||
<Accordion.Item key={section.key} id={section.key}>
|
||||
<Accordion.Heading>
|
||||
<Accordion.Trigger>
|
||||
<span className="flex flex-col items-start text-left">
|
||||
<span className="flex items-center gap-2 text-lg font-semibold text-foreground">
|
||||
{section.title}
|
||||
<span className="text-xs font-normal tabular-nums text-muted">
|
||||
{section.talks.length}
|
||||
</span>
|
||||
</span>
|
||||
<span className="mt-1 text-sm text-muted">
|
||||
{section.description}
|
||||
</span>
|
||||
</span>
|
||||
<Accordion.Indicator className="ml-auto" />
|
||||
</Accordion.Trigger>
|
||||
</Accordion.Heading>
|
||||
|
||||
<Accordion.Panel>
|
||||
<Accordion.Body>
|
||||
<div className="grid grid-cols-1 gap-4 md:grid-cols-2 xl:grid-cols-3">
|
||||
{section.talks.map((talk) => (
|
||||
<Card
|
||||
key={talk.url}
|
||||
className="relative z-0 gap-0 overflow-hidden bg-black p-0 shadow-surface"
|
||||
>
|
||||
<Youtube
|
||||
className="w-full"
|
||||
url={talk.url}
|
||||
title={talk.title}
|
||||
onInteract={() => hideOverlayFor(talk.url)}
|
||||
onPlay={() => hideOverlayFor(talk.url)}
|
||||
/>
|
||||
|
||||
{overlayHidden[talk.url] ? null : (
|
||||
<>
|
||||
<div
|
||||
aria-hidden="true"
|
||||
className="pointer-events-none absolute inset-x-0 bottom-0 h-32 bg-gradient-to-t from-black/85 via-black/35 to-transparent"
|
||||
/>
|
||||
<div className="pointer-events-none absolute inset-x-3 bottom-3 z-10">
|
||||
<div className="flex items-end gap-3 rounded-2xl border border-white/15 bg-black/55 p-3 text-white shadow-xl backdrop-blur-xl">
|
||||
<div className="min-w-0 flex-1">
|
||||
<h3 className="text-sm font-semibold leading-snug text-white">
|
||||
{talk.title}
|
||||
</h3>
|
||||
<p className="mt-0.5 truncate text-xs text-white/65">
|
||||
{talk.description}
|
||||
</p>
|
||||
</div>
|
||||
<a
|
||||
href={talk.url}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
aria-label={`Watch ${talk.title} on YouTube`}
|
||||
className="pointer-events-auto inline-flex min-h-9 shrink-0 items-center gap-1.5 rounded-xl px-2.5 text-xs font-semibold text-white no-underline outline-none transition-colors hover:bg-white/10 focus-visible:ring-2 focus-visible:ring-white/70"
|
||||
>
|
||||
Watch
|
||||
<FontAwesomeIcon
|
||||
className="text-[10px]"
|
||||
icon={faArrowUpRightFromSquare}
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
</Accordion.Body>
|
||||
</Accordion.Panel>
|
||||
</Accordion.Item>
|
||||
))}
|
||||
</Accordion>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -3,14 +3,18 @@ import LoadingState from "@/components/loading-state";
|
||||
import { Tutorials } from "@/util/tutorials";
|
||||
import { PREBUILD_VERSION } from "@/util/__generated__/prebuild-version";
|
||||
import { fetchTutorials as fetchTutorialsContent } from "@/util/content-fetchers";
|
||||
import { faSearch } from "@fortawesome/free-solid-svg-icons";
|
||||
import {
|
||||
faChevronRight,
|
||||
faGraduationCap,
|
||||
faSearch,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
ListBox,
|
||||
ScrollShadow,
|
||||
SearchField,
|
||||
Separator,
|
||||
} from "@heroui/react";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import Fuse from "fuse.js";
|
||||
@@ -70,13 +74,14 @@ const TutorialsIndexPage: NextPage = () => {
|
||||
}, [name, tutorials, visibleTutorials]);
|
||||
|
||||
const listboxClasses =
|
||||
"p-0 gap-0 divide-y divide-separator bg-surface overflow-visible rounded-lg shadow-sm";
|
||||
"flex flex-col gap-1 overflow-visible bg-transparent p-0";
|
||||
|
||||
const renderFilterInput = (className?: string) => (
|
||||
<SearchField
|
||||
aria-label="Filter tutorials"
|
||||
className={className}
|
||||
fullWidth
|
||||
variant="secondary"
|
||||
value={filterValue}
|
||||
onChange={setFilterValue}
|
||||
>
|
||||
@@ -99,87 +104,146 @@ const TutorialsIndexPage: NextPage = () => {
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>Sliver Tutorial: {name}</title>
|
||||
<title>{name ? `${name} · Sliver Tutorials` : "Sliver Tutorials"}</title>
|
||||
</Head>
|
||||
<div className="px-4 pt-4 lg:hidden">
|
||||
<label
|
||||
htmlFor="tutorials-mobile-selector"
|
||||
className="block text-sm font-medium text-foreground"
|
||||
>
|
||||
Select a tutorial
|
||||
</label>
|
||||
<div className="mt-2">{renderFilterInput()}</div>
|
||||
<select
|
||||
id="tutorials-mobile-selector"
|
||||
className="mt-3 w-full rounded-lg border border-separator bg-surface p-2 text-sm"
|
||||
value={name}
|
||||
onChange={(event) => {
|
||||
const selectedName = event.target.value;
|
||||
router.push({
|
||||
pathname: "/tutorials",
|
||||
query: selectedName ? { name: selectedName } : undefined,
|
||||
});
|
||||
}}
|
||||
>
|
||||
<option value="">Browse tutorials…</option>
|
||||
{mobileTutorials.map((tutorial) => (
|
||||
<option key={tutorial.name} value={tutorial.name}>
|
||||
{tutorial.name}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 gap-6 lg:grid-cols-12 lg:gap-8">
|
||||
<aside className="hidden lg:block lg:col-span-3">
|
||||
<div className="sticky top-16 ml-4 flex flex-col gap-3">
|
||||
{renderFilterInput("mt-2")}
|
||||
<ScrollShadow className="max-h-[calc(100vh-6rem)] sliver-scrollbar overflow-y-auto pr-1 rounded-lg">
|
||||
<ListBox
|
||||
aria-label="Toolbox Menu"
|
||||
className={listboxClasses}
|
||||
onAction={(key) => {
|
||||
router.push({
|
||||
pathname: "/tutorials",
|
||||
query: { name: String(key) },
|
||||
});
|
||||
}}
|
||||
>
|
||||
{visibleTutorials.map((tutorial) => (
|
||||
<ListBox.Item
|
||||
key={tutorial.name}
|
||||
id={tutorial.name}
|
||||
textValue={tutorial.name}
|
||||
className="h-12 rounded-none px-3 first:rounded-t-lg last:rounded-b-lg"
|
||||
>
|
||||
{tutorial.name}
|
||||
</ListBox.Item>
|
||||
))}
|
||||
</ListBox>
|
||||
</ScrollShadow>
|
||||
<div className="mx-auto w-full max-w-[90rem] px-4 pt-8 sm:px-6 lg:px-8 lg:pt-10">
|
||||
<div className="mb-8 lg:hidden">
|
||||
<div className="flex items-center gap-3">
|
||||
<span className="flex size-9 items-center justify-center rounded-2xl bg-surface-secondary text-accent">
|
||||
<FontAwesomeIcon icon={faGraduationCap} />
|
||||
</span>
|
||||
<div>
|
||||
<p className="text-sm font-medium text-foreground">Tutorials</p>
|
||||
<p className="text-xs text-muted">Follow a guided workflow</p>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
<div className="px-4 pb-8 lg:col-span-9 lg:px-8">
|
||||
{name !== "" ? (
|
||||
<Card className="mt-2">
|
||||
<Card.Header>
|
||||
<span className="text-3xl">{name}</span>
|
||||
</Card.Header>
|
||||
<Separator />
|
||||
<Card.Content>
|
||||
<div className="mt-5">{renderFilterInput()}</div>
|
||||
<label
|
||||
htmlFor="tutorials-mobile-selector"
|
||||
className="mt-4 block text-sm font-medium text-foreground"
|
||||
>
|
||||
Tutorial
|
||||
</label>
|
||||
<select
|
||||
id="tutorials-mobile-selector"
|
||||
className="mt-2 w-full rounded-2xl border border-transparent bg-surface-secondary px-3 py-2.5 text-sm text-foreground outline-none focus:border-accent"
|
||||
value={name}
|
||||
onChange={(event) => {
|
||||
const selectedName = event.target.value;
|
||||
router.push({
|
||||
pathname: "/tutorials",
|
||||
query: selectedName ? { name: selectedName } : undefined,
|
||||
});
|
||||
}}
|
||||
>
|
||||
<option value="">Browse tutorials…</option>
|
||||
{mobileTutorials.map((tutorial) => (
|
||||
<option key={tutorial.name} value={tutorial.name}>
|
||||
{tutorial.name}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div className="grid min-w-0 grid-cols-1 gap-8 lg:grid-cols-[17rem_minmax(0,1fr)] lg:gap-10">
|
||||
<aside className="sliver-sticky-sidebar hidden border-r border-separator/70 pr-6 lg:block">
|
||||
<div className="flex h-full min-h-0 flex-col gap-5">
|
||||
<div className="flex items-center gap-3 px-1">
|
||||
<span className="flex size-9 items-center justify-center rounded-2xl bg-surface-secondary text-accent">
|
||||
<FontAwesomeIcon icon={faGraduationCap} />
|
||||
</span>
|
||||
<div>
|
||||
<p className="text-sm font-medium text-foreground">Tutorials</p>
|
||||
<p className="text-xs text-muted">
|
||||
{tutorials.tutorials.length} chapters
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{renderFilterInput()}
|
||||
<ScrollShadow className="sliver-scrollbar min-h-0 flex-1 overscroll-contain overflow-y-auto pr-2">
|
||||
<ListBox
|
||||
aria-label="Tutorials"
|
||||
className={listboxClasses}
|
||||
selectedKeys={name ? [name] : []}
|
||||
selectionMode="single"
|
||||
>
|
||||
{visibleTutorials.map((tutorial) => (
|
||||
<ListBox.Item
|
||||
key={tutorial.name}
|
||||
id={tutorial.name}
|
||||
href={`/tutorials/?name=${encodeURIComponent(tutorial.name)}`}
|
||||
textValue={tutorial.name}
|
||||
className={`min-h-10 rounded-xl px-3 py-2 text-sm ${
|
||||
tutorial.name === name
|
||||
? "bg-surface font-medium text-foreground shadow-surface"
|
||||
: "text-muted"
|
||||
}`}
|
||||
>
|
||||
{tutorial.name}
|
||||
</ListBox.Item>
|
||||
))}
|
||||
</ListBox>
|
||||
</ScrollShadow>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<div
|
||||
key={name || "tutorials-overview"}
|
||||
className="min-w-0 pb-16 lg:pr-4"
|
||||
>
|
||||
{name !== "" ? (
|
||||
<article className="mx-auto w-full max-w-4xl">
|
||||
<header className="mb-8 border-b border-separator/70 pb-8">
|
||||
<p className="text-sm font-medium text-accent">Tutorial</p>
|
||||
<h1 className="mt-2 text-balance text-4xl font-semibold tracking-tight text-foreground sm:text-5xl">
|
||||
{name}
|
||||
</h1>
|
||||
</header>
|
||||
<MarkdownViewer
|
||||
key={name}
|
||||
markdown={markdown || ""}
|
||||
demoteTopLevelHeading
|
||||
/>
|
||||
</Card.Content>
|
||||
</Card>
|
||||
) : (
|
||||
<div className="mt-8 text-center text-2xl text-foreground/90">
|
||||
Welcome to the Sliver Tutorials!
|
||||
<div className="mt-2 text-xl text-muted">
|
||||
Please select a chapter
|
||||
</article>
|
||||
) : (
|
||||
<div className="mx-auto w-full max-w-5xl pt-4 lg:pt-8">
|
||||
<h1 className="text-sm font-medium text-accent">
|
||||
Guided learning
|
||||
</h1>
|
||||
<p className="mt-4 max-w-2xl text-lg leading-8 text-muted">
|
||||
Follow practical walkthroughs covering setup, sessions,
|
||||
staging, pivots, scripting, and post-exploitation workflows.
|
||||
</p>
|
||||
|
||||
<div className="mt-10 grid gap-4 sm:grid-cols-2">
|
||||
{tutorials.tutorials.slice(0, 6).map((tutorial) => (
|
||||
<Card key={tutorial.name} className="h-full">
|
||||
<Card.Header>
|
||||
<Card.Title>{tutorial.name}</Card.Title>
|
||||
<Card.Description>
|
||||
Continue through this guided Sliver workflow.
|
||||
</Card.Description>
|
||||
</Card.Header>
|
||||
<Card.Footer className="mt-auto">
|
||||
<Button
|
||||
variant="ghost"
|
||||
onPress={() => {
|
||||
router.push({
|
||||
pathname: "/tutorials",
|
||||
query: { name: tutorial.name },
|
||||
});
|
||||
}}
|
||||
>
|
||||
Start tutorial
|
||||
<FontAwesomeIcon icon={faChevronRight} />
|
||||
</Button>
|
||||
</Card.Footer>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
|
||||
@@ -6,14 +6,39 @@
|
||||
:root {
|
||||
--font-mono: "Fira Code", ui-monospace, SFMono-Regular, Menlo, Monaco,
|
||||
Consolas, "Liberation Mono", "Courier New", monospace;
|
||||
--sliver-navbar-height: 4rem;
|
||||
--sliver-footer-height: 4.75rem;
|
||||
}
|
||||
|
||||
/*
|
||||
Keep html as the single scrolling element. Setting overflow on both html
|
||||
and body breaks sticky sidebar behavior on docs/tutorial pages.
|
||||
*/
|
||||
/* Keep html as the single page scroller so content can pass beneath the shell. */
|
||||
html {
|
||||
overflow-y: scroll;
|
||||
scroll-padding-top: calc(var(--sliver-navbar-height) + 1.5rem);
|
||||
scroll-padding-bottom: calc(
|
||||
var(--sliver-footer-height) + env(safe-area-inset-bottom)
|
||||
);
|
||||
}
|
||||
|
||||
body {
|
||||
min-height: 100dvh;
|
||||
background:
|
||||
radial-gradient(circle at 12% -10%, color-mix(in oklab, var(--accent) 12%, transparent), transparent 28rem),
|
||||
radial-gradient(circle at 88% 4%, color-mix(in oklab, var(--surface-tertiary) 55%, transparent), transparent 26rem),
|
||||
var(--background);
|
||||
}
|
||||
|
||||
.sliver-page-content {
|
||||
padding-bottom: calc(
|
||||
var(--sliver-footer-height) + env(safe-area-inset-bottom)
|
||||
);
|
||||
}
|
||||
|
||||
.sliver-fixed-footer {
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
}
|
||||
|
||||
::selection {
|
||||
background: color-mix(in oklab, var(--accent) 32%, transparent);
|
||||
}
|
||||
|
||||
/* Fallback for engines that do not support scrollbar-gutter. */
|
||||
@@ -31,6 +56,22 @@ html {
|
||||
html {
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.sliver-sticky-sidebar {
|
||||
position: sticky;
|
||||
top: calc(var(--sliver-navbar-height) + 2.5rem);
|
||||
align-self: start;
|
||||
height: calc(
|
||||
100dvh - var(--sliver-navbar-height) - var(--sliver-footer-height) -
|
||||
env(safe-area-inset-bottom) - 3.5rem
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
:root {
|
||||
--sliver-footer-height: 3.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
code,
|
||||
@@ -44,7 +85,7 @@ pre {
|
||||
|
||||
.sliver-scrollbar {
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: rgba(148, 163, 184, 0.7) transparent;
|
||||
scrollbar-color: color-mix(in oklab, var(--muted) 58%, transparent) transparent;
|
||||
scrollbar-gutter: stable;
|
||||
}
|
||||
|
||||
@@ -57,33 +98,35 @@ pre {
|
||||
}
|
||||
|
||||
.sliver-scrollbar::-webkit-scrollbar-thumb {
|
||||
background-color: rgba(148, 163, 184, 0.7);
|
||||
background-color: color-mix(in oklab, var(--muted) 58%, transparent);
|
||||
border-radius: 9999px;
|
||||
border: 2px solid transparent;
|
||||
background-clip: content-box;
|
||||
}
|
||||
|
||||
.sliver-navbar-glass {
|
||||
width: 100%;
|
||||
border-bottom: 1px solid var(--separator);
|
||||
background-color: color-mix(in oklab, var(--surface) 72%, transparent);
|
||||
-webkit-backdrop-filter: blur(18px) saturate(1.18);
|
||||
backdrop-filter: blur(18px) saturate(1.18);
|
||||
.sliver-grid-surface {
|
||||
background-image:
|
||||
linear-gradient(color-mix(in oklab, var(--separator) 35%, transparent) 1px, transparent 1px),
|
||||
linear-gradient(90deg, color-mix(in oklab, var(--separator) 35%, transparent) 1px, transparent 1px);
|
||||
background-size: 32px 32px;
|
||||
mask-image: linear-gradient(to bottom, black, transparent 92%);
|
||||
}
|
||||
|
||||
.sliver-armory-ghost {
|
||||
--button-bg: transparent;
|
||||
--button-bg-hover: rgb(109 40 217 / 0.16);
|
||||
--button-bg-pressed: rgb(109 40 217 / 0.24);
|
||||
--button-fg: #a78bfa;
|
||||
.sliver-terminal-frame .ap-wrapper {
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
|
||||
.dark .sliver-scrollbar {
|
||||
scrollbar-color: rgba(79, 97, 125, 0.8) transparent;
|
||||
.sliver-asciinema-bottom-aligned .ap-wrapper {
|
||||
align-items: flex-end;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.dark .sliver-scrollbar::-webkit-scrollbar-thumb {
|
||||
background-color: rgba(79, 97, 125, 0.8);
|
||||
.sliver-terminal-frame .asciinema-player {
|
||||
background: #111315;
|
||||
}
|
||||
|
||||
.sliver-asciinema-controls-hidden .ap-control-bar {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.asciinema-player {
|
||||
@@ -94,3 +137,19 @@ pre {
|
||||
.asciinema-player .asciinema-terminal {
|
||||
max-width: 100% !important;
|
||||
}
|
||||
|
||||
.markdown-body {
|
||||
color: var(--foreground);
|
||||
}
|
||||
|
||||
.markdown-body :where(h2, h3, h4) {
|
||||
scroll-margin-top: calc(var(--sliver-navbar-height) + 1.5rem);
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
scroll-behavior: auto !important;
|
||||
}
|
||||
}
|
||||
@@ -367,6 +367,13 @@ try {
|
||||
}
|
||||
|
||||
if (-not $SkipGenerate) {
|
||||
# The package tests above no longer need their Go build cache. Reclaim it
|
||||
# before the cross-platform generation matrix starts so long CI runs do
|
||||
# not exhaust the runner's disk while retaining the implant compiler cache.
|
||||
Invoke-TestStep -Name "clean Go build cache" -Action {
|
||||
Invoke-ExternalCommand -FilePath "go" -Arguments @("clean", "-cache")
|
||||
}
|
||||
|
||||
$generateGoMaxProcs = if ($env:SLIVER_GENERATE_GOMAXPROCS) { $env:SLIVER_GENERATE_GOMAXPROCS } else { "2" }
|
||||
$generateGoP = if ($env:SLIVER_GENERATE_GO_P) { $env:SLIVER_GENERATE_GO_P } else { "1" }
|
||||
$generateTestParallel = if ($env:SLIVER_GENERATE_TEST_PARALLEL) { $env:SLIVER_GENERATE_TEST_PARALLEL } else { "1" }
|
||||
|
||||
@@ -234,6 +234,10 @@ fi
|
||||
|
||||
## Server generate
|
||||
if [ "$SKIP_GENERATE" -eq 0 ]; then
|
||||
# The package tests above no longer need their Go build cache. Reclaim it
|
||||
# before the cross-platform generation matrix starts so long CI runs do not
|
||||
# exhaust the runner's disk while retaining the implant compiler cache.
|
||||
run_test_cmd "clean Go build cache" go clean -cache || exit 1
|
||||
export GOPROXY=off
|
||||
# Generate tests are memory intensive (garble/c-shared cross-builds). Keep
|
||||
# parallelism conservative by default to avoid OOM kills on smaller systems.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module github.com/bishopfox/sliver
|
||||
|
||||
go 1.25.8
|
||||
go 1.26.6
|
||||
|
||||
replace github.com/rsteube/carapace v0.36.3 => github.com/reeflective/carapace v0.46.3-0.20231214181515-27e49f3c3b69
|
||||
|
||||
@@ -10,9 +10,9 @@ replace github.com/reeflective/console => github.com/moloch--/console v0.0.0-202
|
||||
|
||||
require (
|
||||
charm.land/bubbles/v2 v2.0.0
|
||||
charm.land/glamour/v2 v2.0.0
|
||||
charm.land/glamour/v2 v2.0.1
|
||||
charm.land/huh/v2 v2.0.3
|
||||
charm.land/lipgloss/v2 v2.0.2
|
||||
charm.land/lipgloss/v2 v2.0.4
|
||||
filippo.io/age v1.3.1
|
||||
github.com/Binject/binjection v0.0.0-20210701074423-605d46e35deb
|
||||
github.com/Binject/debug v0.0.0-20230508195519-26db73212a7a
|
||||
@@ -39,7 +39,6 @@ require (
|
||||
github.com/mattn/go-sqlite3 v1.14.32
|
||||
github.com/miekg/dns v1.1.70
|
||||
github.com/moloch--/asciicast v0.1.1
|
||||
github.com/moloch--/memmod v0.0.0-20230225130813-fd77d905589e
|
||||
github.com/moloch--/sgn v0.0.5
|
||||
github.com/ncruces/go-sqlite3 v0.30.4
|
||||
github.com/nikoksr/notify v1.5.0
|
||||
@@ -50,6 +49,7 @@ require (
|
||||
github.com/sirupsen/logrus v1.9.4
|
||||
github.com/sliverarmory/beignet v0.0.3
|
||||
github.com/sliverarmory/malasada v0.0.3
|
||||
github.com/sliverarmory/reflektor v0.0.2
|
||||
github.com/sliverarmory/wasm-donut v0.0.3
|
||||
github.com/spf13/cobra v1.10.2
|
||||
github.com/spf13/pflag v1.0.10
|
||||
@@ -59,22 +59,23 @@ require (
|
||||
github.com/ulikunitz/xz v0.5.15
|
||||
github.com/xlab/treeprint v1.2.0
|
||||
github.com/yiya1989/sshkrb5 v0.0.1
|
||||
golang.org/x/crypto v0.50.0
|
||||
golang.org/x/crypto v0.53.0
|
||||
golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa
|
||||
golang.org/x/mod v0.35.0
|
||||
golang.org/x/net v0.53.0
|
||||
golang.org/x/sys v0.43.0
|
||||
golang.org/x/term v0.42.0
|
||||
golang.org/x/text v0.37.0
|
||||
golang.org/x/mod v0.37.0
|
||||
golang.org/x/net v0.56.0
|
||||
golang.org/x/sys v0.46.0
|
||||
golang.org/x/term v0.44.0
|
||||
golang.org/x/text v0.40.0
|
||||
golang.zx2c4.com/wireguard v0.0.0-20250521234502-f333402bd9cb
|
||||
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20241231184526-a9ab2273dd10
|
||||
google.golang.org/api v0.269.0
|
||||
google.golang.org/grpc v1.79.3
|
||||
google.golang.org/grpc v1.82.1
|
||||
google.golang.org/protobuf v1.36.11
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
||||
gorm.io/driver/mysql v1.6.0
|
||||
gorm.io/driver/postgres v1.6.0
|
||||
gorm.io/driver/postgres v1.6.2
|
||||
gorm.io/driver/sqlite v1.6.0
|
||||
gorm.io/gorm v1.31.0
|
||||
gorm.io/gorm v1.31.2
|
||||
gvisor.dev/gvisor v0.0.0-20250503011706-39ed1f5ac29c
|
||||
maunium.net/go/mautrix v0.26.0
|
||||
modernc.org/sqlite v1.39.0
|
||||
@@ -93,7 +94,7 @@ require (
|
||||
cloud.google.com/go/storage v1.60.0 // indirect
|
||||
filippo.io/hpke v0.4.0 // indirect
|
||||
firebase.google.com/go/v4 v4.18.0 // indirect
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.31.0 // indirect
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.32.0 // indirect
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.55.0 // indirect
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.55.0 // indirect
|
||||
github.com/MicahParks/keyfunc v1.9.0 // indirect
|
||||
@@ -144,7 +145,7 @@ require (
|
||||
github.com/fatih/structs v1.1.0 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/fsnotify/fsnotify v1.9.0 // indirect
|
||||
github.com/go-jose/go-jose/v4 v4.1.3 // indirect
|
||||
github.com/go-jose/go-jose/v4 v4.1.4 // indirect
|
||||
github.com/go-lark/lark v1.16.0 // indirect
|
||||
github.com/go-logr/logr v1.4.3 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
@@ -206,17 +207,17 @@ require (
|
||||
github.com/yuin/goldmark-emoji v1.0.5 // indirect
|
||||
go.mau.fi/util v0.9.3 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.40.0 // indirect
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.43.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.65.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0 // indirect
|
||||
go.opentelemetry.io/otel v1.40.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.40.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.40.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk/metric v1.40.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.40.0 // indirect
|
||||
go.opentelemetry.io/otel v1.43.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.43.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.43.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk/metric v1.43.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.43.0 // indirect
|
||||
google.golang.org/appengine/v2 v2.0.6 // indirect
|
||||
google.golang.org/genproto v0.0.0-20260226221140-a57be14db171 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20260226221140-a57be14db171 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20260414002931-afd174a4e478 // indirect
|
||||
gopkg.in/go-playground/validator.v9 v9.31.0 // indirect
|
||||
)
|
||||
|
||||
@@ -239,8 +240,8 @@ require (
|
||||
github.com/carapace-sh/carapace v1.11.0
|
||||
github.com/carapace-sh/carapace-shlex v1.1.1 // indirect
|
||||
github.com/catppuccin/go v0.3.0 // indirect
|
||||
github.com/charmbracelet/colorprofile v0.4.2
|
||||
github.com/charmbracelet/x/ansi v0.11.6
|
||||
github.com/charmbracelet/colorprofile v0.4.3
|
||||
github.com/charmbracelet/x/ansi v0.11.7
|
||||
github.com/charmbracelet/x/exp/charmtone v0.0.0-20260109001716-2fbdffcb221f
|
||||
github.com/charmbracelet/x/exp/strings v0.0.0-20240722160745-212f7b056ed0 // indirect
|
||||
github.com/charmbracelet/x/term v0.2.2 // indirect
|
||||
@@ -272,7 +273,7 @@ require (
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
||||
github.com/jackc/pgx/v5 v5.9.2 // indirect
|
||||
github.com/jackc/pgx/v5 v5.10.0 // indirect
|
||||
github.com/jackc/puddle/v2 v2.2.2 // indirect
|
||||
github.com/jcmturner/gofork v1.7.6 // indirect
|
||||
github.com/jezek/xgb v1.1.1 // indirect
|
||||
@@ -280,12 +281,12 @@ require (
|
||||
github.com/jinzhu/now v1.1.5 // indirect
|
||||
github.com/jsimonetti/rtnetlink v1.4.2 // indirect
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
|
||||
github.com/lucasb-eyer/go-colorful v1.3.0
|
||||
github.com/lucasb-eyer/go-colorful v1.4.0
|
||||
github.com/lxn/win v0.0.0-20210218163916-a377121e959e // indirect
|
||||
github.com/mark3labs/mcp-go v0.45.0
|
||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.20 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.23 // indirect
|
||||
github.com/mdlayher/netlink v1.8.0 // indirect
|
||||
github.com/mdlayher/socket v0.5.1 // indirect
|
||||
github.com/mitchellh/go-ps v1.0.0 // indirect
|
||||
@@ -315,12 +316,12 @@ require (
|
||||
go4.org/mem v0.0.0-20240501181205-ae6ca9944745 // indirect
|
||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect
|
||||
golang.org/x/oauth2 v0.36.0 // indirect
|
||||
golang.org/x/sync v0.20.0 // indirect
|
||||
golang.org/x/sync v0.22.0 // indirect
|
||||
golang.org/x/time v0.14.0
|
||||
golang.org/x/tools v0.44.0 // indirect
|
||||
golang.org/x/tools v0.47.0 // indirect
|
||||
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
|
||||
golang.zx2c4.com/wireguard/windows v0.5.3 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260316180232-0b37fe3546d5 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478 // indirect
|
||||
gopkg.in/jcmturner/aescts.v1 v1.0.1 // indirect
|
||||
gopkg.in/jcmturner/dnsutils.v1 v1.0.1 // indirect
|
||||
gopkg.in/jcmturner/goidentity.v3 v3.0.0 // indirect
|
||||
|
||||
@@ -8,12 +8,12 @@ charm.land/bubbles/v2 v2.0.0 h1:tE3eK/pHjmtrDiRdoC9uGNLgpopOd8fjhEe31B/ai5s=
|
||||
charm.land/bubbles/v2 v2.0.0/go.mod h1:rCHoleP2XhU8um45NTuOWBPNVHxnkXKTiZqcclL/qOI=
|
||||
charm.land/bubbletea/v2 v2.0.2 h1:4CRtRnuZOdFDTWSff9r8QFt/9+z6Emubz3aDMnf/dx0=
|
||||
charm.land/bubbletea/v2 v2.0.2/go.mod h1:3LRff2U4WIYXy7MTxfbAQ+AdfM3D8Xuvz2wbsOD9OHQ=
|
||||
charm.land/glamour/v2 v2.0.0 h1:IDBoqLEy7Hdpb9VOXN+khLP/XSxtJy1VsHuW/yF87+U=
|
||||
charm.land/glamour/v2 v2.0.0/go.mod h1:kjq9WB0s8vuUYZNYey2jp4Lgd9f4cKdzAw88FZtpj/w=
|
||||
charm.land/glamour/v2 v2.0.1 h1:xl+r00A4aJWU0z8fgwKd9fQQ4rsphqGUzuEiXZP5n+c=
|
||||
charm.land/glamour/v2 v2.0.1/go.mod h1:jo9z8XqVKPeEFMVdvCRLGk++RyJ3CdUwgNr7EvXLw3k=
|
||||
charm.land/huh/v2 v2.0.3 h1:2cJsMqEPwSywGHvdlKsJyQKPtSJLVnFKyFbsYZTlLkU=
|
||||
charm.land/huh/v2 v2.0.3/go.mod h1:93eEveeeqn47MwiC3tf+2atZ2l7Is88rAtmZNZ8x9Wc=
|
||||
charm.land/lipgloss/v2 v2.0.2 h1:xFolbF8JdpNkM2cEPTfXEcW1p6NRzOWTSamRfYEw8cs=
|
||||
charm.land/lipgloss/v2 v2.0.2/go.mod h1:KjPle2Qd3YmvP1KL5OMHiHysGcNwq6u83MUjYkFvEkM=
|
||||
charm.land/lipgloss/v2 v2.0.4 h1:lcPeVtcp23SNra7lHy8iYE4UC2aIipVQ47sbGyyxR5Q=
|
||||
charm.land/lipgloss/v2 v2.0.4/go.mod h1:0653x8epbZSzdDfO/XPS1a/uYPOBeSsCssOpJOqDzik=
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.123.0 h1:2NAUJwPR47q+E35uaJeYoNhuNEM9kM8SjgRgdeOJUSE=
|
||||
cloud.google.com/go v0.123.0/go.mod h1:xBoMV08QcqUGuPW65Qfm1o9Y4zKZBpGS+7bImXLTAZU=
|
||||
@@ -60,8 +60,8 @@ github.com/Binject/universal v0.0.0-20220519011857-bea739e758c0/go.mod h1:J3XDRl
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c h1:pxW6RcqyfI9/kWtOwnv/G+AzdKuy2ZrqINhenH4HyNs=
|
||||
github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.31.0 h1:DHa2U07rk8syqvCge0QIGMCE1WxGj9njT44GH7zNJLQ=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.31.0/go.mod h1:P4WPRUkOhJC13W//jWpyfJNDAIpvRbAUIYLX/4jtlE0=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.32.0 h1:rIkQfkCOVKc1OiRCNcSDD8ml5RJlZbH/Xsq7lbpynwc=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.32.0/go.mod h1:RD2SsorTmYhF6HkTmDw7KmPYQk8OBYwTkuasChwv7R4=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.55.0 h1:UnDZ/zFfG1JhH/DqxIZYU/1CUAlTUScoXD/LcM2Ykk8=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.55.0/go.mod h1:IA1C1U7jO/ENqm/vhi7V9YYpBsp+IMyqNrEN94N7tVc=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.55.0 h1:7t/qx5Ost0s0wbA/VDrByOooURhp+ikYwv20i9Y07TQ=
|
||||
@@ -182,14 +182,14 @@ github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA
|
||||
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/charmbracelet/colorprofile v0.4.2 h1:BdSNuMjRbotnxHSfxy+PCSa4xAmz7szw70ktAtWRYrY=
|
||||
github.com/charmbracelet/colorprofile v0.4.2/go.mod h1:0rTi81QpwDElInthtrQ6Ni7cG0sDtwAd4C4le060fT8=
|
||||
github.com/charmbracelet/colorprofile v0.4.3 h1:QPa1IWkYI+AOB+fE+mg/5/4HRMZcaXex9t5KX76i20Q=
|
||||
github.com/charmbracelet/colorprofile v0.4.3/go.mod h1:/zT4BhpD5aGFpqQQqw7a+VtHCzu+zrQtt1zhMt9mR4Q=
|
||||
github.com/charmbracelet/harmonica v0.2.0 h1:8NxJWRWg/bzKqqEaaeFNipOu77YR5t8aSwG4pgaUBiQ=
|
||||
github.com/charmbracelet/harmonica v0.2.0/go.mod h1:KSri/1RMQOZLbw7AHqgcBycp8pgJnQMYYT8QZRqZ1Ao=
|
||||
github.com/charmbracelet/ultraviolet v0.0.0-20260205113103-524a6607adb8 h1:eyFRbAmexyt43hVfeyBofiGSEmJ7krjLOYt/9CF5NKA=
|
||||
github.com/charmbracelet/ultraviolet v0.0.0-20260205113103-524a6607adb8/go.mod h1:SQpCTRNBtzJkwku5ye4S3HEuthAlGy2n9VXZnWkEW98=
|
||||
github.com/charmbracelet/x/ansi v0.11.6 h1:GhV21SiDz/45W9AnV2R61xZMRri5NlLnl6CVF7ihZW8=
|
||||
github.com/charmbracelet/x/ansi v0.11.6/go.mod h1:2JNYLgQUsyqaiLovhU2Rv/pb8r6ydXKS3NIttu3VGZQ=
|
||||
github.com/charmbracelet/x/ansi v0.11.7 h1:kzv1kJvjg2S3r9KHo8hDdHFQLEqn4RBCb39dAYC84jI=
|
||||
github.com/charmbracelet/x/ansi v0.11.7/go.mod h1:9qGpnAVYz+8ACONkZBUWPtL7lulP9No6p1epAihUZwQ=
|
||||
github.com/charmbracelet/x/conpty v0.1.1 h1:s1bUxjoi7EpqiXysVtC+a8RrvPPNcNvAjfi4jxsAuEs=
|
||||
github.com/charmbracelet/x/conpty v0.1.1/go.mod h1:OmtR77VODEFbiTzGE9G1XiRJAga6011PIm4u5fTNZpk=
|
||||
github.com/charmbracelet/x/errors v0.0.0-20240508181413-e8d8b6e2de86 h1:JSt3B+U9iqk37QUU2Rvb6DSBYRLtWqFqfxf8l5hOZUA=
|
||||
@@ -313,8 +313,8 @@ github.com/glebarez/sqlite v1.11.0 h1:wSG0irqzP6VurnMEpFGer5Li19RpIRi2qvQz++w0GM
|
||||
github.com/glebarez/sqlite v1.11.0/go.mod h1:h8/o8j5wiAsqSPoWELDUdJXhjAhsVliSn7bWZjOhrgQ=
|
||||
github.com/go-chi/chi/v5 v5.2.3 h1:WQIt9uxdsAbgIYgid+BpYc+liqQZGMHRaUwp0JUcvdE=
|
||||
github.com/go-chi/chi/v5 v5.2.3/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
|
||||
github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs=
|
||||
github.com/go-jose/go-jose/v4 v4.1.3/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08=
|
||||
github.com/go-jose/go-jose/v4 v4.1.4 h1:moDMcTHmvE6Groj34emNPLs/qtYXRVcd6S7NHbHz3kA=
|
||||
github.com/go-jose/go-jose/v4 v4.1.4/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08=
|
||||
github.com/go-json-experiment/json v0.0.0-20251027170946-4849db3c2f7e h1:Lf/gRkoycfOBPa42vU2bbgPurFong6zXeFtPoxholzU=
|
||||
github.com/go-json-experiment/json v0.0.0-20251027170946-4849db3c2f7e/go.mod h1:uNVvRXArCGbZ508SxYYTC5v1JWoz2voff5pm25jU1Ok=
|
||||
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
|
||||
@@ -455,8 +455,8 @@ github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsI
|
||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||
github.com/jackc/pgx/v5 v5.9.2 h1:3ZhOzMWnR4yJ+RW1XImIPsD1aNSz4T4fyP7zlQb56hw=
|
||||
github.com/jackc/pgx/v5 v5.9.2/go.mod h1:mal1tBGAFfLHvZzaYh77YS/eC6IX9OWbRV1QIIM0Jn4=
|
||||
github.com/jackc/pgx/v5 v5.10.0 h1:VhSvgU2jSli8o3AqIEOTJr7rZwAEUVo4E4XhR94Zfr0=
|
||||
github.com/jackc/pgx/v5 v5.10.0/go.mod h1:mal1tBGAFfLHvZzaYh77YS/eC6IX9OWbRV1QIIM0Jn4=
|
||||
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
|
||||
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
||||
github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o=
|
||||
@@ -521,8 +521,8 @@ github.com/lesnuages/snitch v0.6.0 h1:vOao32MdYDHYDcTAq2CKszDh6Dn8Bv1Gmgc8uVh193
|
||||
github.com/lesnuages/snitch v0.6.0/go.mod h1:RfXlAVJYL7gUoZ9VMMon4LqrPiAjC8x62Ntbse4a4s0=
|
||||
github.com/line/line-bot-sdk-go v7.8.0+incompatible h1:Uf9/OxV0zCVfqyvwZPH8CrdiHXXmMRa/L91G3btQblQ=
|
||||
github.com/line/line-bot-sdk-go v7.8.0+incompatible/go.mod h1:0RjLjJEAU/3GIcHkC3av6O4jInAbt25nnZVmOFUgDBg=
|
||||
github.com/lucasb-eyer/go-colorful v1.3.0 h1:2/yBRLdWBZKrf7gB40FoiKfAWYQ0lqNcbuQwVHXptag=
|
||||
github.com/lucasb-eyer/go-colorful v1.3.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||
github.com/lucasb-eyer/go-colorful v1.4.0 h1:UtrWVfLdarDgc44HcS7pYloGHJUjHV/4FwW4TvVgFr4=
|
||||
github.com/lucasb-eyer/go-colorful v1.4.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||
github.com/lxn/win v0.0.0-20210218163916-a377121e959e h1:H+t6A/QJMbhCSEH5rAuRxh+CtW96g0Or0Fxa9IKr4uc=
|
||||
github.com/lxn/win v0.0.0-20210218163916-a377121e959e/go.mod h1:KxxjdtRkfNoYDCUP5ryK7XJJNTnpC8atvtmTheChOtk=
|
||||
github.com/mailgun/errors v0.4.0 h1:6LFBvod6VIW83CMIOT9sYNp28TCX0NejFPP4dSX++i8=
|
||||
@@ -543,8 +543,8 @@ github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-runewidth v0.0.20 h1:WcT52H91ZUAwy8+HUkdM3THM6gXqXuLJi9O3rjcQQaQ=
|
||||
github.com/mattn/go-runewidth v0.0.20/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
|
||||
github.com/mattn/go-runewidth v0.0.23 h1:7ykA0T0jkPpzSvMS5i9uoNn2Xy3R383f9HDx3RybWcw=
|
||||
github.com/mattn/go-runewidth v0.0.23/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
|
||||
github.com/mattn/go-sqlite3 v1.14.32 h1:JD12Ag3oLy1zQA+BNn74xRgaBbdhbNIDYvQUEuuErjs=
|
||||
github.com/mattn/go-sqlite3 v1.14.32/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||
github.com/mdlayher/genetlink v1.3.2 h1:KdrNKe+CTu+IbZnm/GVUMXSqBBLqcGpRDa0xkQy56gw=
|
||||
@@ -576,8 +576,6 @@ github.com/moloch--/console v0.0.0-20260129035459-883dcb25c701 h1:6caCgDZpovjvv+
|
||||
github.com/moloch--/console v0.0.0-20260129035459-883dcb25c701/go.mod h1:UdqyqqCSnPu3Zc8Q3kpDszrq1hcyBHsG17hlWlRJmWI=
|
||||
github.com/moloch--/go-keystone v0.0.2 h1:xThbYs45CSzoDUz5kBZxAyTPIpK3t5M7NB1x+NTTRL8=
|
||||
github.com/moloch--/go-keystone v0.0.2/go.mod h1:kpGRJpw9b7Eq3MluHrba+GPKZhSyDrvhLULSwH5nGGM=
|
||||
github.com/moloch--/memmod v0.0.0-20230225130813-fd77d905589e h1:IkFCPlAa0iTiLxck+NqAwBx8JDlnHYm4orOQBbs4BDQ=
|
||||
github.com/moloch--/memmod v0.0.0-20230225130813-fd77d905589e/go.mod h1:eYeI6cQ5YHhHt9i0BBW0zc1DaQnb4ZMXsSPuEV/V5Og=
|
||||
github.com/moloch--/readline v0.0.0-20260129035512-cb5b3e87d51a h1:Q69DxLWF+Z8oIjuNbeKC6Xygk8Z4heWzzO79Io1cEYA=
|
||||
github.com/moloch--/readline v0.0.0-20260129035512-cb5b3e87d51a/go.mod h1:CwNkh9BmFBBCSO6mdDaNWb34rOqQsI9eYbxyqvOEazY=
|
||||
github.com/moloch--/sgn v0.0.5 h1:92GFaRpe+353uhqzFiNKXKgmTiD4dBxnvb8gd4MaV/g=
|
||||
@@ -680,6 +678,8 @@ github.com/sliverarmory/beignet v0.0.3 h1:ssR6AK9lirVulHZhQMyMmVAi0FcFwWxlh9LwKC
|
||||
github.com/sliverarmory/beignet v0.0.3/go.mod h1:xXfTKBJqFBY/pakRFwJ+5+oGiSlg2CiCVUg/76kW1H4=
|
||||
github.com/sliverarmory/malasada v0.0.3 h1:b2KG2NhQVfBIIrbP8rGJwmdh7o8LH6NKYKH1DF4No1U=
|
||||
github.com/sliverarmory/malasada v0.0.3/go.mod h1:F96IgTOoX72FU995F+Jip0ni8Z5sXiYOwfmlRGobJkQ=
|
||||
github.com/sliverarmory/reflektor v0.0.2 h1:nrEEFXrYiYFLCqyMpOJpe4RsY0Pu3tc1CvwChsNoAq4=
|
||||
github.com/sliverarmory/reflektor v0.0.2/go.mod h1:Rw7qTWQQlCM3YTxxeuklFt3Q+kh1Ytlmzg5UVw1Nhkg=
|
||||
github.com/sliverarmory/wasm-donut v0.0.3 h1:sldbfAsz1YziULlhDKpU3DY/+/dAfv5gl26qSqHIpzE=
|
||||
github.com/sliverarmory/wasm-donut v0.0.3/go.mod h1:D6OLBZBfFm2Tk857vqGqFS9uUi4CXqnqHxKqtONllVk=
|
||||
github.com/sony/sonyflake v1.0.0 h1:MpU6Ro7tfXwgn2l5eluf9xQvQJDROTBImNCfRXn/YeM=
|
||||
@@ -806,24 +806,24 @@ go.mau.fi/util v0.9.3 h1:aqNF8KDIN8bFpFbybSk+mEBil7IHeBwlujfyTnvP0uU=
|
||||
go.mau.fi/util v0.9.3/go.mod h1:krWWfBM1jWTb5f8NCa2TLqWMQuM81X7TGQjhMjBeXmQ=
|
||||
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
||||
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.40.0 h1:Awaf8gmW99tZTOWqkLCOl6aw1/rxAWVlHsHIZ3fT2sA=
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.40.0/go.mod h1:99OY9ZCqyLkzJLTh5XhECpLRSxcZl+ZDKBEO+jMBFR4=
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.43.0 h1:62yY3dT7/ShwOxzA0RsKRgshBmfElKI4d/Myu2OxDFU=
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.43.0/go.mod h1:RyaZMFY7yi1kAs45S6mbFGz8O8rqB0dTY14uzvG4LCs=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.65.0 h1:XmiuHzgJt067+a6kwyAzkhXooYVv3/TOw9cM2VfJgUM=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.65.0/go.mod h1:KDgtbWKTQs4bM+VPUr6WlL9m/WXcmkCcBlIzqxPGzmI=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0 h1:7iP2uCb7sGddAr30RRS6xjKy7AZ2JtTOPA3oolgVSw8=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0/go.mod h1:c7hN3ddxs/z6q9xwvfLPk+UHlWRQyaeR1LdgfL/66l0=
|
||||
go.opentelemetry.io/otel v1.40.0 h1:oA5YeOcpRTXq6NN7frwmwFR0Cn3RhTVZvXsP4duvCms=
|
||||
go.opentelemetry.io/otel v1.40.0/go.mod h1:IMb+uXZUKkMXdPddhwAHm6UfOwJyh4ct1ybIlV14J0g=
|
||||
go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I=
|
||||
go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0=
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.39.0 h1:5gn2urDL/FBnK8OkCfD1j3/ER79rUuTYmCvlXBKeYL8=
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.39.0/go.mod h1:0fBG6ZJxhqByfFZDwSwpZGzJU671HkwpWaNe2t4VUPI=
|
||||
go.opentelemetry.io/otel/metric v1.40.0 h1:rcZe317KPftE2rstWIBitCdVp89A2HqjkxR3c11+p9g=
|
||||
go.opentelemetry.io/otel/metric v1.40.0/go.mod h1:ib/crwQH7N3r5kfiBZQbwrTge743UDc7DTFVZrrXnqc=
|
||||
go.opentelemetry.io/otel/sdk v1.40.0 h1:KHW/jUzgo6wsPh9At46+h4upjtccTmuZCFAc9OJ71f8=
|
||||
go.opentelemetry.io/otel/sdk v1.40.0/go.mod h1:Ph7EFdYvxq72Y8Li9q8KebuYUr2KoeyHx0DRMKrYBUE=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.40.0 h1:mtmdVqgQkeRxHgRv4qhyJduP3fYJRMX4AtAlbuWdCYw=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.40.0/go.mod h1:4Z2bGMf0KSK3uRjlczMOeMhKU2rhUqdWNoKcYrtcBPg=
|
||||
go.opentelemetry.io/otel/trace v1.40.0 h1:WA4etStDttCSYuhwvEa8OP8I5EWu24lkOzp+ZYblVjw=
|
||||
go.opentelemetry.io/otel/trace v1.40.0/go.mod h1:zeAhriXecNGP/s2SEG3+Y8X9ujcJOTqQ5RgdEJcawiA=
|
||||
go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM=
|
||||
go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY=
|
||||
go.opentelemetry.io/otel/sdk v1.43.0 h1:pi5mE86i5rTeLXqoF/hhiBtUNcrAGHLKQdhg4h4V9Dg=
|
||||
go.opentelemetry.io/otel/sdk v1.43.0/go.mod h1:P+IkVU3iWukmiit/Yf9AWvpyRDlUeBaRg6Y+C58QHzg=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.43.0 h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfCGLEo89fDkw=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A=
|
||||
go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A=
|
||||
go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
|
||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||
@@ -844,8 +844,8 @@ golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliY
|
||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||
golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI=
|
||||
golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q=
|
||||
golang.org/x/crypto v0.53.0 h1:QZ4Muo8THX6CizN2vPPd5fBGHyogrdK9fG4wLPFUsto=
|
||||
golang.org/x/crypto v0.53.0/go.mod h1:DNLU434OwVakk9PzuwV8w62mAJpRJL3vsgcfp4Qnsio=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa h1:Zt3DZoOFFYkKhDT3v7Lm9FDMEV06GpzjG2jrqW+QTE0=
|
||||
golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa/go.mod h1:K79w1Vqn7PoiZn+TkNpx3BUWUQksGO3JcVX6qIjytmA=
|
||||
@@ -864,8 +864,8 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.35.0 h1:Ww1D637e6Pg+Zb2KrWfHQUnH2dQRLBQyAtpr/haaJeM=
|
||||
golang.org/x/mod v0.35.0/go.mod h1:+GwiRhIInF8wPm+4AoT6L0FA1QWAad3OMdTRx4tFYlU=
|
||||
golang.org/x/mod v0.37.0 h1:vF1DjpVEshcIqoEaauuHebaLk1O1forxjxBaVn884JQ=
|
||||
golang.org/x/mod v0.37.0/go.mod h1:m8S8VeM9r4dzDwjrKO0a1sZP3YjeMamRRlD+fmR2Q/0=
|
||||
golang.org/x/net v0.0.0-20171115151908-9dfe39835686/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -887,8 +887,8 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA=
|
||||
golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs=
|
||||
golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o=
|
||||
golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs=
|
||||
golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q=
|
||||
@@ -905,8 +905,8 @@ golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
|
||||
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
||||
golang.org/x/sync v0.22.0 h1:SZjpbeLmrCk4xhRSZFNZW5gFUeCeFgjekvI/+gfScek=
|
||||
golang.org/x/sync v0.22.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -945,8 +945,8 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI=
|
||||
golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw=
|
||||
golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
@@ -956,8 +956,8 @@ golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
|
||||
golang.org/x/term v0.42.0 h1:UiKe+zDFmJobeJ5ggPwOshJIVt6/Ft0rcfrXZDLWAWY=
|
||||
golang.org/x/term v0.42.0/go.mod h1:Dq/D+snpsbazcBG5+F9Q1n2rXV8Ma+71xEjTRufARgY=
|
||||
golang.org/x/term v0.44.0 h1:0rLvDRCtNj0gZkyIXhCyOb2OAzEhLVqc4B+hrsBhrmc=
|
||||
golang.org/x/term v0.44.0/go.mod h1:7ze4MdzUzLXpSAoFP1H0bOI9aXDqveSvatT5vKcFh2Y=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
@@ -971,8 +971,8 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc=
|
||||
golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38=
|
||||
golang.org/x/text v0.40.0 h1:Ub2Z6/xjgF1WrYQz2nuITOEegKFtiIy+rieRJ5lHZKs=
|
||||
golang.org/x/text v0.40.0/go.mod h1:hpnzDAfGV753zIKo+wk3u1bVKCGPbrnF7+7LBF/UHVY=
|
||||
golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
|
||||
golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
@@ -989,8 +989,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||
golang.org/x/tools v0.44.0 h1:UP4ajHPIcuMjT1GqzDWRlalUEoY+uzoZKnhOjbIPD2c=
|
||||
golang.org/x/tools v0.44.0/go.mod h1:KA0AfVErSdxRZIsOVipbv3rQhVXTnlU6UhKxHd1seDI=
|
||||
golang.org/x/tools v0.47.0 h1:7Kn5x/d1svx/PzryTsqeoZN4TZwqeH5pGWjefhLi/1Q=
|
||||
golang.org/x/tools v0.47.0/go.mod h1:dFHnyTvFWY212G+h7ZY4Vsp/K3U4/7W9TyVaAul8uCA=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -1003,8 +1003,8 @@ golang.zx2c4.com/wireguard/wgctrl v0.0.0-20241231184526-a9ab2273dd10 h1:3GDAcqdI
|
||||
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20241231184526-a9ab2273dd10/go.mod h1:T97yPqesLiNrOYxkwmhMI0ZIlJDm+p0PMR8eRVeR5tQ=
|
||||
golang.zx2c4.com/wireguard/windows v0.5.3 h1:On6j2Rpn3OEMXqBq00QEDC7bWSZrPIHKIus8eIuExIE=
|
||||
golang.zx2c4.com/wireguard/windows v0.5.3/go.mod h1:9TEe8TJmtwyQebdFwAkEWOPr3prrtqm+REGFifP60hI=
|
||||
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||
gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=
|
||||
gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=
|
||||
google.golang.org/api v0.269.0 h1:qDrTOxKUQ/P0MveH6a7vZ+DNHxJQjtGm/uvdbdGXCQg=
|
||||
google.golang.org/api v0.269.0/go.mod h1:N8Wpcu23Tlccl0zSHEkcAZQKDLdquxK+l9r2LkwAauE=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
@@ -1016,17 +1016,17 @@ google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98
|
||||
google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20260226221140-a57be14db171 h1:RxhCsti413yL0IjU9dVvuTbCISo8gs3RW1jPMStck+4=
|
||||
google.golang.org/genproto v0.0.0-20260226221140-a57be14db171/go.mod h1:uhvzakVEqAuXU3TC2JCsxIRe5f77l+JySE3EqPoMyqM=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20260226221140-a57be14db171 h1:tu/dtnW1o3wfaxCOjSLn5IRX4YDcJrtlpzYkhHhGaC4=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20260226221140-a57be14db171/go.mod h1:M5krXqk4GhBKvB596udGL3UyjL4I1+cTbK0orROM9ng=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260316180232-0b37fe3546d5 h1:aJmi6DVGGIStN9Mobk/tZOOQUBbj0BPjZjjnOdoZKts=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260316180232-0b37fe3546d5/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20260414002931-afd174a4e478 h1:yQugLulqltosq0B/f8l4w9VryjV+N/5gcW0jQ3N8Qec=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20260414002931-afd174a4e478/go.mod h1:C6ADNqOxbgdUUeRTU+LCHDPB9ttAMCTff6auwCVa4uc=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478 h1:RmoJA1ujG+/lRGNfUnOMfhCy5EipVMyvUE+KNbPbTlw=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||
google.golang.org/grpc v1.79.3 h1:sybAEdRIEtvcD68Gx7dmnwjZKlyfuc61Dyo9pGXXkKE=
|
||||
google.golang.org/grpc v1.79.3/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||
google.golang.org/grpc v1.82.1 h1:NnAxzGRA0677vCa4BUkOAnO5+FfQqVl9iUXeD0IqcGE=
|
||||
google.golang.org/grpc v1.82.1/go.mod h1:yzTZ1TB1Z3SG+LIYaI+WiE8D5+PZ3ArnrSp8zF3+/ZA=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
@@ -1059,6 +1059,8 @@ gopkg.in/jcmturner/gokrb5.v7 v7.5.0 h1:a9tsXlIDD9SKxotJMK3niV7rPZAJeX2aD/0yg3qlI
|
||||
gopkg.in/jcmturner/gokrb5.v7 v7.5.0/go.mod h1:l8VISx+WGYp+Fp7KRbsiUuXTTOnxIc3Tuvyavf11/WM=
|
||||
gopkg.in/jcmturner/rpc.v1 v1.1.0 h1:QHIUxTX1ISuAv9dD2wJ9HWQVuWDX/Zc0PfeC2tjc4rU=
|
||||
gopkg.in/jcmturner/rpc.v1 v1.1.0/go.mod h1:YIdkC4XfD6GXbzje11McwsDuOlZQSb9W4vfLvuNnlv8=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
@@ -1073,12 +1075,12 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gorm.io/driver/mysql v1.6.0 h1:eNbLmNTpPpTOVZi8MMxCi2aaIm0ZpInbORNXDwyLGvg=
|
||||
gorm.io/driver/mysql v1.6.0/go.mod h1:D/oCC2GWK3M/dqoLxnOlaNKmXz8WNTfcS9y5ovaSqKo=
|
||||
gorm.io/driver/postgres v1.6.0 h1:2dxzU8xJ+ivvqTRph34QX+WrRaJlmfyPqXmoGVjMBa4=
|
||||
gorm.io/driver/postgres v1.6.0/go.mod h1:vUw0mrGgrTK+uPHEhAdV4sfFELrByKVGnaVRkXDhtWo=
|
||||
gorm.io/driver/postgres v1.6.2 h1:BvXQ/cNUg63q5TFNg672DmDcowZSFrNLkkA3Xe6GXq4=
|
||||
gorm.io/driver/postgres v1.6.2/go.mod h1:0c4fQA44XhOklXDkgtuKqysHCycTa5i9e3EIpDGCwXk=
|
||||
gorm.io/driver/sqlite v1.6.0 h1:WHRRrIiulaPiPFmDcod6prc4l2VGVWHz80KspNsxSfQ=
|
||||
gorm.io/driver/sqlite v1.6.0/go.mod h1:AO9V1qIQddBESngQUKWL9yoH93HIeA1X6V633rBwyT8=
|
||||
gorm.io/gorm v1.31.0 h1:0VlycGreVhK7RF/Bwt51Fk8v0xLiiiFdbGDPIZQ7mJY=
|
||||
gorm.io/gorm v1.31.0/go.mod h1:XyQVbO2k6YkOis7C2437jSit3SsDK72s7n7rsSHd+Gs=
|
||||
gorm.io/gorm v1.31.2 h1:3o8FXNo9v9S858gil+3LlZA1LkCOzgb4g5BL64FgaCo=
|
||||
gorm.io/gorm v1.31.2/go.mod h1:XyQVbO2k6YkOis7C2437jSit3SsDK72s7n7rsSHd+Gs=
|
||||
gvisor.dev/gvisor v0.0.0-20250503011706-39ed1f5ac29c h1:m/r7OM+Y2Ty1sgBQ7Qb27VgIMBW8ZZhT4gLnUyDIhzI=
|
||||
gvisor.dev/gvisor v0.0.0-20250503011706-39ed1f5ac29c/go.mod h1:3r5CMtNQMKIvBlrmM9xWUNamjKBYPOWyXOjmg5Kts3g=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
|
||||
+9
-9
@@ -1,6 +1,6 @@
|
||||
module github.com/bishopfox/sliver
|
||||
|
||||
go 1.24.0
|
||||
go 1.26.6
|
||||
|
||||
require (
|
||||
filippo.io/age v1.1.1
|
||||
@@ -11,14 +11,14 @@ require (
|
||||
github.com/kbinani/screenshot v0.0.0-20191211154542-3a185f1ce18f
|
||||
github.com/lesnuages/go-winio v0.4.19
|
||||
github.com/miekg/dns v1.1.50
|
||||
github.com/moloch--/memmod v0.0.0-20230225130813-fd77d905589e
|
||||
github.com/sliverarmory/reflektor v0.0.2
|
||||
github.com/stretchr/testify v1.8.4
|
||||
github.com/tetratelabs/wazero v1.7.1
|
||||
github.com/things-go/go-socks5 v0.0.4
|
||||
github.com/yiya1989/sshkrb5 v0.0.0-20201110125252-a1455b75a35e
|
||||
golang.org/x/crypto v0.42.0
|
||||
golang.org/x/net v0.43.0
|
||||
golang.org/x/sys v0.36.0
|
||||
golang.org/x/crypto v0.52.0
|
||||
golang.org/x/net v0.55.0
|
||||
golang.org/x/sys v0.45.0
|
||||
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173
|
||||
google.golang.org/protobuf v1.32.0
|
||||
gvisor.dev/gvisor v0.0.0-20230927004350-cbd86285d259
|
||||
@@ -37,11 +37,11 @@ require (
|
||||
github.com/jcmturner/gofork v1.0.0 // indirect
|
||||
github.com/lxn/win v0.0.0-20210218163916-a377121e959e // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
golang.org/x/mod v0.27.0 // indirect
|
||||
golang.org/x/sync v0.17.0 // indirect
|
||||
golang.org/x/text v0.29.0 // indirect
|
||||
golang.org/x/mod v0.35.0 // indirect
|
||||
golang.org/x/sync v0.20.0 // indirect
|
||||
golang.org/x/text v0.37.0 // indirect
|
||||
golang.org/x/time v0.5.0 // indirect
|
||||
golang.org/x/tools v0.36.0 // indirect
|
||||
golang.org/x/tools v0.44.0 // indirect
|
||||
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
|
||||
gopkg.in/jcmturner/aescts.v1 v1.0.1 // indirect
|
||||
gopkg.in/jcmturner/dnsutils.v1 v1.0.1 // indirect
|
||||
|
||||
+18
-18
@@ -39,12 +39,12 @@ github.com/lxn/win v0.0.0-20210218163916-a377121e959e h1:H+t6A/QJMbhCSEH5rAuRxh+
|
||||
github.com/lxn/win v0.0.0-20210218163916-a377121e959e/go.mod h1:KxxjdtRkfNoYDCUP5ryK7XJJNTnpC8atvtmTheChOtk=
|
||||
github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA=
|
||||
github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
|
||||
github.com/moloch--/memmod v0.0.0-20230225130813-fd77d905589e h1:IkFCPlAa0iTiLxck+NqAwBx8JDlnHYm4orOQBbs4BDQ=
|
||||
github.com/moloch--/memmod v0.0.0-20230225130813-fd77d905589e/go.mod h1:eYeI6cQ5YHhHt9i0BBW0zc1DaQnb4ZMXsSPuEV/V5Og=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/sliverarmory/reflektor v0.0.2 h1:nrEEFXrYiYFLCqyMpOJpe4RsY0Pu3tc1CvwChsNoAq4=
|
||||
github.com/sliverarmory/reflektor v0.0.2/go.mod h1:Rw7qTWQQlCM3YTxxeuklFt3Q+kh1Ytlmzg5UVw1Nhkg=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
@@ -61,21 +61,21 @@ github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI=
|
||||
golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8=
|
||||
golang.org/x/crypto v0.52.0 h1:RMs7fP2rXdep0CftQlK8Uf+kibLm7qkCcradZWYz988=
|
||||
golang.org/x/crypto v0.52.0/go.mod h1:1QgfPxDqh0T2M/elOJtp9RvuR95kVjir0e6/BvEmGbc=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.27.0 h1:kb+q2PyFnEADO2IEF935ehFUXlWiNjJWtRNgBLSfbxQ=
|
||||
golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc=
|
||||
golang.org/x/mod v0.35.0 h1:Ww1D637e6Pg+Zb2KrWfHQUnH2dQRLBQyAtpr/haaJeM=
|
||||
golang.org/x/mod v0.35.0/go.mod h1:+GwiRhIInF8wPm+4AoT6L0FA1QWAad3OMdTRx4tFYlU=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
|
||||
golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
|
||||
golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8=
|
||||
golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
|
||||
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
|
||||
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -88,24 +88,24 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220330033206-e17cdc41300f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
|
||||
golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY=
|
||||
golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ=
|
||||
golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA=
|
||||
golang.org/x/term v0.43.0 h1:S4RLU2sB31O/NCl+zFN9Aru9A/Cq2aqKpTZJ6B+DwT4=
|
||||
golang.org/x/term v0.43.0/go.mod h1:lrhlHNdQJHO+1qVYiHfFKVuVioJIheAc3fBSMFYEIsk=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk=
|
||||
golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=
|
||||
golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc=
|
||||
golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38=
|
||||
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
||||
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.36.0 h1:kWS0uv/zsvHEle1LbV5LE8QujrxB3wfQyxHfhOk0Qkg=
|
||||
golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s=
|
||||
golang.org/x/tools v0.44.0 h1:UP4ajHPIcuMjT1GqzDWRlalUEoY+uzoZKnhOjbIPD2c=
|
||||
golang.org/x/tools v0.44.0/go.mod h1:KA0AfVErSdxRZIsOVipbv3rQhVXTnlU6UhKxHd1seDI=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
||||
@@ -34,5 +34,16 @@ cd "$tempDir"
|
||||
go mod tidy -compat=1.25
|
||||
go mod vendor
|
||||
|
||||
# The lesnuages/go-winio fork provides RemoteClientMode, which Sliver needs,
|
||||
# but its checked-in syscall wrappers predate syscall.SyscallN. Regenerate the
|
||||
# wrappers with the pinned x/sys generator so Go 1.26 Windows/ARM64 debug builds
|
||||
# do not link the oversized syscall.Syscall15 wrapper.
|
||||
(
|
||||
cd vendor/github.com/lesnuages/go-winio
|
||||
go run -mod=mod golang.org/x/sys/windows/mkwinsyscall \
|
||||
-output zsyscall_windows.go \
|
||||
file.go pipe.go sd.go fileinfo.go privilege.go backup.go hvsock.go
|
||||
)
|
||||
|
||||
# move updated files back
|
||||
cleanup
|
||||
@@ -28,7 +28,7 @@ import (
|
||||
"log"
|
||||
// {{end}}
|
||||
|
||||
"github.com/moloch--/memmod"
|
||||
reflektor "github.com/sliverarmory/reflektor/memmod"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -39,7 +39,7 @@ const (
|
||||
type WindowsExtension struct {
|
||||
id string
|
||||
data []byte
|
||||
module *memmod.Module
|
||||
module *reflektor.Module
|
||||
arch string
|
||||
init string
|
||||
sync.Mutex
|
||||
@@ -73,7 +73,7 @@ func (w *WindowsExtension) Load() error {
|
||||
}
|
||||
w.Lock()
|
||||
defer w.Unlock()
|
||||
w.module, err = memmod.LoadLibrary(w.data)
|
||||
w.module, err = reflektor.LoadLibrary(w.data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
//go:build !sliver_lint
|
||||
|
||||
package main
|
||||
|
||||
/*
|
||||
|
||||
@@ -38,11 +38,20 @@ import (
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
// MaxFrameLength bounds the payload size a pivot will allocate from a peer's
|
||||
// 4-byte length prefix. A corrupted or desynced prefix can otherwise be read as
|
||||
// a value up to ~4GiB and trigger an allocation large enough to crash the
|
||||
// implant (see BishopFox/sliver#1452). 512MiB is far above any realistic
|
||||
// relayed message but well below a fatal allocation.
|
||||
const MaxFrameLength = 512 * 1024 * 1024
|
||||
|
||||
var (
|
||||
// ErrFailedWrite - Failed to write to a connection
|
||||
ErrFailedWrite = errors.New("failed to write")
|
||||
// ErrFailedKeyExchange - Failed to exchange session and/or peer keys
|
||||
ErrFailedKeyExchange = errors.New("failed key exchange")
|
||||
// ErrFrameTooLarge - A peer's declared frame length exceeds MaxFrameLength
|
||||
ErrFrameTooLarge = errors.New("pivot frame exceeds maximum length")
|
||||
|
||||
pivotListeners = &sync.Map{}
|
||||
stoppedPivotListeners = &sync.Map{}
|
||||
@@ -496,6 +505,12 @@ func (p *NetConnPivot) read() ([]byte, error) {
|
||||
// {{end}}
|
||||
return nil, errors.New("[pivot] zero data length")
|
||||
}
|
||||
if dataLength > MaxFrameLength {
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("[pivot] read error: frame length %d exceeds max %d\n", dataLength, MaxFrameLength)
|
||||
// {{end}}
|
||||
return nil, ErrFrameTooLarge
|
||||
}
|
||||
dataBuf := make([]byte, dataLength)
|
||||
|
||||
n, err = io.ReadFull(p.conn, dataBuf)
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
package pivots
|
||||
|
||||
/*
|
||||
Sliver Implant Framework
|
||||
Copyright (C) 2019 Bishop Fox
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"net"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func framePrefix(n uint32) []byte {
|
||||
b := make([]byte, 4)
|
||||
binary.LittleEndian.PutUint32(b, n)
|
||||
return b
|
||||
}
|
||||
|
||||
// readWithTimeout runs read() with a deadline so a regression (an unbounded
|
||||
// read that blocks waiting for a bogus multi-GB body) fails fast instead of
|
||||
// hanging the whole test binary.
|
||||
func readWithTimeout(t *testing.T, read func() ([]byte, error)) ([]byte, error) {
|
||||
t.Helper()
|
||||
type result struct {
|
||||
data []byte
|
||||
err error
|
||||
}
|
||||
ch := make(chan result, 1)
|
||||
go func() {
|
||||
d, e := read()
|
||||
ch <- result{d, e}
|
||||
}()
|
||||
select {
|
||||
case r := <-ch:
|
||||
return r.data, r.err
|
||||
case <-time.After(3 * time.Second):
|
||||
t.Fatal("read() did not return in time (possible unbounded read)")
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
// A corrupted/desynced 4-byte length prefix that reads as a huge value must be
|
||||
// rejected before allocating, instead of triggering a multi-GB allocation that
|
||||
// crashes the implant (BishopFox/sliver#1452).
|
||||
func TestNetConnPivotReadRejectsOversizedFrame(t *testing.T) {
|
||||
client, server := net.Pipe()
|
||||
defer func() { _ = client.Close() }()
|
||||
defer func() { _ = server.Close() }()
|
||||
|
||||
p := &NetConnPivot{conn: server, readMutex: &sync.Mutex{}}
|
||||
|
||||
go func() {
|
||||
// Only the length prefix is ever sent; no body follows.
|
||||
_, _ = client.Write(framePrefix(uint32(MaxFrameLength) + 1))
|
||||
}()
|
||||
|
||||
if _, err := readWithTimeout(t, p.read); !errors.Is(err, ErrFrameTooLarge) {
|
||||
t.Fatalf("expected ErrFrameTooLarge, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// A well-formed frame within the bound must still round-trip unchanged.
|
||||
func TestNetConnPivotReadAcceptsValidFrame(t *testing.T) {
|
||||
client, server := net.Pipe()
|
||||
defer func() { _ = client.Close() }()
|
||||
defer func() { _ = server.Close() }()
|
||||
|
||||
p := &NetConnPivot{conn: server, readMutex: &sync.Mutex{}}
|
||||
|
||||
payload := []byte("hello pivot")
|
||||
go func() {
|
||||
_, _ = client.Write(framePrefix(uint32(len(payload))))
|
||||
_, _ = client.Write(payload)
|
||||
}()
|
||||
|
||||
data, err := readWithTimeout(t, p.read)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if string(data) != string(payload) {
|
||||
t.Fatalf("got %q, want %q", data, payload)
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
//go:build !sliver_lint
|
||||
|
||||
package runner
|
||||
|
||||
/*
|
||||
|
||||
@@ -709,6 +709,9 @@ func (s *SliverDNSClient) parallelRecv(manifest *dnspb.DNSMessage) ([]byte, erro
|
||||
// SplitBuffer - There's probably a fancy way to calculate this with math and shit but it's much easier to just encode bytes
|
||||
// and check the length until we hit the limit
|
||||
func (s *SliverDNSClient) SplitBuffer(msg *dnspb.DNSMessage, encoder encoders.Encoder, data []byte) ([]string, error) {
|
||||
if msg == nil {
|
||||
return nil, ErrInvalidMsg
|
||||
}
|
||||
subdata := []string{}
|
||||
start := 0
|
||||
stop := start
|
||||
@@ -743,14 +746,34 @@ func (s *SliverDNSClient) SplitBuffer(msg *dnspb.DNSMessage, encoder encoders.En
|
||||
// log.Printf("[dns] shave data [%d:%d] of %d", start, stop, len(data))
|
||||
// {{end}}
|
||||
msg.Data = data[start:stop]
|
||||
pbMsg, _ := proto.Marshal(msg)
|
||||
encodedValue, _ := encoder.Encode(pbMsg)
|
||||
encoded = string(encodedValue)
|
||||
var err error
|
||||
encoded, err = encodeDNSMessage(msg, encoder)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// {{if .Config.Debug}}
|
||||
// log.Printf("[dns] encoded length is %d (max: %d)", len(encoded), s.subdataSpace)
|
||||
// {{end}}
|
||||
}
|
||||
|
||||
// Step back if a protobuf varint boundary caused encoded to overshoot.
|
||||
// Adding 1 byte across a varint boundary (e.g. Data length 127 to 128) grows
|
||||
// the proto by 2 bytes, which can jump base32 by +3 or +4, exceeding the
|
||||
// subdataSpace-1 guard above.
|
||||
for s.subdataSpace < len(encoded) && stop > start {
|
||||
stop--
|
||||
msg.Data = data[start:stop]
|
||||
var err error
|
||||
encoded, err = encodeDNSMessage(msg, encoder)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if stop <= start {
|
||||
return nil, errMsgTooLong
|
||||
}
|
||||
lastLen = len(msg.Data) // Save the amount of data that fit for the next loop
|
||||
|
||||
// {{if .Config.Debug}}
|
||||
encodedSubdata = append(encodedSubdata, encoded)
|
||||
// {{end}}
|
||||
@@ -789,6 +812,18 @@ func (s *SliverDNSClient) SplitBuffer(msg *dnspb.DNSMessage, encoder encoders.En
|
||||
return subdata, nil
|
||||
}
|
||||
|
||||
func encodeDNSMessage(msg *dnspb.DNSMessage, encoder encoders.Encoder) (string, error) {
|
||||
pbMsg, err := proto.Marshal(msg)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
encoded, err := encoder.Encode(pbMsg)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(encoded), nil
|
||||
}
|
||||
|
||||
func (s *SliverDNSClient) randomDNSSessionID() (uint32, error) {
|
||||
// sessionID is 24-bit and must be non-zero.
|
||||
randBuf := make([]byte, 4)
|
||||
|
||||
@@ -21,6 +21,7 @@ package dnsclient
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
insecureRand "math/rand"
|
||||
@@ -34,6 +35,18 @@ import (
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
type errorEncoder struct {
|
||||
err error
|
||||
}
|
||||
|
||||
func (e errorEncoder) Encode([]byte) ([]byte, error) {
|
||||
return nil, e.err
|
||||
}
|
||||
|
||||
func (e errorEncoder) Decode([]byte) ([]byte, error) {
|
||||
return nil, e.err
|
||||
}
|
||||
|
||||
const (
|
||||
// Do not change these without updating the tests
|
||||
parent1 = ".1.example.com."
|
||||
@@ -137,6 +150,40 @@ func TestSplitBufferBase32(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSplitBufferVarintBoundary(t *testing.T) {
|
||||
// At this parent length, growing msg.Data from 127 to 128 bytes makes the
|
||||
// encoded protobuf jump from 215 to 218 bytes while only 217 bytes fit.
|
||||
// SplitBuffer must step back before joining the encoded data to the parent.
|
||||
parent := fmt.Sprintf(".%s.example.com.", strings.Repeat("x", 19))
|
||||
client := NewDNSClient(parent, opts)
|
||||
if client.subdataSpace != 217 {
|
||||
t.Fatalf("Unexpected subdata space for parent %s: %d", parent, client.subdataSpace)
|
||||
}
|
||||
clientSplitBuffer(t, client, encoders.Base32{}, randomData(256))
|
||||
}
|
||||
|
||||
func TestSplitBufferErrors(t *testing.T) {
|
||||
client := NewDNSClient(parent1, opts)
|
||||
if _, err := client.SplitBuffer(nil, encoders.Base32{}, []byte{1}); !errors.Is(err, ErrInvalidMsg) {
|
||||
t.Fatalf("Expected %s, got %v", ErrInvalidMsg, err)
|
||||
}
|
||||
|
||||
encodeErr := errors.New("encode failed")
|
||||
msg := &dnspb.DNSMessage{Type: dnspb.DNSMessageType_DATA_FROM_IMPLANT, Size: 1}
|
||||
if _, err := client.SplitBuffer(msg, errorEncoder{err: encodeErr}, []byte{1}); !errors.Is(err, encodeErr) {
|
||||
t.Fatalf("Expected %s, got %v", encodeErr, err)
|
||||
}
|
||||
|
||||
// Leave one encoded byte of space so no non-empty protobuf can fit.
|
||||
client = NewDNSClient("."+strings.Repeat("a", 250)+".", opts)
|
||||
if client.subdataSpace != 1 {
|
||||
t.Fatalf("Unexpected subdata space: %d", client.subdataSpace)
|
||||
}
|
||||
if _, err := client.SplitBuffer(msg, encoders.Base32{}, []byte{1}); !errors.Is(err, errMsgTooLong) {
|
||||
t.Fatalf("Expected %s, got %v", errMsgTooLong, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSplitBufferDomainConstraints(t *testing.T) {
|
||||
client := NewDNSClient(parent1, opts)
|
||||
testData := randomData(8192)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
//go:build !windows
|
||||
|
||||
package http
|
||||
// Package wininet provides the Windows WinINet HTTP transport.
|
||||
package wininet
|
||||
|
||||
import "errors"
|
||||
|
||||
|
||||
@@ -62,6 +62,9 @@ func GoHTTPDriver(origin string, secure bool, opts *HTTPOptions) (HTTPDriver, er
|
||||
TLSClientConfig: tlsConfig,
|
||||
}
|
||||
}
|
||||
transport.ProxyConnectHeader = http.Header{
|
||||
"User-Agent": []string{userAgent},
|
||||
}
|
||||
client := &http.Client{
|
||||
Jar: cookieJar(),
|
||||
Timeout: opts.NetTimeout,
|
||||
|
||||
@@ -62,6 +62,10 @@ var (
|
||||
|
||||
const mtlsEnvelopeSigningSeedPrefix = "env-signing-v1:"
|
||||
|
||||
const maxEnvelopeLength = 512 * 1024 * 1024
|
||||
|
||||
var errEnvelopeTooLarge = errors.New("[mtls] envelope exceeds maximum length")
|
||||
|
||||
var (
|
||||
envelopeSigningOnce sync.Once
|
||||
envelopeSigningErr error
|
||||
@@ -207,11 +211,18 @@ func ReadEnvelope(r io.Reader) (*pb.Envelope, error) {
|
||||
|
||||
if dataLength <= 0 {
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("[pivot] read error: %s\n", err)
|
||||
log.Printf("[mtls] read error: %s\n", err)
|
||||
// {{end}}
|
||||
return nil, errors.New("[mtls] zero data length")
|
||||
}
|
||||
|
||||
if dataLength > maxEnvelopeLength {
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("[mtls] read error: envelope length %d exceeds max %d\n", dataLength, maxEnvelopeLength)
|
||||
// {{end}}
|
||||
return nil, errEnvelopeTooLarge
|
||||
}
|
||||
|
||||
dataBuf := make([]byte, dataLength)
|
||||
|
||||
n, err = io.ReadFull(r, dataBuf)
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
package mtls
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/bishopfox/sliver/implant/sliver/cryptography"
|
||||
)
|
||||
|
||||
func rawSigStub() []byte {
|
||||
return make([]byte, cryptography.RawSigSize)
|
||||
}
|
||||
|
||||
func lengthPrefix(n uint32) []byte {
|
||||
b := make([]byte, 4)
|
||||
binary.LittleEndian.PutUint32(b, n)
|
||||
return b
|
||||
}
|
||||
|
||||
func readEnvelopeWithTimeout(t *testing.T, buf *bytes.Reader) error {
|
||||
t.Helper()
|
||||
ch := make(chan error, 1)
|
||||
go func() {
|
||||
_, err := ReadEnvelope(buf)
|
||||
ch <- err
|
||||
}()
|
||||
select {
|
||||
case err := <-ch:
|
||||
return err
|
||||
case <-time.After(3 * time.Second):
|
||||
t.Fatal("ReadEnvelope did not return in time (possible unbounded allocation)")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadEnvelopeRejectsOversizedFrame(t *testing.T) {
|
||||
var frame []byte
|
||||
frame = append(frame, rawSigStub()...)
|
||||
frame = append(frame, lengthPrefix(uint32(maxEnvelopeLength)+1)...)
|
||||
buf := bytes.NewReader(frame)
|
||||
|
||||
err := readEnvelopeWithTimeout(t, buf)
|
||||
if !errors.Is(err, errEnvelopeTooLarge) {
|
||||
t.Fatalf("expected errEnvelopeTooLarge, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadEnvelopeRejectsZeroLength(t *testing.T) {
|
||||
var frame []byte
|
||||
frame = append(frame, rawSigStub()...)
|
||||
frame = append(frame, lengthPrefix(0)...)
|
||||
buf := bytes.NewReader(frame)
|
||||
|
||||
err := readEnvelopeWithTimeout(t, buf)
|
||||
if err == nil {
|
||||
t.Fatal("expected error for zero-length envelope")
|
||||
}
|
||||
}
|
||||
@@ -247,6 +247,13 @@ func (p *NetConnPivotClient) read() ([]byte, error) {
|
||||
return nil, errors.New("[pivot] zero data length")
|
||||
}
|
||||
|
||||
if dataLength > pivots.MaxFrameLength {
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("[pivot] read error: frame length %d exceeds max %d\n", dataLength, pivots.MaxFrameLength)
|
||||
// {{end}}
|
||||
return nil, pivots.ErrFrameTooLarge
|
||||
}
|
||||
|
||||
dataBuf := make([]byte, dataLength)
|
||||
|
||||
n, err = io.ReadFull(p.conn, dataBuf)
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
package pivotclients
|
||||
|
||||
/*
|
||||
Sliver Implant Framework
|
||||
Copyright (C) 2019 Bishop Fox
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"net"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/bishopfox/sliver/implant/sliver/pivots"
|
||||
)
|
||||
|
||||
func framePrefix(n uint32) []byte {
|
||||
b := make([]byte, 4)
|
||||
binary.LittleEndian.PutUint32(b, n)
|
||||
return b
|
||||
}
|
||||
|
||||
func readWithTimeout(t *testing.T, read func() ([]byte, error)) ([]byte, error) {
|
||||
t.Helper()
|
||||
type result struct {
|
||||
data []byte
|
||||
err error
|
||||
}
|
||||
ch := make(chan result, 1)
|
||||
go func() {
|
||||
d, e := read()
|
||||
ch <- result{d, e}
|
||||
}()
|
||||
select {
|
||||
case r := <-ch:
|
||||
return r.data, r.err
|
||||
case <-time.After(3 * time.Second):
|
||||
t.Fatal("read() did not return in time (possible unbounded read)")
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
// A corrupted/desynced length prefix must be rejected before allocating rather
|
||||
// than triggering a multi-GB allocation that crashes the implant.
|
||||
func TestNetConnPivotClientReadRejectsOversizedFrame(t *testing.T) {
|
||||
client, server := net.Pipe()
|
||||
defer func() { _ = client.Close() }()
|
||||
defer func() { _ = server.Close() }()
|
||||
|
||||
p := &NetConnPivotClient{conn: server, readMutex: &sync.Mutex{}}
|
||||
|
||||
go func() {
|
||||
_, _ = client.Write(framePrefix(uint32(pivots.MaxFrameLength) + 1))
|
||||
}()
|
||||
|
||||
if _, err := readWithTimeout(t, p.read); !errors.Is(err, pivots.ErrFrameTooLarge) {
|
||||
t.Fatalf("expected pivots.ErrFrameTooLarge, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNetConnPivotClientReadAcceptsValidFrame(t *testing.T) {
|
||||
client, server := net.Pipe()
|
||||
defer func() { _ = client.Close() }()
|
||||
defer func() { _ = server.Close() }()
|
||||
|
||||
p := &NetConnPivotClient{conn: server, readMutex: &sync.Mutex{}}
|
||||
|
||||
payload := []byte("hello pivot client")
|
||||
go func() {
|
||||
_, _ = client.Write(framePrefix(uint32(len(payload))))
|
||||
_, _ = client.Write(payload)
|
||||
}()
|
||||
|
||||
data, err := readWithTimeout(t, p.read)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if string(data) != string(payload) {
|
||||
t.Fatalf("got %q, want %q", data, payload)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
//go:build windows || darwin || linux
|
||||
|
||||
// Package wireguard implements the WireGuard transport for Sliver implants.
|
||||
package wireguard
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"net"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/bishopfox/sliver/implant/sliver/cryptography"
|
||||
)
|
||||
|
||||
func rawSigStub() []byte {
|
||||
return make([]byte, cryptography.RawSigSize)
|
||||
}
|
||||
|
||||
func lengthPrefix(n uint32) []byte {
|
||||
b := make([]byte, 4)
|
||||
binary.LittleEndian.PutUint32(b, n)
|
||||
return b
|
||||
}
|
||||
|
||||
func readEnvelopeWithTimeout(t *testing.T, conn net.Conn) error {
|
||||
t.Helper()
|
||||
ch := make(chan error, 1)
|
||||
go func() {
|
||||
_, err := ReadEnvelope(conn)
|
||||
ch <- err
|
||||
}()
|
||||
select {
|
||||
case err := <-ch:
|
||||
return err
|
||||
case <-time.After(3 * time.Second):
|
||||
t.Fatal("ReadEnvelope did not return in time (possible unbounded allocation)")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadEnvelopeRejectsOversizedFrame(t *testing.T) {
|
||||
client, server := net.Pipe()
|
||||
defer func() { _ = client.Close() }()
|
||||
defer func() { _ = server.Close() }()
|
||||
|
||||
go func() {
|
||||
_, _ = client.Write(rawSigStub())
|
||||
_, _ = client.Write(lengthPrefix(uint32(maxEnvelopeLength) + 1))
|
||||
}()
|
||||
|
||||
err := readEnvelopeWithTimeout(t, server)
|
||||
if !errors.Is(err, errEnvelopeTooLarge) {
|
||||
t.Fatalf("expected errEnvelopeTooLarge, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadEnvelopeRejectsZeroLength(t *testing.T) {
|
||||
client, server := net.Pipe()
|
||||
defer func() { _ = client.Close() }()
|
||||
defer func() { _ = server.Close() }()
|
||||
|
||||
go func() {
|
||||
_, _ = client.Write(rawSigStub())
|
||||
_, _ = client.Write(lengthPrefix(0))
|
||||
}()
|
||||
|
||||
err := readEnvelopeWithTimeout(t, server)
|
||||
if err == nil {
|
||||
t.Fatal("expected error for zero-length envelope")
|
||||
}
|
||||
}
|
||||
@@ -76,6 +76,10 @@ var (
|
||||
|
||||
const wgEnvelopeSigningSeedPrefix = "env-signing-v1:"
|
||||
|
||||
const maxEnvelopeLength = 512 * 1024 * 1024
|
||||
|
||||
var errEnvelopeTooLarge = errors.New("[wireguard] envelope exceeds maximum length")
|
||||
|
||||
var (
|
||||
envelopeSigningOnce sync.Once
|
||||
envelopeSigningErr error
|
||||
@@ -200,11 +204,18 @@ func ReadEnvelope(connection net.Conn) (*pb.Envelope, error) {
|
||||
|
||||
if dataLength <= 0 {
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("[pivot] read error: %s\n", err)
|
||||
log.Printf("[wireguard] read error: %s\n", err)
|
||||
// {{end}}
|
||||
return nil, errors.New("[wireguard] zero data length")
|
||||
}
|
||||
|
||||
if dataLength > maxEnvelopeLength {
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("[wireguard] read error: envelope length %d exceeds max %d\n", dataLength, maxEnvelopeLength)
|
||||
// {{end}}
|
||||
return nil, errEnvelopeTooLarge
|
||||
}
|
||||
|
||||
dataBuf := make([]byte, dataLength)
|
||||
|
||||
n, err = io.ReadFull(connection, dataBuf)
|
||||
|
||||
+32
-32
@@ -82,7 +82,7 @@ func adjustTokenPrivileges(token windows.Token, releaseAll bool, input *byte, ou
|
||||
if releaseAll {
|
||||
_p0 = 1
|
||||
}
|
||||
r0, _, e1 := syscall.Syscall6(procAdjustTokenPrivileges.Addr(), 6, uintptr(token), uintptr(_p0), uintptr(unsafe.Pointer(input)), uintptr(outputSize), uintptr(unsafe.Pointer(output)), uintptr(unsafe.Pointer(requiredSize)))
|
||||
r0, _, e1 := syscall.SyscallN(procAdjustTokenPrivileges.Addr(), uintptr(token), uintptr(_p0), uintptr(unsafe.Pointer(input)), uintptr(outputSize), uintptr(unsafe.Pointer(output)), uintptr(unsafe.Pointer(requiredSize)))
|
||||
success = r0 != 0
|
||||
if true {
|
||||
err = errnoErr(e1)
|
||||
@@ -91,7 +91,7 @@ func adjustTokenPrivileges(token windows.Token, releaseAll bool, input *byte, ou
|
||||
}
|
||||
|
||||
func convertSecurityDescriptorToStringSecurityDescriptor(sd *byte, revision uint32, secInfo uint32, sddl **uint16, sddlSize *uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall6(procConvertSecurityDescriptorToStringSecurityDescriptorW.Addr(), 5, uintptr(unsafe.Pointer(sd)), uintptr(revision), uintptr(secInfo), uintptr(unsafe.Pointer(sddl)), uintptr(unsafe.Pointer(sddlSize)), 0)
|
||||
r1, _, e1 := syscall.SyscallN(procConvertSecurityDescriptorToStringSecurityDescriptorW.Addr(), uintptr(unsafe.Pointer(sd)), uintptr(revision), uintptr(secInfo), uintptr(unsafe.Pointer(sddl)), uintptr(unsafe.Pointer(sddlSize)))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
@@ -99,7 +99,7 @@ func convertSecurityDescriptorToStringSecurityDescriptor(sd *byte, revision uint
|
||||
}
|
||||
|
||||
func convertSidToStringSid(sid *byte, str **uint16) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procConvertSidToStringSidW.Addr(), 2, uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(str)), 0)
|
||||
r1, _, e1 := syscall.SyscallN(procConvertSidToStringSidW.Addr(), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(str)))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
@@ -116,7 +116,7 @@ func convertStringSecurityDescriptorToSecurityDescriptor(str string, revision ui
|
||||
}
|
||||
|
||||
func _convertStringSecurityDescriptorToSecurityDescriptor(str *uint16, revision uint32, sd *uintptr, size *uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall6(procConvertStringSecurityDescriptorToSecurityDescriptorW.Addr(), 4, uintptr(unsafe.Pointer(str)), uintptr(revision), uintptr(unsafe.Pointer(sd)), uintptr(unsafe.Pointer(size)), 0, 0)
|
||||
r1, _, e1 := syscall.SyscallN(procConvertStringSecurityDescriptorToSecurityDescriptorW.Addr(), uintptr(unsafe.Pointer(str)), uintptr(revision), uintptr(unsafe.Pointer(sd)), uintptr(unsafe.Pointer(size)))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
@@ -124,13 +124,13 @@ func _convertStringSecurityDescriptorToSecurityDescriptor(str *uint16, revision
|
||||
}
|
||||
|
||||
func getSecurityDescriptorLength(sd uintptr) (len uint32) {
|
||||
r0, _, _ := syscall.Syscall(procGetSecurityDescriptorLength.Addr(), 1, uintptr(sd), 0, 0)
|
||||
r0, _, _ := syscall.SyscallN(procGetSecurityDescriptorLength.Addr(), uintptr(sd))
|
||||
len = uint32(r0)
|
||||
return
|
||||
}
|
||||
|
||||
func impersonateSelf(level uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procImpersonateSelf.Addr(), 1, uintptr(level), 0, 0)
|
||||
r1, _, e1 := syscall.SyscallN(procImpersonateSelf.Addr(), uintptr(level))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
@@ -147,7 +147,7 @@ func lookupAccountName(systemName *uint16, accountName string, sid *byte, sidSiz
|
||||
}
|
||||
|
||||
func _lookupAccountName(systemName *uint16, accountName *uint16, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall9(procLookupAccountNameW.Addr(), 7, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(accountName)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(sidSize)), uintptr(unsafe.Pointer(refDomain)), uintptr(unsafe.Pointer(refDomainSize)), uintptr(unsafe.Pointer(sidNameUse)), 0, 0)
|
||||
r1, _, e1 := syscall.SyscallN(procLookupAccountNameW.Addr(), uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(accountName)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(sidSize)), uintptr(unsafe.Pointer(refDomain)), uintptr(unsafe.Pointer(refDomainSize)), uintptr(unsafe.Pointer(sidNameUse)))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
@@ -164,7 +164,7 @@ func lookupPrivilegeDisplayName(systemName string, name *uint16, buffer *uint16,
|
||||
}
|
||||
|
||||
func _lookupPrivilegeDisplayName(systemName *uint16, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall6(procLookupPrivilegeDisplayNameW.Addr(), 5, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(buffer)), uintptr(unsafe.Pointer(size)), uintptr(unsafe.Pointer(languageId)), 0)
|
||||
r1, _, e1 := syscall.SyscallN(procLookupPrivilegeDisplayNameW.Addr(), uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(buffer)), uintptr(unsafe.Pointer(size)), uintptr(unsafe.Pointer(languageId)))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
@@ -181,7 +181,7 @@ func lookupPrivilegeName(systemName string, luid *uint64, buffer *uint16, size *
|
||||
}
|
||||
|
||||
func _lookupPrivilegeName(systemName *uint16, luid *uint64, buffer *uint16, size *uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall6(procLookupPrivilegeNameW.Addr(), 4, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(luid)), uintptr(unsafe.Pointer(buffer)), uintptr(unsafe.Pointer(size)), 0, 0)
|
||||
r1, _, e1 := syscall.SyscallN(procLookupPrivilegeNameW.Addr(), uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(luid)), uintptr(unsafe.Pointer(buffer)), uintptr(unsafe.Pointer(size)))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
@@ -203,7 +203,7 @@ func lookupPrivilegeValue(systemName string, name string, luid *uint64) (err err
|
||||
}
|
||||
|
||||
func _lookupPrivilegeValue(systemName *uint16, name *uint16, luid *uint64) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procLookupPrivilegeValueW.Addr(), 3, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(luid)))
|
||||
r1, _, e1 := syscall.SyscallN(procLookupPrivilegeValueW.Addr(), uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(luid)))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
@@ -215,7 +215,7 @@ func openThreadToken(thread syscall.Handle, accessMask uint32, openAsSelf bool,
|
||||
if openAsSelf {
|
||||
_p0 = 1
|
||||
}
|
||||
r1, _, e1 := syscall.Syscall6(procOpenThreadToken.Addr(), 4, uintptr(thread), uintptr(accessMask), uintptr(_p0), uintptr(unsafe.Pointer(token)), 0, 0)
|
||||
r1, _, e1 := syscall.SyscallN(procOpenThreadToken.Addr(), uintptr(thread), uintptr(accessMask), uintptr(_p0), uintptr(unsafe.Pointer(token)))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
@@ -223,7 +223,7 @@ func openThreadToken(thread syscall.Handle, accessMask uint32, openAsSelf bool,
|
||||
}
|
||||
|
||||
func revertToSelf() (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procRevertToSelf.Addr(), 0, 0, 0, 0)
|
||||
r1, _, e1 := syscall.SyscallN(procRevertToSelf.Addr())
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
@@ -243,7 +243,7 @@ func backupRead(h syscall.Handle, b []byte, bytesRead *uint32, abort bool, proce
|
||||
if processSecurity {
|
||||
_p2 = 1
|
||||
}
|
||||
r1, _, e1 := syscall.Syscall9(procBackupRead.Addr(), 7, uintptr(h), uintptr(unsafe.Pointer(_p0)), uintptr(len(b)), uintptr(unsafe.Pointer(bytesRead)), uintptr(_p1), uintptr(_p2), uintptr(unsafe.Pointer(context)), 0, 0)
|
||||
r1, _, e1 := syscall.SyscallN(procBackupRead.Addr(), uintptr(h), uintptr(unsafe.Pointer(_p0)), uintptr(len(b)), uintptr(unsafe.Pointer(bytesRead)), uintptr(_p1), uintptr(_p2), uintptr(unsafe.Pointer(context)))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
@@ -263,7 +263,7 @@ func backupWrite(h syscall.Handle, b []byte, bytesWritten *uint32, abort bool, p
|
||||
if processSecurity {
|
||||
_p2 = 1
|
||||
}
|
||||
r1, _, e1 := syscall.Syscall9(procBackupWrite.Addr(), 7, uintptr(h), uintptr(unsafe.Pointer(_p0)), uintptr(len(b)), uintptr(unsafe.Pointer(bytesWritten)), uintptr(_p1), uintptr(_p2), uintptr(unsafe.Pointer(context)), 0, 0)
|
||||
r1, _, e1 := syscall.SyscallN(procBackupWrite.Addr(), uintptr(h), uintptr(unsafe.Pointer(_p0)), uintptr(len(b)), uintptr(unsafe.Pointer(bytesWritten)), uintptr(_p1), uintptr(_p2), uintptr(unsafe.Pointer(context)))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
@@ -271,7 +271,7 @@ func backupWrite(h syscall.Handle, b []byte, bytesWritten *uint32, abort bool, p
|
||||
}
|
||||
|
||||
func cancelIoEx(file syscall.Handle, o *syscall.Overlapped) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procCancelIoEx.Addr(), 2, uintptr(file), uintptr(unsafe.Pointer(o)), 0)
|
||||
r1, _, e1 := syscall.SyscallN(procCancelIoEx.Addr(), uintptr(file), uintptr(unsafe.Pointer(o)))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
@@ -279,7 +279,7 @@ func cancelIoEx(file syscall.Handle, o *syscall.Overlapped) (err error) {
|
||||
}
|
||||
|
||||
func connectNamedPipe(pipe syscall.Handle, o *syscall.Overlapped) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procConnectNamedPipe.Addr(), 2, uintptr(pipe), uintptr(unsafe.Pointer(o)), 0)
|
||||
r1, _, e1 := syscall.SyscallN(procConnectNamedPipe.Addr(), uintptr(pipe), uintptr(unsafe.Pointer(o)))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
@@ -296,7 +296,7 @@ func createFile(name string, access uint32, mode uint32, sa *syscall.SecurityAtt
|
||||
}
|
||||
|
||||
func _createFile(name *uint16, access uint32, mode uint32, sa *syscall.SecurityAttributes, createmode uint32, attrs uint32, templatefile syscall.Handle) (handle syscall.Handle, err error) {
|
||||
r0, _, e1 := syscall.Syscall9(procCreateFileW.Addr(), 7, uintptr(unsafe.Pointer(name)), uintptr(access), uintptr(mode), uintptr(unsafe.Pointer(sa)), uintptr(createmode), uintptr(attrs), uintptr(templatefile), 0, 0)
|
||||
r0, _, e1 := syscall.SyscallN(procCreateFileW.Addr(), uintptr(unsafe.Pointer(name)), uintptr(access), uintptr(mode), uintptr(unsafe.Pointer(sa)), uintptr(createmode), uintptr(attrs), uintptr(templatefile))
|
||||
handle = syscall.Handle(r0)
|
||||
if handle == syscall.InvalidHandle {
|
||||
err = errnoErr(e1)
|
||||
@@ -305,7 +305,7 @@ func _createFile(name *uint16, access uint32, mode uint32, sa *syscall.SecurityA
|
||||
}
|
||||
|
||||
func createIoCompletionPort(file syscall.Handle, port syscall.Handle, key uintptr, threadCount uint32) (newport syscall.Handle, err error) {
|
||||
r0, _, e1 := syscall.Syscall6(procCreateIoCompletionPort.Addr(), 4, uintptr(file), uintptr(port), uintptr(key), uintptr(threadCount), 0, 0)
|
||||
r0, _, e1 := syscall.SyscallN(procCreateIoCompletionPort.Addr(), uintptr(file), uintptr(port), uintptr(key), uintptr(threadCount))
|
||||
newport = syscall.Handle(r0)
|
||||
if newport == 0 {
|
||||
err = errnoErr(e1)
|
||||
@@ -323,7 +323,7 @@ func createNamedPipe(name string, flags uint32, pipeMode uint32, maxInstances ui
|
||||
}
|
||||
|
||||
func _createNamedPipe(name *uint16, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *syscall.SecurityAttributes) (handle syscall.Handle, err error) {
|
||||
r0, _, e1 := syscall.Syscall9(procCreateNamedPipeW.Addr(), 8, uintptr(unsafe.Pointer(name)), uintptr(flags), uintptr(pipeMode), uintptr(maxInstances), uintptr(outSize), uintptr(inSize), uintptr(defaultTimeout), uintptr(unsafe.Pointer(sa)), 0)
|
||||
r0, _, e1 := syscall.SyscallN(procCreateNamedPipeW.Addr(), uintptr(unsafe.Pointer(name)), uintptr(flags), uintptr(pipeMode), uintptr(maxInstances), uintptr(outSize), uintptr(inSize), uintptr(defaultTimeout), uintptr(unsafe.Pointer(sa)))
|
||||
handle = syscall.Handle(r0)
|
||||
if handle == syscall.InvalidHandle {
|
||||
err = errnoErr(e1)
|
||||
@@ -332,13 +332,13 @@ func _createNamedPipe(name *uint16, flags uint32, pipeMode uint32, maxInstances
|
||||
}
|
||||
|
||||
func getCurrentThread() (h syscall.Handle) {
|
||||
r0, _, _ := syscall.Syscall(procGetCurrentThread.Addr(), 0, 0, 0, 0)
|
||||
r0, _, _ := syscall.SyscallN(procGetCurrentThread.Addr())
|
||||
h = syscall.Handle(r0)
|
||||
return
|
||||
}
|
||||
|
||||
func getNamedPipeHandleState(pipe syscall.Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall9(procGetNamedPipeHandleStateW.Addr(), 7, uintptr(pipe), uintptr(unsafe.Pointer(state)), uintptr(unsafe.Pointer(curInstances)), uintptr(unsafe.Pointer(maxCollectionCount)), uintptr(unsafe.Pointer(collectDataTimeout)), uintptr(unsafe.Pointer(userName)), uintptr(maxUserNameSize), 0, 0)
|
||||
r1, _, e1 := syscall.SyscallN(procGetNamedPipeHandleStateW.Addr(), uintptr(pipe), uintptr(unsafe.Pointer(state)), uintptr(unsafe.Pointer(curInstances)), uintptr(unsafe.Pointer(maxCollectionCount)), uintptr(unsafe.Pointer(collectDataTimeout)), uintptr(unsafe.Pointer(userName)), uintptr(maxUserNameSize))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
@@ -346,7 +346,7 @@ func getNamedPipeHandleState(pipe syscall.Handle, state *uint32, curInstances *u
|
||||
}
|
||||
|
||||
func getNamedPipeInfo(pipe syscall.Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall6(procGetNamedPipeInfo.Addr(), 5, uintptr(pipe), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(outSize)), uintptr(unsafe.Pointer(inSize)), uintptr(unsafe.Pointer(maxInstances)), 0)
|
||||
r1, _, e1 := syscall.SyscallN(procGetNamedPipeInfo.Addr(), uintptr(pipe), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(outSize)), uintptr(unsafe.Pointer(inSize)), uintptr(unsafe.Pointer(maxInstances)))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
@@ -354,7 +354,7 @@ func getNamedPipeInfo(pipe syscall.Handle, flags *uint32, outSize *uint32, inSiz
|
||||
}
|
||||
|
||||
func getQueuedCompletionStatus(port syscall.Handle, bytes *uint32, key *uintptr, o **ioOperation, timeout uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall6(procGetQueuedCompletionStatus.Addr(), 5, uintptr(port), uintptr(unsafe.Pointer(bytes)), uintptr(unsafe.Pointer(key)), uintptr(unsafe.Pointer(o)), uintptr(timeout), 0)
|
||||
r1, _, e1 := syscall.SyscallN(procGetQueuedCompletionStatus.Addr(), uintptr(port), uintptr(unsafe.Pointer(bytes)), uintptr(unsafe.Pointer(key)), uintptr(unsafe.Pointer(o)), uintptr(timeout))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
@@ -362,18 +362,18 @@ func getQueuedCompletionStatus(port syscall.Handle, bytes *uint32, key *uintptr,
|
||||
}
|
||||
|
||||
func localAlloc(uFlags uint32, length uint32) (ptr uintptr) {
|
||||
r0, _, _ := syscall.Syscall(procLocalAlloc.Addr(), 2, uintptr(uFlags), uintptr(length), 0)
|
||||
r0, _, _ := syscall.SyscallN(procLocalAlloc.Addr(), uintptr(uFlags), uintptr(length))
|
||||
ptr = uintptr(r0)
|
||||
return
|
||||
}
|
||||
|
||||
func localFree(mem uintptr) {
|
||||
syscall.Syscall(procLocalFree.Addr(), 1, uintptr(mem), 0, 0)
|
||||
syscall.SyscallN(procLocalFree.Addr(), uintptr(mem))
|
||||
return
|
||||
}
|
||||
|
||||
func setFileCompletionNotificationModes(h syscall.Handle, flags uint8) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procSetFileCompletionNotificationModes.Addr(), 2, uintptr(h), uintptr(flags), 0)
|
||||
r1, _, e1 := syscall.SyscallN(procSetFileCompletionNotificationModes.Addr(), uintptr(h), uintptr(flags))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
@@ -381,25 +381,25 @@ func setFileCompletionNotificationModes(h syscall.Handle, flags uint8) (err erro
|
||||
}
|
||||
|
||||
func ntCreateNamedPipeFile(pipe *syscall.Handle, access uint32, oa *objectAttributes, iosb *ioStatusBlock, share uint32, disposition uint32, options uint32, typ uint32, readMode uint32, completionMode uint32, maxInstances uint32, inboundQuota uint32, outputQuota uint32, timeout *int64) (status ntstatus) {
|
||||
r0, _, _ := syscall.Syscall15(procNtCreateNamedPipeFile.Addr(), 14, uintptr(unsafe.Pointer(pipe)), uintptr(access), uintptr(unsafe.Pointer(oa)), uintptr(unsafe.Pointer(iosb)), uintptr(share), uintptr(disposition), uintptr(options), uintptr(typ), uintptr(readMode), uintptr(completionMode), uintptr(maxInstances), uintptr(inboundQuota), uintptr(outputQuota), uintptr(unsafe.Pointer(timeout)), 0)
|
||||
r0, _, _ := syscall.SyscallN(procNtCreateNamedPipeFile.Addr(), uintptr(unsafe.Pointer(pipe)), uintptr(access), uintptr(unsafe.Pointer(oa)), uintptr(unsafe.Pointer(iosb)), uintptr(share), uintptr(disposition), uintptr(options), uintptr(typ), uintptr(readMode), uintptr(completionMode), uintptr(maxInstances), uintptr(inboundQuota), uintptr(outputQuota), uintptr(unsafe.Pointer(timeout)))
|
||||
status = ntstatus(r0)
|
||||
return
|
||||
}
|
||||
|
||||
func rtlDefaultNpAcl(dacl *uintptr) (status ntstatus) {
|
||||
r0, _, _ := syscall.Syscall(procRtlDefaultNpAcl.Addr(), 1, uintptr(unsafe.Pointer(dacl)), 0, 0)
|
||||
r0, _, _ := syscall.SyscallN(procRtlDefaultNpAcl.Addr(), uintptr(unsafe.Pointer(dacl)))
|
||||
status = ntstatus(r0)
|
||||
return
|
||||
}
|
||||
|
||||
func rtlDosPathNameToNtPathName(name *uint16, ntName *unicodeString, filePart uintptr, reserved uintptr) (status ntstatus) {
|
||||
r0, _, _ := syscall.Syscall6(procRtlDosPathNameToNtPathName_U.Addr(), 4, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(ntName)), uintptr(filePart), uintptr(reserved), 0, 0)
|
||||
r0, _, _ := syscall.SyscallN(procRtlDosPathNameToNtPathName_U.Addr(), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(ntName)), uintptr(filePart), uintptr(reserved))
|
||||
status = ntstatus(r0)
|
||||
return
|
||||
}
|
||||
|
||||
func rtlNtStatusToDosError(status ntstatus) (winerr error) {
|
||||
r0, _, _ := syscall.Syscall(procRtlNtStatusToDosErrorNoTeb.Addr(), 1, uintptr(status), 0, 0)
|
||||
r0, _, _ := syscall.SyscallN(procRtlNtStatusToDosErrorNoTeb.Addr(), uintptr(status))
|
||||
if r0 != 0 {
|
||||
winerr = syscall.Errno(r0)
|
||||
}
|
||||
@@ -411,7 +411,7 @@ func wsaGetOverlappedResult(h syscall.Handle, o *syscall.Overlapped, bytes *uint
|
||||
if wait {
|
||||
_p0 = 1
|
||||
}
|
||||
r1, _, e1 := syscall.Syscall6(procWSAGetOverlappedResult.Addr(), 5, uintptr(h), uintptr(unsafe.Pointer(o)), uintptr(unsafe.Pointer(bytes)), uintptr(_p0), uintptr(unsafe.Pointer(flags)), 0)
|
||||
r1, _, e1 := syscall.SyscallN(procWSAGetOverlappedResult.Addr(), uintptr(h), uintptr(unsafe.Pointer(o)), uintptr(unsafe.Pointer(bytes)), uintptr(_p0), uintptr(unsafe.Pointer(flags)))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
@@ -419,7 +419,7 @@ func wsaGetOverlappedResult(h syscall.Handle, o *syscall.Overlapped, bytes *uint
|
||||
}
|
||||
|
||||
func bind(s syscall.Handle, name unsafe.Pointer, namelen int32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procbind.Addr(), 3, uintptr(s), uintptr(name), uintptr(namelen))
|
||||
r1, _, e1 := syscall.SyscallN(procbind.Addr(), uintptr(s), uintptr(name), uintptr(namelen))
|
||||
if r1 == socketError {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
|
||||
+674
@@ -0,0 +1,674 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
||||
Generated
Vendored
File renamed without changes.
Generated
Vendored
File renamed without changes.
+1541
File diff suppressed because it is too large.
Load diff
+30
@@ -0,0 +1,30 @@
|
||||
//go:build darwin && amd64 && !cgo
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
TEXT ·cCall10(SB), NOSPLIT, $0-96
|
||||
MOVQ fn+0(FP), AX
|
||||
MOVQ a0+8(FP), DI
|
||||
MOVQ a1+16(FP), SI
|
||||
MOVQ a2+24(FP), DX
|
||||
MOVQ a3+32(FP), CX
|
||||
MOVQ a4+40(FP), R8
|
||||
MOVQ a5+48(FP), R9
|
||||
|
||||
// Keep SysV stack alignment before calling C++ dyld internals:
|
||||
// reserve 32 bytes for stack args (a6-a9) plus 8 bytes padding.
|
||||
SUBQ $40, SP
|
||||
MOVQ a6+56(FP), R10
|
||||
MOVQ R10, 0(SP)
|
||||
MOVQ a7+64(FP), R10
|
||||
MOVQ R10, 8(SP)
|
||||
MOVQ a8+72(FP), R10
|
||||
MOVQ R10, 16(SP)
|
||||
MOVQ a9+80(FP), R10
|
||||
MOVQ R10, 24(SP)
|
||||
|
||||
CALL AX
|
||||
|
||||
ADDQ $40, SP
|
||||
MOVQ AX, ret+88(FP)
|
||||
RET
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
//go:build darwin && arm64 && !cgo
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
TEXT ·cCall10(SB), NOSPLIT, $0-96
|
||||
MOVD fn+0(FP), R16
|
||||
MOVD a0+8(FP), R0
|
||||
MOVD a1+16(FP), R1
|
||||
MOVD a2+24(FP), R2
|
||||
MOVD a3+32(FP), R3
|
||||
MOVD a4+40(FP), R4
|
||||
MOVD a5+48(FP), R5
|
||||
MOVD a6+56(FP), R6
|
||||
MOVD a7+64(FP), R7
|
||||
SUB $16, RSP
|
||||
MOVD a8+72(FP), R10
|
||||
MOVD a9+80(FP), R11
|
||||
MOVD R10, 0(RSP)
|
||||
MOVD R11, 8(RSP)
|
||||
BL (R16)
|
||||
ADD $16, RSP
|
||||
MOVD R0, ret+88(FP)
|
||||
RET
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
//go:build darwin && (amd64 || arm64) && !cgo
|
||||
|
||||
package memmod
|
||||
|
||||
import _ "unsafe"
|
||||
|
||||
//go:noescape
|
||||
func cCall10(fn, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) uintptr
|
||||
|
||||
//go:linkname runtimeSystemstack runtime.systemstack
|
||||
func runtimeSystemstack(fn func())
|
||||
|
||||
func call0(fn uintptr) uintptr {
|
||||
return call10(fn, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
|
||||
}
|
||||
|
||||
func callVoid0(fn uintptr) {
|
||||
_ = call0(fn)
|
||||
}
|
||||
|
||||
func callDlopen(fn, name uintptr, flags int) uintptr {
|
||||
return call2(fn, name, uintptr(flags))
|
||||
}
|
||||
|
||||
func callDlerror(fn uintptr) uintptr {
|
||||
return call0(fn)
|
||||
}
|
||||
|
||||
func call1(fn, a0 uintptr) uintptr {
|
||||
return call10(fn, a0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
|
||||
}
|
||||
|
||||
func call2(fn, a0, a1 uintptr) uintptr {
|
||||
return call10(fn, a0, a1, 0, 0, 0, 0, 0, 0, 0, 0)
|
||||
}
|
||||
|
||||
func call4(fn, a0, a1, a2, a3 uintptr) uintptr {
|
||||
return call10(fn, a0, a1, a2, a3, 0, 0, 0, 0, 0, 0)
|
||||
}
|
||||
|
||||
func call6(fn, a0, a1, a2, a3, a4, a5 uintptr) uintptr {
|
||||
return call10(fn, a0, a1, a2, a3, a4, a5, 0, 0, 0, 0)
|
||||
}
|
||||
|
||||
func call10(fn, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) uintptr {
|
||||
var ret uintptr
|
||||
runtimeSystemstack(func() {
|
||||
ret = cCall10(fn, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)
|
||||
})
|
||||
return ret
|
||||
}
|
||||
Generated
Vendored
+85
@@ -0,0 +1,85 @@
|
||||
//go:build darwin && (amd64 || arm64) && cgo
|
||||
|
||||
package memmod
|
||||
|
||||
/*
|
||||
#include <stdint.h>
|
||||
|
||||
typedef uintptr_t (*reflektor_fn10_t)(
|
||||
uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t,
|
||||
uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t
|
||||
);
|
||||
|
||||
typedef void (*reflektor_void_fn0_t)(void);
|
||||
typedef void *(*reflektor_dlopen_fn_t)(const char *, int);
|
||||
typedef const char *(*reflektor_dlerror_fn_t)(void);
|
||||
|
||||
static void reflektor_call_void0(uintptr_t fn) {
|
||||
((reflektor_void_fn0_t)fn)();
|
||||
}
|
||||
|
||||
static uintptr_t reflektor_call_dlopen(uintptr_t fn, uintptr_t name, int flags) {
|
||||
return (uintptr_t)((reflektor_dlopen_fn_t)fn)((const char *)name, flags);
|
||||
}
|
||||
|
||||
static uintptr_t reflektor_call_dlerror(uintptr_t fn) {
|
||||
return (uintptr_t)((reflektor_dlerror_fn_t)fn)();
|
||||
}
|
||||
|
||||
static uintptr_t reflektor_call10(
|
||||
uintptr_t fn,
|
||||
uintptr_t a0, uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4,
|
||||
uintptr_t a5, uintptr_t a6, uintptr_t a7, uintptr_t a8, uintptr_t a9
|
||||
) {
|
||||
return ((reflektor_fn10_t)fn)(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
|
||||
func callVoid0(fn uintptr) {
|
||||
C.reflektor_call_void0(C.uintptr_t(fn))
|
||||
}
|
||||
|
||||
func callDlopen(fn, name uintptr, flags int) uintptr {
|
||||
return uintptr(C.reflektor_call_dlopen(C.uintptr_t(fn), C.uintptr_t(name), C.int(flags)))
|
||||
}
|
||||
|
||||
func callDlerror(fn uintptr) uintptr {
|
||||
return uintptr(C.reflektor_call_dlerror(C.uintptr_t(fn)))
|
||||
}
|
||||
|
||||
func call0(fn uintptr) uintptr {
|
||||
return call10(fn, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
|
||||
}
|
||||
|
||||
func call1(fn, a0 uintptr) uintptr {
|
||||
return call10(fn, a0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
|
||||
}
|
||||
|
||||
func call2(fn, a0, a1 uintptr) uintptr {
|
||||
return call10(fn, a0, a1, 0, 0, 0, 0, 0, 0, 0, 0)
|
||||
}
|
||||
|
||||
func call4(fn, a0, a1, a2, a3 uintptr) uintptr {
|
||||
return call10(fn, a0, a1, a2, a3, 0, 0, 0, 0, 0, 0)
|
||||
}
|
||||
|
||||
func call6(fn, a0, a1, a2, a3, a4, a5 uintptr) uintptr {
|
||||
return call10(fn, a0, a1, a2, a3, a4, a5, 0, 0, 0, 0)
|
||||
}
|
||||
|
||||
func call10(fn, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) uintptr {
|
||||
return uintptr(C.reflektor_call10(
|
||||
C.uintptr_t(fn),
|
||||
C.uintptr_t(a0),
|
||||
C.uintptr_t(a1),
|
||||
C.uintptr_t(a2),
|
||||
C.uintptr_t(a3),
|
||||
C.uintptr_t(a4),
|
||||
C.uintptr_t(a5),
|
||||
C.uintptr_t(a6),
|
||||
C.uintptr_t(a7),
|
||||
C.uintptr_t(a8),
|
||||
C.uintptr_t(a9),
|
||||
))
|
||||
}
|
||||
+1526
File diff suppressed because it is too large.
Load diff
+45
@@ -0,0 +1,45 @@
|
||||
//go:build linux && !cgo && 386
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
TEXT ·cCall0(SB), NOSPLIT, $0-8
|
||||
MOVL fn+0(FP), AX
|
||||
CALL AX
|
||||
MOVL AX, ret+4(FP)
|
||||
RET
|
||||
|
||||
TEXT ·cCall1(SB), NOSPLIT, $0-12
|
||||
MOVL fn+0(FP), AX
|
||||
MOVL a0+4(FP), BX
|
||||
SUBL $4, SP
|
||||
MOVL BX, 0(SP)
|
||||
CALL AX
|
||||
ADDL $4, SP
|
||||
MOVL AX, ret+8(FP)
|
||||
RET
|
||||
|
||||
TEXT ·cCall2(SB), NOSPLIT, $0-16
|
||||
MOVL fn+0(FP), AX
|
||||
MOVL a0+4(FP), BX
|
||||
MOVL a1+8(FP), CX
|
||||
SUBL $8, SP
|
||||
MOVL BX, 0(SP)
|
||||
MOVL CX, 4(SP)
|
||||
CALL AX
|
||||
ADDL $8, SP
|
||||
MOVL AX, ret+12(FP)
|
||||
RET
|
||||
|
||||
TEXT ·cCall3(SB), NOSPLIT, $0-20
|
||||
MOVL fn+0(FP), AX
|
||||
MOVL a0+4(FP), BX
|
||||
MOVL a1+8(FP), CX
|
||||
MOVL a2+12(FP), DX
|
||||
SUBL $12, SP
|
||||
MOVL BX, 0(SP)
|
||||
MOVL CX, 4(SP)
|
||||
MOVL DX, 8(SP)
|
||||
CALL AX
|
||||
ADDL $12, SP
|
||||
MOVL AX, ret+16(FP)
|
||||
RET
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
//go:build linux && !cgo && amd64
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
TEXT ·cCall0(SB), NOSPLIT, $0-16
|
||||
MOVQ fn+0(FP), AX
|
||||
CALL AX
|
||||
MOVQ AX, ret+8(FP)
|
||||
RET
|
||||
|
||||
TEXT ·cCall1(SB), NOSPLIT, $0-24
|
||||
MOVQ fn+0(FP), AX
|
||||
MOVQ a0+8(FP), DI
|
||||
CALL AX
|
||||
MOVQ AX, ret+16(FP)
|
||||
RET
|
||||
|
||||
TEXT ·cCall2(SB), NOSPLIT, $0-32
|
||||
MOVQ fn+0(FP), AX
|
||||
MOVQ a0+8(FP), DI
|
||||
MOVQ a1+16(FP), SI
|
||||
CALL AX
|
||||
MOVQ AX, ret+24(FP)
|
||||
RET
|
||||
|
||||
TEXT ·cCall3(SB), NOSPLIT, $0-40
|
||||
MOVQ fn+0(FP), AX
|
||||
MOVQ a0+8(FP), DI
|
||||
MOVQ a1+16(FP), SI
|
||||
MOVQ a2+24(FP), DX
|
||||
CALL AX
|
||||
MOVQ AX, ret+32(FP)
|
||||
RET
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
//go:build linux && !cgo && arm64
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
TEXT ·cCall0(SB), NOSPLIT, $0-16
|
||||
MOVD fn+0(FP), R16
|
||||
BL (R16)
|
||||
MOVD R0, ret+8(FP)
|
||||
RET
|
||||
|
||||
TEXT ·cCall1(SB), NOSPLIT, $0-24
|
||||
MOVD fn+0(FP), R16
|
||||
MOVD a0+8(FP), R0
|
||||
BL (R16)
|
||||
MOVD R0, ret+16(FP)
|
||||
RET
|
||||
|
||||
TEXT ·cCall2(SB), NOSPLIT, $0-32
|
||||
MOVD fn+0(FP), R16
|
||||
MOVD a0+8(FP), R0
|
||||
MOVD a1+16(FP), R1
|
||||
BL (R16)
|
||||
MOVD R0, ret+24(FP)
|
||||
RET
|
||||
|
||||
TEXT ·cCall3(SB), NOSPLIT, $0-40
|
||||
MOVD fn+0(FP), R16
|
||||
MOVD a0+8(FP), R0
|
||||
MOVD a1+16(FP), R1
|
||||
MOVD a2+24(FP), R2
|
||||
BL (R16)
|
||||
MOVD R0, ret+32(FP)
|
||||
RET
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
//go:build linux && !cgo && (386 || amd64 || arm64)
|
||||
|
||||
package memmod
|
||||
|
||||
//go:noescape
|
||||
func cCall0(fn uintptr) uintptr
|
||||
|
||||
//go:noescape
|
||||
func cCall1(fn, a0 uintptr) uintptr
|
||||
|
||||
//go:noescape
|
||||
func cCall2(fn, a0, a1 uintptr) uintptr
|
||||
|
||||
//go:noescape
|
||||
func cCall3(fn, a0, a1, a2 uintptr) uintptr
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
//go:build linux && cgo && (386 || amd64 || arm64)
|
||||
|
||||
package memmod
|
||||
|
||||
/*
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef uintptr_t (*reflektor_fn0)(void);
|
||||
typedef uintptr_t (*reflektor_fn1)(uintptr_t);
|
||||
typedef uintptr_t (*reflektor_fn2)(uintptr_t, uintptr_t);
|
||||
typedef uintptr_t (*reflektor_fn3)(uintptr_t, uintptr_t, uintptr_t);
|
||||
|
||||
static uintptr_t reflektor_call0(uintptr_t fn) {
|
||||
return ((reflektor_fn0)fn)();
|
||||
}
|
||||
|
||||
static uintptr_t reflektor_call1(uintptr_t fn, uintptr_t a0) {
|
||||
return ((reflektor_fn1)fn)(a0);
|
||||
}
|
||||
|
||||
static uintptr_t reflektor_call2(uintptr_t fn, uintptr_t a0, uintptr_t a1) {
|
||||
return ((reflektor_fn2)fn)(a0, a1);
|
||||
}
|
||||
|
||||
static uintptr_t reflektor_call3(uintptr_t fn, uintptr_t a0, uintptr_t a1, uintptr_t a2) {
|
||||
return ((reflektor_fn3)fn)(a0, a1, a2);
|
||||
}
|
||||
|
||||
static uintptr_t reflektor_init_argc = 0;
|
||||
static uintptr_t reflektor_init_argv = 0;
|
||||
static uintptr_t reflektor_init_envp = 0;
|
||||
|
||||
// Build a tiny synthetic argv/envp/auxv vector for runtimes that expect a
|
||||
// startup-like layout (argc/argv/envp/auxv). The layout is:
|
||||
// argv[0] = NULL
|
||||
// envp[0] = NULL
|
||||
// auxv[0] = AT_NULL
|
||||
// auxv[1] = 0
|
||||
static void reflektor_init_call_args(uintptr_t *argc, uintptr_t *argv, uintptr_t *envp) {
|
||||
if (reflektor_init_argv == 0) {
|
||||
uintptr_t *vec = (uintptr_t *)calloc(4, sizeof(uintptr_t));
|
||||
if (vec != NULL) {
|
||||
reflektor_init_argv = (uintptr_t)vec;
|
||||
reflektor_init_envp = (uintptr_t)(vec + 1);
|
||||
}
|
||||
}
|
||||
*argc = reflektor_init_argc;
|
||||
*argv = reflektor_init_argv;
|
||||
*envp = reflektor_init_envp;
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
|
||||
func cCall0(fn uintptr) uintptr {
|
||||
return uintptr(C.reflektor_call0(C.uintptr_t(fn)))
|
||||
}
|
||||
|
||||
func cCall1(fn, a0 uintptr) uintptr {
|
||||
return uintptr(C.reflektor_call1(C.uintptr_t(fn), C.uintptr_t(a0)))
|
||||
}
|
||||
|
||||
func cCall2(fn, a0, a1 uintptr) uintptr {
|
||||
return uintptr(C.reflektor_call2(C.uintptr_t(fn), C.uintptr_t(a0), C.uintptr_t(a1)))
|
||||
}
|
||||
|
||||
func cCall3(fn, a0, a1, a2 uintptr) uintptr {
|
||||
return uintptr(C.reflektor_call3(C.uintptr_t(fn), C.uintptr_t(a0), C.uintptr_t(a1), C.uintptr_t(a2)))
|
||||
}
|
||||
|
||||
func linuxInitCallArgs() (uintptr, uintptr, uintptr) {
|
||||
var argc C.uintptr_t
|
||||
var argv C.uintptr_t
|
||||
var envp C.uintptr_t
|
||||
C.reflektor_init_call_args(&argc, &argv, &envp)
|
||||
return uintptr(argc), uintptr(argv), uintptr(envp)
|
||||
}
|
||||
Generated
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
//go:build linux && !cgo && (386 || amd64 || arm64)
|
||||
|
||||
package memmod
|
||||
|
||||
func linuxInitCallArgs() (uintptr, uintptr, uintptr) {
|
||||
return 0, 0, 0
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
//go:build !windows && !darwin && !linux
|
||||
|
||||
package memmod
|
||||
|
||||
import "errors"
|
||||
|
||||
type Module struct{}
|
||||
|
||||
func LoadLibrary(data []byte) (*Module, error) {
|
||||
_ = data
|
||||
return nil, errors.New("memmod is only supported on windows, darwin, and linux")
|
||||
}
|
||||
|
||||
func (module *Module) Free() {}
|
||||
|
||||
func (module *Module) CallExport(name string) error {
|
||||
_ = name
|
||||
return errors.New("memmod is only supported on windows, darwin, and linux")
|
||||
}
|
||||
|
||||
func (module *Module) ProcAddressByName(name string) (uintptr, error) {
|
||||
_ = name
|
||||
return 0, errors.New("memmod is only supported on windows, darwin, and linux")
|
||||
}
|
||||
|
||||
func (module *Module) ProcAddressByOrdinal(ordinal uint16) (uintptr, error) {
|
||||
_ = ordinal
|
||||
return 0, errors.New("memmod is only supported on windows, darwin, and linux")
|
||||
}
|
||||
Generated
Vendored
File renamed without changes.
Generated
Vendored
-1
@@ -1,5 +1,4 @@
|
||||
//go:build (windows && 386) || (windows && arm)
|
||||
// +build windows,386 windows,arm
|
||||
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
Generated
Vendored
File renamed without changes.
Generated
Vendored
-1
@@ -1,5 +1,4 @@
|
||||
//go:build (windows && amd64) || (windows && arm64)
|
||||
// +build windows,amd64 windows,arm64
|
||||
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
Generated
Vendored
File renamed without changes.
Generated
Vendored
File renamed without changes.
Generated
Vendored
File renamed without changes.
+42
@@ -0,0 +1,42 @@
|
||||
//go:build windows
|
||||
|
||||
package memmod
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// CallExport resolves and calls an exported zero-argument function.
|
||||
func (module *Module) CallExport(name string) error {
|
||||
name = strings.TrimSpace(name)
|
||||
if name == "" {
|
||||
return errors.New("export name cannot be empty")
|
||||
}
|
||||
|
||||
candidates := []string{name}
|
||||
if strings.HasPrefix(name, "_") {
|
||||
candidates = append(candidates, strings.TrimPrefix(name, "_"))
|
||||
} else {
|
||||
candidates = append(candidates, "_"+name)
|
||||
}
|
||||
|
||||
var (
|
||||
addr uintptr
|
||||
err error
|
||||
)
|
||||
for _, candidate := range candidates {
|
||||
addr, err = module.ProcAddressByName(candidate)
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("resolve export %q: %w", name, err)
|
||||
}
|
||||
|
||||
_, _, _ = syscall.SyscallN(addr)
|
||||
return nil
|
||||
}
|
||||
Generated
Vendored
File renamed without changes.
Generated
Vendored
-1
@@ -1,5 +1,4 @@
|
||||
//go:build (windows && 386) || (windows && arm)
|
||||
// +build windows,386 windows,arm
|
||||
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
Generated
Vendored
-1
@@ -1,5 +1,4 @@
|
||||
//go:build (windows && amd64) || (windows && arm64)
|
||||
// +build windows,amd64 windows,arm64
|
||||
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
+1
-1
@@ -29,7 +29,7 @@ loop:
|
||||
MOVD $NUM_ROUNDS, R21
|
||||
VLD1 (R11), [V30.S4, V31.S4]
|
||||
|
||||
// load contants
|
||||
// load constants
|
||||
// VLD4R (R10), [V0.S4, V1.S4, V2.S4, V3.S4]
|
||||
WORD $0x4D60E940
|
||||
|
||||
|
||||
+3
@@ -38,6 +38,9 @@ type chacha20poly1305 struct {
|
||||
|
||||
// New returns a ChaCha20-Poly1305 AEAD that uses the given 256-bit key.
|
||||
func New(key []byte) (cipher.AEAD, error) {
|
||||
if fips140Enforced() {
|
||||
return nil, errors.New("chacha20poly1305: use of ChaCha20Poly1305 is not allowed in FIPS 140-only mode")
|
||||
}
|
||||
if len(key) != KeySize {
|
||||
return nil, errors.New("chacha20poly1305: bad key length")
|
||||
}
|
||||
|
||||
+11
-5
@@ -20,7 +20,7 @@ func chacha20Poly1305Open(dst []byte, key []uint32, src, ad []byte) bool
|
||||
func chacha20Poly1305Seal(dst []byte, key []uint32, src, ad []byte)
|
||||
|
||||
var (
|
||||
useAVX2 = cpu.X86.HasAVX2 && cpu.X86.HasBMI2
|
||||
useAVX2 = cpu.X86.HasSSSE3 && cpu.X86.HasAVX2 && cpu.X86.HasBMI2
|
||||
)
|
||||
|
||||
// setupState writes a ChaCha20 input matrix to state. See
|
||||
@@ -47,7 +47,7 @@ func setupState(state *[16]uint32, key *[32]byte, nonce []byte) {
|
||||
}
|
||||
|
||||
func (c *chacha20poly1305) seal(dst, nonce, plaintext, additionalData []byte) []byte {
|
||||
if !cpu.X86.HasSSSE3 {
|
||||
if !useAVX2 {
|
||||
return c.sealGeneric(dst, nonce, plaintext, additionalData)
|
||||
}
|
||||
|
||||
@@ -56,14 +56,17 @@ func (c *chacha20poly1305) seal(dst, nonce, plaintext, additionalData []byte) []
|
||||
|
||||
ret, out := sliceForAppend(dst, len(plaintext)+16)
|
||||
if alias.InexactOverlap(out, plaintext) {
|
||||
panic("chacha20poly1305: invalid buffer overlap")
|
||||
panic("chacha20poly1305: invalid buffer overlap of output and input")
|
||||
}
|
||||
if alias.AnyOverlap(out, additionalData) {
|
||||
panic("chacha20poly1305: invalid buffer overlap of output and additional data")
|
||||
}
|
||||
chacha20Poly1305Seal(out[:], state[:], plaintext, additionalData)
|
||||
return ret
|
||||
}
|
||||
|
||||
func (c *chacha20poly1305) open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
|
||||
if !cpu.X86.HasSSSE3 {
|
||||
if !useAVX2 {
|
||||
return c.openGeneric(dst, nonce, ciphertext, additionalData)
|
||||
}
|
||||
|
||||
@@ -73,7 +76,10 @@ func (c *chacha20poly1305) open(dst, nonce, ciphertext, additionalData []byte) (
|
||||
ciphertext = ciphertext[:len(ciphertext)-16]
|
||||
ret, out := sliceForAppend(dst, len(ciphertext))
|
||||
if alias.InexactOverlap(out, ciphertext) {
|
||||
panic("chacha20poly1305: invalid buffer overlap")
|
||||
panic("chacha20poly1305: invalid buffer overlap of output and input")
|
||||
}
|
||||
if alias.AnyOverlap(out, additionalData) {
|
||||
panic("chacha20poly1305: invalid buffer overlap of output and additional data")
|
||||
}
|
||||
if !chacha20Poly1305Open(out, state[:], ciphertext, additionalData) {
|
||||
for i := range out {
|
||||
|
||||
+325
-4857
File diff suppressed because it is too large.
Load diff
+8
-2
@@ -31,7 +31,10 @@ func (c *chacha20poly1305) sealGeneric(dst, nonce, plaintext, additionalData []b
|
||||
ret, out := sliceForAppend(dst, len(plaintext)+poly1305.TagSize)
|
||||
ciphertext, tag := out[:len(plaintext)], out[len(plaintext):]
|
||||
if alias.InexactOverlap(out, plaintext) {
|
||||
panic("chacha20poly1305: invalid buffer overlap")
|
||||
panic("chacha20poly1305: invalid buffer overlap of output and input")
|
||||
}
|
||||
if alias.AnyOverlap(out, additionalData) {
|
||||
panic("chacha20poly1305: invalid buffer overlap of output and additional data")
|
||||
}
|
||||
|
||||
var polyKey [32]byte
|
||||
@@ -67,7 +70,10 @@ func (c *chacha20poly1305) openGeneric(dst, nonce, ciphertext, additionalData []
|
||||
|
||||
ret, out := sliceForAppend(dst, len(ciphertext))
|
||||
if alias.InexactOverlap(out, ciphertext) {
|
||||
panic("chacha20poly1305: invalid buffer overlap")
|
||||
panic("chacha20poly1305: invalid buffer overlap of output and input")
|
||||
}
|
||||
if alias.AnyOverlap(out, additionalData) {
|
||||
panic("chacha20poly1305: invalid buffer overlap of output and additional data")
|
||||
}
|
||||
if !p.Verify(tag) {
|
||||
for i := range out {
|
||||
|
||||
Generated
Vendored
+3
-5
@@ -2,10 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build go1.25
|
||||
//go:build !go1.26
|
||||
|
||||
package blake2b
|
||||
package chacha20poly1305
|
||||
|
||||
import "hash"
|
||||
|
||||
var _ hash.XOF = (*xof)(nil)
|
||||
func fips140Enforced() bool { return false }
|
||||
Generated
Vendored
+4
-4
@@ -2,10 +2,10 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build go1.25
|
||||
//go:build go1.26
|
||||
|
||||
package blake2b
|
||||
package chacha20poly1305
|
||||
|
||||
import "hash"
|
||||
import "crypto/fips140"
|
||||
|
||||
var _ hash.XOF = (*xof)(nil)
|
||||
func fips140Enforced() bool { return fips140.Enforced() }
|
||||
Loaded 100 of 856 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user