Extend the system informations

This commit is contained in:
Zoltán Papp 2024-01-17 09:03:41 +01:00
parent 9fa0fbda0d
commit ef4a2ccbca
9 changed files with 286 additions and 12 deletions

119
client/system/chassis.go Normal file
View File

@ -0,0 +1,119 @@
package system
const (
ChassisTypeOther uint = 0x01 // Other
ChassisTypeUnknown uint = 0x02 // Unknown
ChassisTypeDesktop uint = 0x03 // Desktop
ChassisTypeLowProfileDesktop uint = 0x04 // Low Profile Desktop
ChassisTypePizzaBox uint = 0x05 // Pizza Box
ChassisTypeMiniTower uint = 0x06 // Mini Tower
ChassisTypeTower uint = 0x07 // Tower
ChassisTypePortable uint = 0x08 // Portable
ChassisTypeLaptop uint = 0x09 // Laptop
ChassisTypeNotebook uint = 0x0a // Notebook
ChassisTypeHandHeld uint = 0x0b // Hand Held
ChassisTypeDockingStation uint = 0x0c // Docking Station
ChassisTypeAllInOne uint = 0x0d // All in One
ChassisTypeSubNotebook uint = 0x0e // Sub Notebook
ChassisTypeSpacesaving uint = 0x0f // Space-saving
ChassisTypeLunchBox uint = 0x10 // Lunch Box
ChassisTypeMainServerChassis uint = 0x11 // Main Server Chassis
ChassisTypeExpansionChassis uint = 0x12 // Expansion Chassis
ChassisTypeSubChassis uint = 0x13 // SubChassis
ChassisTypeBusExpansionChassis uint = 0x14 // Bus Expansion Chassis
ChassisTypePeripheralChassis uint = 0x15 // Peripheral Chassis
ChassisTypeRAIDChassis uint = 0x16 // RAID Chassis
ChassisTypeRackMountChassis uint = 0x17 // Rack Mount Chassis
ChassisTypeSealedcasePC uint = 0x18 // Sealed-case PC
ChassisTypeMultisystemChassis uint = 0x19 // Multi-system chassis
ChassisTypeCompactPCI uint = 0x1a // Compact PCI
ChassisTypeAdvancedTCA uint = 0x1b // Advanced TCA
ChassisTypeBlade uint = 0x1c // Blade
ChassisTypeBladeChassis uint = 0x1d // Blade Chassis
ChassisTypeTablet uint = 0x1e // Tablet
ChassisTypeConvertible uint = 0x1f // Convertible
ChassisTypeDetachable uint = 0x20 // Detachable
ChassisTypeIoTGateway uint = 0x21 // IoT Gateway
ChassisTypeEmbeddedPC uint = 0x22 // Embedded PC
ChassisTypeMiniPC uint = 0x23 // Mini PC
ChassisTypeStickPC uint = 0x24 // Stick PC
)
func chassisTypeDesc(id uint) string {
switch id {
case ChassisTypeOther:
return "Other"
case ChassisTypeUnknown:
return "Unknown"
case ChassisTypeDesktop:
return "Desktop"
case ChassisTypeLowProfileDesktop:
return "Low Profile Desktop"
case ChassisTypePizzaBox:
return "Pizza Box"
case ChassisTypeMiniTower:
return "Mini Tower"
case ChassisTypeTower:
return "Tower"
case ChassisTypePortable:
return "Portable"
case ChassisTypeLaptop:
return "Laptop"
case ChassisTypeNotebook:
return "Notebook"
case ChassisTypeHandHeld:
return "Hand Held"
case ChassisTypeDockingStation:
return "Docking Station"
case ChassisTypeAllInOne:
return "All In One"
case ChassisTypeSubNotebook:
return "Sub Notebook"
case ChassisTypeSpacesaving:
return "Space-saving"
case ChassisTypeLunchBox:
return "Lunch Box"
case ChassisTypeMainServerChassis:
return "Main Server Chassis"
case ChassisTypeExpansionChassis:
return "Expansion Chassis"
case ChassisTypeSubChassis:
return "Sub Chassis"
case ChassisTypeBusExpansionChassis:
return "Bus Expansion Chassis"
case ChassisTypePeripheralChassis:
return "Peripheral Chassis"
case ChassisTypeRAIDChassis:
return "RAID Chassis"
case ChassisTypeRackMountChassis:
return "Rack Mount Chassis"
case ChassisTypeSealedcasePC:
return "Sealed-case PC"
case ChassisTypeMultisystemChassis:
return "Multi-system"
case ChassisTypeCompactPCI:
return "CompactPCI"
case ChassisTypeAdvancedTCA:
return "AdvancedTCA"
case ChassisTypeBlade:
return "Blade"
case ChassisTypeBladeChassis:
return "Blade Chassis"
case ChassisTypeTablet:
return "Tablet"
case ChassisTypeConvertible:
return "Convertible"
case ChassisTypeDetachable:
return "Detachable"
case ChassisTypeIoTGateway:
return "IoT Gateway"
case ChassisTypeEmbeddedPC:
return "Embedded PC"
case ChassisTypeMiniPC:
return "Mini PC"
case ChassisTypeStickPC:
return "Stick PC"
default:
return "Unknown"
}
}

View File

@ -31,6 +31,27 @@ type Info struct {
CPUs int CPUs int
WiretrusteeVersion string WiretrusteeVersion string
UIVersion string UIVersion string
BiosManufacturer string
BiosVersion string
ChassisType uint
ChassisTypeDesc string
ConnectionIp string
ConnectionMacAddress string
CPUSignature string
DefaultGatewayIp string
ExternalIp string
LastReboot string
LocalIp string
MacAddress string
KernelMajorVersion string
KernelMinorVersion string
OSBuild string
OSProductName string
ProductTypeDesc string
SerialNumber string
SystemManufacturer string
SystemProductName string
} }
// extractUserAgent extracts Netbird's agent (client) name and version from the outgoing context // extractUserAgent extracts Netbird's agent (client) name and version from the outgoing context

View File

@ -33,11 +33,23 @@ func GetInfo(ctx context.Context) *Info {
log.Warnf("got an error while retrieving macOS version with sw_vers, error: %s. Using darwin version instead.\n", err) log.Warnf("got an error while retrieving macOS version with sw_vers, error: %s. Using darwin version instead.\n", err)
swVersion = []byte(release) swVersion = []byte(release)
} }
gio := &Info{Kernel: sysName, OSVersion: strings.TrimSpace(string(swVersion)), Core: release, Platform: machine, OS: sysName, GoOS: runtime.GOOS, CPUs: runtime.NumCPU()}
systemHostname, _ := os.Hostname()
gio.Hostname = extractDeviceName(ctx, systemHostname)
gio.WiretrusteeVersion = version.NetbirdVersion()
gio.UIVersion = extractUserAgent(ctx)
systemHostname, _ := os.Hostname()
localAddr, macAddr := localAddresses()
gio := &Info{
Kernel: sysName,
OSVersion: strings.TrimSpace(string(swVersion)),
Core: release,
Platform: machine,
OS: sysName,
GoOS: runtime.GOOS,
CPUs: runtime.NumCPU(),
Hostname: extractDeviceName(ctx, systemHostname),
WiretrusteeVersion: version.NetbirdVersion(),
UIVersion: extractUserAgent(ctx),
LastReboot: lastReboot(),
LocalIp: localAddr,
MacAddress: macAddr,
}
return gio return gio
} }

View File

@ -13,6 +13,7 @@ import (
"time" "time"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"github.com/zcalusic/sysinfo"
"github.com/netbirdio/netbird/version" "github.com/netbirdio/netbird/version"
) )
@ -26,7 +27,7 @@ func GetInfo(ctx context.Context) *Info {
} }
releaseInfo := _getReleaseInfo() releaseInfo := _getReleaseInfo()
for strings.Contains(info, "broken pipe") { for strings.Contains(releaseInfo, "broken pipe") {
releaseInfo = _getReleaseInfo() releaseInfo = _getReleaseInfo()
time.Sleep(500 * time.Millisecond) time.Sleep(500 * time.Millisecond)
} }
@ -50,15 +51,51 @@ func GetInfo(ctx context.Context) *Info {
if osName == "" { if osName == "" {
osName = osInfo[3] osName = osInfo[3]
} }
gio := &Info{Kernel: osInfo[0], Core: osInfo[1], Platform: osInfo[2], OS: osName, OSVersion: osVer, GoOS: runtime.GOOS, CPUs: runtime.NumCPU()}
systemHostname, _ := os.Hostname() systemHostname, _ := os.Hostname()
gio.Hostname = extractDeviceName(ctx, systemHostname)
gio.WiretrusteeVersion = version.NetbirdVersion()
gio.UIVersion = extractUserAgent(ctx)
sysinfo := extendedInfo()
localAddr, macAddr := localAddresses()
gio := &Info{
Kernel: osInfo[0],
Core: osInfo[1],
Platform: osInfo[2],
OS: osName,
OSVersion: osVer,
GoOS: runtime.GOOS,
CPUs: runtime.NumCPU(),
Hostname: extractDeviceName(ctx, systemHostname),
WiretrusteeVersion: version.NetbirdVersion(),
UIVersion: extractUserAgent(ctx),
BiosManufacturer: sysinfo.BIOS.Vendor,
BiosVersion: sysinfo.BIOS.Version,
ChassisType: sysinfo.Chassis.Type,
ChassisTypeDesc: chassisTypeDesc(sysinfo.Chassis.Type), // make no sense to send the string to the server
/*
ConnectionIp: "", // "10.145.236.123",
ConnectionMacAddress: "", // 52-54-00-1a-31-05"
CPUSignature: "", // "198339"
*/
LastReboot: lastReboot(),
LocalIp: localAddr,
MacAddress: macAddr,
/*
OSBuild: string // 22621
OSProductName: string // "Windows 11 Home"
ProductTypeDesc: string // "Workstation"
SerialNumber: string // "MP1PKC2C""
SystemProductName: string // "81ND", # how to get this?
*/
SystemManufacturer: sysinfo.Product.Vendor, // todo validate
}
return gio return gio
} }
func extendedInfo() sysinfo.SysInfo {
var si sysinfo.SysInfo
si.GetSysInfo()
return si
}
func _getInfo() string { func _getInfo() string {
cmd := exec.Command("uname", "-srio") cmd := exec.Command("uname", "-srio")
cmd.Stdin = strings.NewReader("some") cmd.Stdin = strings.NewReader("some")

View File

@ -0,0 +1,13 @@
package system
import (
"context"
"testing"
log "github.com/sirupsen/logrus"
)
func TestGetInfo(t *testing.T) {
info := GetInfo(context.Background())
log.Infof("info: %+v", info)
}

42
client/system/ip.go Normal file
View File

@ -0,0 +1,42 @@
package system
import (
"net"
log "github.com/sirupsen/logrus"
)
func localAddresses() (string, string) {
conn, err := net.Dial("udp", "8.8.8.8:53")
if err != nil {
log.Errorf("failed to check ip: %s", err)
return "", ""
}
defer conn.Close()
localAddr := conn.LocalAddr().(*net.UDPAddr)
ifaces, err := net.Interfaces()
if err != nil {
log.Errorf("failed to list interfaces: %s", err)
return "", ""
}
for _, i := range ifaces {
addrs, err := i.Addrs()
if err != nil {
log.Errorf("failed to list addresses: %s", err)
continue
}
for _, addr := range addrs {
cidr, _, err := net.ParseCIDR(addr.String())
if err != nil {
continue
}
if localAddr.IP.String() == cidr.String() {
return addr.String(), i.HardwareAddr.String()
}
}
}
return "", ""
}

17
client/system/reboot.go Normal file
View File

@ -0,0 +1,17 @@
package system
import (
"time"
"github.com/shirou/gopsutil/host"
log "github.com/sirupsen/logrus"
)
func lastReboot() string {
info, err := host.Info()
if err != nil {
log.Errorf("failed to get boot time: %s", err)
return ""
}
return time.Unix(int64(info.BootTime), 0).String()
}

6
go.mod
View File

@ -22,7 +22,7 @@ require (
github.com/spf13/pflag v1.0.5 github.com/spf13/pflag v1.0.5
github.com/vishvananda/netlink v1.1.1-0.20211118161826-650dca95af54 github.com/vishvananda/netlink v1.1.1-0.20211118161826-650dca95af54
golang.org/x/crypto v0.14.0 golang.org/x/crypto v0.14.0
golang.org/x/sys v0.13.0 golang.org/x/sys v0.15.0
golang.zx2c4.com/wireguard v0.0.0-20230704135630-469159ecf7d1 golang.zx2c4.com/wireguard v0.0.0-20230704135630-469159ecf7d1
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6
golang.zx2c4.com/wireguard/windows v0.5.3 golang.zx2c4.com/wireguard/windows v0.5.3
@ -64,10 +64,12 @@ require (
github.com/pion/transport/v3 v3.0.1 github.com/pion/transport/v3 v3.0.1
github.com/prometheus/client_golang v1.14.0 github.com/prometheus/client_golang v1.14.0
github.com/rs/xid v1.3.0 github.com/rs/xid v1.3.0
github.com/shirou/gopsutil v3.21.11+incompatible
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966
github.com/stretchr/testify v1.8.4 github.com/stretchr/testify v1.8.4
github.com/things-go/go-socks5 v0.0.4 github.com/things-go/go-socks5 v0.0.4
github.com/yusufpapurcu/wmi v1.2.3 github.com/yusufpapurcu/wmi v1.2.3
github.com/zcalusic/sysinfo v1.0.2
go.opentelemetry.io/otel v1.11.1 go.opentelemetry.io/otel v1.11.1
go.opentelemetry.io/otel/exporters/prometheus v0.33.0 go.opentelemetry.io/otel/exporters/prometheus v0.33.0
go.opentelemetry.io/otel/metric v0.33.0 go.opentelemetry.io/otel/metric v0.33.0
@ -143,6 +145,8 @@ require (
github.com/spf13/cast v1.5.0 // indirect github.com/spf13/cast v1.5.0 // indirect
github.com/srwiley/oksvg v0.0.0-20200311192757-870daf9aa564 // indirect github.com/srwiley/oksvg v0.0.0-20200311192757-870daf9aa564 // indirect
github.com/srwiley/rasterx v0.0.0-20200120212402-85cb7272f5e9 // indirect github.com/srwiley/rasterx v0.0.0-20200120212402-85cb7272f5e9 // indirect
github.com/tklauser/go-sysconf v0.3.13 // indirect
github.com/tklauser/numcpus v0.7.0 // indirect
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect
github.com/yuin/goldmark v1.4.13 // indirect github.com/yuin/goldmark v1.4.13 // indirect
go.opencensus.io v0.24.0 // indirect go.opencensus.io v0.24.0 // indirect

11
go.sum
View File

@ -476,6 +476,8 @@ github.com/rs/xid v1.3.0 h1:6NjYksEUlhurdVehpc7S7dk6DAmcKv8V9gG0FsVN2U4=
github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
@ -519,6 +521,10 @@ github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcU
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/things-go/go-socks5 v0.0.4 h1:jMQjIc+qhD4z9cITOMnBiwo9dDmpGuXmBlkRFrl/qD0= github.com/things-go/go-socks5 v0.0.4 h1:jMQjIc+qhD4z9cITOMnBiwo9dDmpGuXmBlkRFrl/qD0=
github.com/things-go/go-socks5 v0.0.4/go.mod h1:sh4K6WHrmHZpjxLTCHyYtXYH8OUuD+yZun41NomR1IQ= github.com/things-go/go-socks5 v0.0.4/go.mod h1:sh4K6WHrmHZpjxLTCHyYtXYH8OUuD+yZun41NomR1IQ=
github.com/tklauser/go-sysconf v0.3.13 h1:GBUpcahXSpR2xN01jhkNAbTLRk2Yzgggk8IM08lq3r4=
github.com/tklauser/go-sysconf v0.3.13/go.mod h1:zwleP4Q4OehZHGn4CYZDipCgg9usW5IJePewFCGVEa0=
github.com/tklauser/numcpus v0.7.0 h1:yjuerZP127QG9m5Zh/mSO4wqurYil27tHrqwRoRjpr4=
github.com/tklauser/numcpus v0.7.0/go.mod h1:bb6dMVcj8A42tSE7i32fsIUCbQNllK5iDguyOZRUzAY=
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
@ -537,6 +543,8 @@ github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw=
github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
github.com/zcalusic/sysinfo v1.0.2 h1:nwTTo2a+WQ0NXwo0BGRojOJvJ/5XKvQih+2RrtWqfxc=
github.com/zcalusic/sysinfo v1.0.2/go.mod h1:kluzTYflRWo6/tXVMJPdEjShsbPpsFRyy+p1mBQPC30=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
@ -755,8 +763,9 @@ golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=