mirror of
https://github.com/JanDeDobbeleer/oh-my-posh.git
synced 2025-03-05 20:49:04 -08:00
feat(connection): new segment
BREAKING CHANGE: this will need a manual migration from the wifi segment to the new connection segment.
This commit is contained in:
parent
f60b1715bd
commit
4b6b128d74
|
@ -5,7 +5,6 @@ linters:
|
||||||
disable-all: true
|
disable-all: true
|
||||||
enable:
|
enable:
|
||||||
- bodyclose
|
- bodyclose
|
||||||
- deadcode
|
|
||||||
- depguard
|
- depguard
|
||||||
- dupl
|
- dupl
|
||||||
- errcheck
|
- errcheck
|
||||||
|
@ -28,12 +27,10 @@ linters:
|
||||||
- rowserrcheck
|
- rowserrcheck
|
||||||
- exportloopref
|
- exportloopref
|
||||||
- staticcheck
|
- staticcheck
|
||||||
- structcheck
|
|
||||||
- typecheck
|
- typecheck
|
||||||
- unconvert
|
- unconvert
|
||||||
- unparam
|
- unparam
|
||||||
- unused
|
- unused
|
||||||
- varcheck
|
|
||||||
- whitespace
|
- whitespace
|
||||||
- lll
|
- lll
|
||||||
linters-settings:
|
linters-settings:
|
||||||
|
|
|
@ -3,12 +3,11 @@
|
||||||
package color
|
package color
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"oh-my-posh/environment"
|
"oh-my-posh/environment"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetAccentColor(env environment.Environment) (*RGB, error) {
|
func GetAccentColor(env environment.Environment) (*RGB, error) {
|
||||||
return nil, errors.New("not implemented")
|
return nil, &environment.NotImplemented{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DefaultColors) SetAccentColor(env environment.Environment, defaultColor string) {
|
func (d *DefaultColors) SetAccentColor(env environment.Environment, defaultColor string) {
|
||||||
|
|
|
@ -96,6 +96,8 @@ const (
|
||||||
CMAKE SegmentType = "cmake"
|
CMAKE SegmentType = "cmake"
|
||||||
// CMD writes the output of a shell command
|
// CMD writes the output of a shell command
|
||||||
CMD SegmentType = "command"
|
CMD SegmentType = "command"
|
||||||
|
// CONNECTION writes a connection's information
|
||||||
|
CONNECTION SegmentType = "connection"
|
||||||
// CRYSTAL writes the active crystal version
|
// CRYSTAL writes the active crystal version
|
||||||
CRYSTAL SegmentType = "crystal"
|
CRYSTAL SegmentType = "crystal"
|
||||||
// DART writes the active dart version
|
// DART writes the active dart version
|
||||||
|
@ -192,8 +194,6 @@ const (
|
||||||
UI5TOOLING SegmentType = "ui5tooling"
|
UI5TOOLING SegmentType = "ui5tooling"
|
||||||
// WAKATIME writes tracked time spend in dev editors
|
// WAKATIME writes tracked time spend in dev editors
|
||||||
WAKATIME SegmentType = "wakatime"
|
WAKATIME SegmentType = "wakatime"
|
||||||
// WIFI writes details about the current WIFI connection
|
|
||||||
WIFI SegmentType = "wifi"
|
|
||||||
// WINREG queries the Windows registry.
|
// WINREG queries the Windows registry.
|
||||||
WINREG SegmentType = "winreg"
|
WINREG SegmentType = "winreg"
|
||||||
// WITHINGS queries the Withings API.
|
// WITHINGS queries the Withings API.
|
||||||
|
@ -277,6 +277,7 @@ func (segment *Segment) mapSegmentWithWriter(env environment.Environment) error
|
||||||
CF: &segments.Cf{},
|
CF: &segments.Cf{},
|
||||||
CFTARGET: &segments.CfTarget{},
|
CFTARGET: &segments.CfTarget{},
|
||||||
CMD: &segments.Cmd{},
|
CMD: &segments.Cmd{},
|
||||||
|
CONNECTION: &segments.Connection{},
|
||||||
CRYSTAL: &segments.Crystal{},
|
CRYSTAL: &segments.Crystal{},
|
||||||
CMAKE: &segments.Cmake{},
|
CMAKE: &segments.Cmake{},
|
||||||
DART: &segments.Dart{},
|
DART: &segments.Dart{},
|
||||||
|
@ -326,7 +327,6 @@ func (segment *Segment) mapSegmentWithWriter(env environment.Environment) error
|
||||||
TIME: &segments.Time{},
|
TIME: &segments.Time{},
|
||||||
UI5TOOLING: &segments.UI5Tooling{},
|
UI5TOOLING: &segments.UI5Tooling{},
|
||||||
WAKATIME: &segments.Wakatime{},
|
WAKATIME: &segments.Wakatime{},
|
||||||
WIFI: &segments.Wifi{},
|
|
||||||
WINREG: &segments.WindowsRegistry{},
|
WINREG: &segments.WindowsRegistry{},
|
||||||
WITHINGS: &segments.Withings{},
|
WITHINGS: &segments.Withings{},
|
||||||
YTM: &segments.Ytm{},
|
YTM: &segments.Ytm{},
|
||||||
|
|
|
@ -98,20 +98,27 @@ type WindowsRegistryValue struct {
|
||||||
String string
|
String string
|
||||||
}
|
}
|
||||||
|
|
||||||
type WifiType string
|
type NotImplemented struct{}
|
||||||
|
|
||||||
type WifiInfo struct {
|
func (n *NotImplemented) Error() string {
|
||||||
SSID string
|
return "not implemented"
|
||||||
Interface string
|
}
|
||||||
RadioType WifiType
|
|
||||||
PhysType WifiType
|
type ConnectionType string
|
||||||
Authentication WifiType
|
|
||||||
Cipher WifiType
|
const (
|
||||||
Channel int
|
ETHERNET ConnectionType = "ethernet"
|
||||||
ReceiveRate int
|
WIFI ConnectionType = "wifi"
|
||||||
TransmitRate int
|
CELLULAR ConnectionType = "cellular"
|
||||||
Signal int
|
BLUETOOTH ConnectionType = "bluetooth"
|
||||||
Error string
|
)
|
||||||
|
|
||||||
|
type Connection struct {
|
||||||
|
Name string
|
||||||
|
Type ConnectionType
|
||||||
|
TransmitRate uint64
|
||||||
|
ReceiveRate uint64
|
||||||
|
SSID string // Wi-Fi only
|
||||||
}
|
}
|
||||||
|
|
||||||
type TemplateCache struct {
|
type TemplateCache struct {
|
||||||
|
@ -182,7 +189,7 @@ type Environment interface {
|
||||||
InWSLSharedDrive() bool
|
InWSLSharedDrive() bool
|
||||||
ConvertToLinuxPath(path string) string
|
ConvertToLinuxPath(path string) string
|
||||||
ConvertToWindowsPath(path string) string
|
ConvertToWindowsPath(path string) string
|
||||||
WifiNetwork() (*WifiInfo, error)
|
Connection(connectionType ConnectionType) (*Connection, error)
|
||||||
TemplateCache() *TemplateCache
|
TemplateCache() *TemplateCache
|
||||||
LoadTemplateCache()
|
LoadTemplateCache()
|
||||||
Log(logType LogType, funcName, message string)
|
Log(logType LogType, funcName, message string)
|
||||||
|
@ -222,6 +229,7 @@ type ShellEnvironment struct {
|
||||||
fileCache *fileCache
|
fileCache *fileCache
|
||||||
tmplCache *TemplateCache
|
tmplCache *TemplateCache
|
||||||
logBuilder strings.Builder
|
logBuilder strings.Builder
|
||||||
|
networks []*Connection
|
||||||
}
|
}
|
||||||
|
|
||||||
func (env *ShellEnvironment) Init() {
|
func (env *ShellEnvironment) Init() {
|
||||||
|
|
|
@ -23,7 +23,7 @@ func (env *ShellEnvironment) Home() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (env *ShellEnvironment) QueryWindowTitles(processName, windowTitleRegex string) (string, error) {
|
func (env *ShellEnvironment) QueryWindowTitles(processName, windowTitleRegex string) (string, error) {
|
||||||
return "", errors.New("not implemented")
|
return "", &NotImplemented{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (env *ShellEnvironment) IsWsl() bool {
|
func (env *ShellEnvironment) IsWsl() bool {
|
||||||
|
@ -94,7 +94,7 @@ func (env *ShellEnvironment) CachePath() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (env *ShellEnvironment) WindowsRegistryKeyValue(path string) (*WindowsRegistryValue, error) {
|
func (env *ShellEnvironment) WindowsRegistryKeyValue(path string) (*WindowsRegistryValue, error) {
|
||||||
return nil, errors.New("not implemented")
|
return nil, &NotImplemented{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (env *ShellEnvironment) InWSLSharedDrive() bool {
|
func (env *ShellEnvironment) InWSLSharedDrive() bool {
|
||||||
|
@ -120,10 +120,6 @@ func (env *ShellEnvironment) ConvertToLinuxPath(path string) string {
|
||||||
return path
|
return path
|
||||||
}
|
}
|
||||||
|
|
||||||
func (env *ShellEnvironment) WifiNetwork() (*WifiInfo, error) {
|
|
||||||
return nil, errors.New("not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (env *ShellEnvironment) LookWinAppPath(file string) (string, error) {
|
func (env *ShellEnvironment) LookWinAppPath(file string) (string, error) {
|
||||||
return "", errors.New("not relevant")
|
return "", errors.New("not relevant")
|
||||||
}
|
}
|
||||||
|
@ -160,3 +156,11 @@ func (env *ShellEnvironment) DirIsWritable(path string) bool {
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (env *ShellEnvironment) Connection(connectionType ConnectionType) (*Connection, error) {
|
||||||
|
// added to disable the linting error, we can implement this later
|
||||||
|
if len(env.networks) == 0 {
|
||||||
|
return nil, &NotImplemented{}
|
||||||
|
}
|
||||||
|
return nil, &NotImplemented{}
|
||||||
|
}
|
||||||
|
|
|
@ -8,8 +8,6 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
"unicode/utf16"
|
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
"github.com/Azure/go-ansiterm/winterm"
|
"github.com/Azure/go-ansiterm/winterm"
|
||||||
"golang.org/x/sys/windows"
|
"golang.org/x/sys/windows"
|
||||||
|
@ -235,248 +233,6 @@ func (env *ShellEnvironment) ConvertToLinuxPath(path string) string {
|
||||||
return path
|
return path
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
|
||||||
hapi = syscall.NewLazyDLL("wlanapi.dll")
|
|
||||||
hWlanOpenHandle = hapi.NewProc("WlanOpenHandle")
|
|
||||||
hWlanCloseHandle = hapi.NewProc("WlanCloseHandle")
|
|
||||||
hWlanEnumInterfaces = hapi.NewProc("WlanEnumInterfaces")
|
|
||||||
hWlanQueryInterface = hapi.NewProc("WlanQueryInterface")
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
FHSS WifiType = "FHSS"
|
|
||||||
DSSS WifiType = "DSSS"
|
|
||||||
IR WifiType = "IR"
|
|
||||||
A WifiType = "802.11a"
|
|
||||||
HRDSSS WifiType = "HRDSSS"
|
|
||||||
G WifiType = "802.11g"
|
|
||||||
N WifiType = "802.11n"
|
|
||||||
AC WifiType = "802.11ac"
|
|
||||||
|
|
||||||
Infrastructure WifiType = "Infrastructure"
|
|
||||||
Independent WifiType = "Independent"
|
|
||||||
Any WifiType = "Any"
|
|
||||||
|
|
||||||
OpenSystem WifiType = "802.11 Open System"
|
|
||||||
SharedKey WifiType = "802.11 Shared Key"
|
|
||||||
WPA WifiType = "WPA"
|
|
||||||
WPAPSK WifiType = "WPA PSK"
|
|
||||||
WPANone WifiType = "WPA NONE"
|
|
||||||
WPA2 WifiType = "WPA2"
|
|
||||||
WPA2PSK WifiType = "WPA2 PSK"
|
|
||||||
Disabled WifiType = "disabled"
|
|
||||||
|
|
||||||
None WifiType = "None"
|
|
||||||
WEP40 WifiType = "WEP40"
|
|
||||||
TKIP WifiType = "TKIP"
|
|
||||||
CCMP WifiType = "CCMP"
|
|
||||||
WEP104 WifiType = "WEP104"
|
|
||||||
WEP WifiType = "WEP"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (env *ShellEnvironment) WifiNetwork() (*WifiInfo, error) {
|
|
||||||
env.Trace(time.Now(), "WifiNetwork")
|
|
||||||
// Open handle
|
|
||||||
var pdwNegotiatedVersion uint32
|
|
||||||
var phClientHandle uint32
|
|
||||||
e, _, err := hWlanOpenHandle.Call(uintptr(uint32(2)), uintptr(unsafe.Pointer(nil)), uintptr(unsafe.Pointer(&pdwNegotiatedVersion)), uintptr(unsafe.Pointer(&phClientHandle)))
|
|
||||||
if e != 0 {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// defer closing handle
|
|
||||||
defer func() {
|
|
||||||
_, _, _ = hWlanCloseHandle.Call(uintptr(phClientHandle), uintptr(unsafe.Pointer(nil)))
|
|
||||||
}()
|
|
||||||
|
|
||||||
// list interfaces
|
|
||||||
var interfaceList *WLAN_INTERFACE_INFO_LIST
|
|
||||||
e, _, err = hWlanEnumInterfaces.Call(uintptr(phClientHandle), uintptr(unsafe.Pointer(nil)), uintptr(unsafe.Pointer(&interfaceList)))
|
|
||||||
if e != 0 {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// use first interface that is connected
|
|
||||||
numberOfInterfaces := int(interfaceList.dwNumberOfItems)
|
|
||||||
infoSize := unsafe.Sizeof(interfaceList.InterfaceInfo[0])
|
|
||||||
for i := 0; i < numberOfInterfaces; i++ {
|
|
||||||
network := (*WLAN_INTERFACE_INFO)(unsafe.Pointer(uintptr(unsafe.Pointer(&interfaceList.InterfaceInfo[0])) + uintptr(i)*infoSize))
|
|
||||||
if network.isState != 1 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
return env.parseNetworkInterface(network, phClientHandle)
|
|
||||||
}
|
|
||||||
return nil, errors.New("Not connected")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (env *ShellEnvironment) parseNetworkInterface(network *WLAN_INTERFACE_INFO, clientHandle uint32) (*WifiInfo, error) {
|
|
||||||
info := WifiInfo{}
|
|
||||||
info.Interface = strings.TrimRight(string(utf16.Decode(network.strInterfaceDescription[:])), "\x00")
|
|
||||||
|
|
||||||
// Query wifi connection state
|
|
||||||
var dataSize uint16
|
|
||||||
var wlanAttr *WLAN_CONNECTION_ATTRIBUTES
|
|
||||||
e, _, err := hWlanQueryInterface.Call(uintptr(clientHandle),
|
|
||||||
uintptr(unsafe.Pointer(&network.InterfaceGuid)),
|
|
||||||
uintptr(7), // wlan_intf_opcode_current_connection
|
|
||||||
uintptr(unsafe.Pointer(nil)),
|
|
||||||
uintptr(unsafe.Pointer(&dataSize)),
|
|
||||||
uintptr(unsafe.Pointer(&wlanAttr)),
|
|
||||||
uintptr(unsafe.Pointer(nil)))
|
|
||||||
if e != 0 {
|
|
||||||
env.Log(Error, "parseNetworkInterface", "wlan_intf_opcode_current_connection error")
|
|
||||||
return &info, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// SSID
|
|
||||||
ssid := wlanAttr.wlanAssociationAttributes.dot11Ssid
|
|
||||||
if ssid.uSSIDLength > 0 {
|
|
||||||
info.SSID = string(ssid.ucSSID[0:ssid.uSSIDLength])
|
|
||||||
}
|
|
||||||
|
|
||||||
// see https://docs.microsoft.com/en-us/windows/win32/nativewifi/dot11-phy-type
|
|
||||||
switch wlanAttr.wlanAssociationAttributes.dot11PhyType {
|
|
||||||
case 1:
|
|
||||||
info.PhysType = FHSS
|
|
||||||
case 2:
|
|
||||||
info.PhysType = DSSS
|
|
||||||
case 3:
|
|
||||||
info.PhysType = IR
|
|
||||||
case 4:
|
|
||||||
info.PhysType = A
|
|
||||||
case 5:
|
|
||||||
info.PhysType = HRDSSS
|
|
||||||
case 6:
|
|
||||||
info.PhysType = G
|
|
||||||
case 7:
|
|
||||||
info.PhysType = N
|
|
||||||
case 8:
|
|
||||||
info.PhysType = AC
|
|
||||||
default:
|
|
||||||
info.PhysType = UNKNOWN
|
|
||||||
}
|
|
||||||
|
|
||||||
// see https://docs.microsoft.com/en-us/windows/win32/nativewifi/dot11-bss-type
|
|
||||||
switch wlanAttr.wlanAssociationAttributes.dot11BssType {
|
|
||||||
case 1:
|
|
||||||
info.RadioType = Infrastructure
|
|
||||||
case 2:
|
|
||||||
info.RadioType = Independent
|
|
||||||
default:
|
|
||||||
info.RadioType = Any
|
|
||||||
}
|
|
||||||
|
|
||||||
info.Signal = int(wlanAttr.wlanAssociationAttributes.wlanSignalQuality)
|
|
||||||
info.TransmitRate = int(wlanAttr.wlanAssociationAttributes.ulTxRate) / 1024
|
|
||||||
info.ReceiveRate = int(wlanAttr.wlanAssociationAttributes.ulRxRate) / 1024
|
|
||||||
|
|
||||||
// Query wifi channel
|
|
||||||
dataSize = 0
|
|
||||||
var channel *uint32
|
|
||||||
e, _, err = hWlanQueryInterface.Call(uintptr(clientHandle),
|
|
||||||
uintptr(unsafe.Pointer(&network.InterfaceGuid)),
|
|
||||||
uintptr(8), // wlan_intf_opcode_channel_number
|
|
||||||
uintptr(unsafe.Pointer(nil)),
|
|
||||||
uintptr(unsafe.Pointer(&dataSize)),
|
|
||||||
uintptr(unsafe.Pointer(&channel)),
|
|
||||||
uintptr(unsafe.Pointer(nil)))
|
|
||||||
if e != 0 {
|
|
||||||
env.Log(Error, "parseNetworkInterface", "wlan_intf_opcode_channel_number error")
|
|
||||||
return &info, err
|
|
||||||
}
|
|
||||||
info.Channel = int(*channel)
|
|
||||||
|
|
||||||
if wlanAttr.wlanSecurityAttributes.bSecurityEnabled <= 0 {
|
|
||||||
info.Authentication = Disabled
|
|
||||||
return &info, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// see https://docs.microsoft.com/en-us/windows/win32/nativewifi/dot11-auth-algorithm
|
|
||||||
switch wlanAttr.wlanSecurityAttributes.dot11AuthAlgorithm {
|
|
||||||
case 1:
|
|
||||||
info.Authentication = OpenSystem
|
|
||||||
case 2:
|
|
||||||
info.Authentication = SharedKey
|
|
||||||
case 3:
|
|
||||||
info.Authentication = WPA
|
|
||||||
case 4:
|
|
||||||
info.Authentication = WPAPSK
|
|
||||||
case 5:
|
|
||||||
info.Authentication = WPANone
|
|
||||||
case 6:
|
|
||||||
info.Authentication = WPA2
|
|
||||||
case 7:
|
|
||||||
info.Authentication = WPA2PSK
|
|
||||||
default:
|
|
||||||
info.Authentication = UNKNOWN
|
|
||||||
}
|
|
||||||
|
|
||||||
// see https://docs.microsoft.com/en-us/windows/win32/nativewifi/dot11-cipher-algorithm
|
|
||||||
switch wlanAttr.wlanSecurityAttributes.dot11CipherAlgorithm {
|
|
||||||
case 0:
|
|
||||||
info.Cipher = None
|
|
||||||
case 0x1:
|
|
||||||
info.Cipher = WEP40
|
|
||||||
case 0x2:
|
|
||||||
info.Cipher = TKIP
|
|
||||||
case 0x4:
|
|
||||||
info.Cipher = CCMP
|
|
||||||
case 0x5:
|
|
||||||
info.Cipher = WEP104
|
|
||||||
case 0x100:
|
|
||||||
info.Cipher = WPA
|
|
||||||
case 0x101:
|
|
||||||
info.Cipher = WEP
|
|
||||||
default:
|
|
||||||
info.Cipher = UNKNOWN
|
|
||||||
}
|
|
||||||
|
|
||||||
return &info, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type WLAN_INTERFACE_INFO_LIST struct { //nolint: revive
|
|
||||||
dwNumberOfItems uint32
|
|
||||||
dwIndex uint32 //nolint: unused
|
|
||||||
InterfaceInfo [1]WLAN_INTERFACE_INFO
|
|
||||||
}
|
|
||||||
|
|
||||||
type WLAN_INTERFACE_INFO struct { //nolint: revive
|
|
||||||
InterfaceGuid syscall.GUID //nolint: revive
|
|
||||||
strInterfaceDescription [256]uint16
|
|
||||||
isState uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
type WLAN_CONNECTION_ATTRIBUTES struct { //nolint: revive
|
|
||||||
isState uint32 //nolint: unused
|
|
||||||
wlanConnectionMode uint32 //nolint: unused
|
|
||||||
strProfileName [256]uint16 //nolint: unused
|
|
||||||
wlanAssociationAttributes WLAN_ASSOCIATION_ATTRIBUTES
|
|
||||||
wlanSecurityAttributes WLAN_SECURITY_ATTRIBUTES
|
|
||||||
}
|
|
||||||
|
|
||||||
type WLAN_ASSOCIATION_ATTRIBUTES struct { //nolint: revive
|
|
||||||
dot11Ssid DOT11_SSID
|
|
||||||
dot11BssType uint32
|
|
||||||
dot11Bssid [6]uint8 //nolint: unused
|
|
||||||
dot11PhyType uint32
|
|
||||||
uDot11PhyIndex uint32 //nolint: unused
|
|
||||||
wlanSignalQuality uint32
|
|
||||||
ulRxRate uint32
|
|
||||||
ulTxRate uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
type WLAN_SECURITY_ATTRIBUTES struct { //nolint: revive
|
|
||||||
bSecurityEnabled uint32
|
|
||||||
bOneXEnabled uint32 //nolint: unused
|
|
||||||
dot11AuthAlgorithm uint32
|
|
||||||
dot11CipherAlgorithm uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
type DOT11_SSID struct { //nolint: revive
|
|
||||||
uSSIDLength uint32
|
|
||||||
ucSSID [32]uint8
|
|
||||||
}
|
|
||||||
|
|
||||||
func (env *ShellEnvironment) DirIsWritable(path string) bool {
|
func (env *ShellEnvironment) DirIsWritable(path string) bool {
|
||||||
defer env.Trace(time.Now(), "DirIsWritable")
|
defer env.Trace(time.Now(), "DirIsWritable")
|
||||||
info, err := os.Stat(path)
|
info, err := os.Stat(path)
|
||||||
|
@ -498,3 +254,20 @@ func (env *ShellEnvironment) DirIsWritable(path string) bool {
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (env *ShellEnvironment) Connection(connectionType ConnectionType) (*Connection, error) {
|
||||||
|
if env.networks == nil {
|
||||||
|
networks := env.getConnections()
|
||||||
|
if len(networks) == 0 {
|
||||||
|
return nil, errors.New("No connections found")
|
||||||
|
}
|
||||||
|
env.networks = networks
|
||||||
|
}
|
||||||
|
for _, network := range env.networks {
|
||||||
|
if network.Type == connectionType {
|
||||||
|
return network, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
env.Log(Error, "network", fmt.Sprintf("Network type '%s' not found", connectionType))
|
||||||
|
return nil, &NotImplemented{}
|
||||||
|
}
|
||||||
|
|
|
@ -24,6 +24,9 @@ var (
|
||||||
|
|
||||||
psapi = syscall.NewLazyDLL("psapi.dll")
|
psapi = syscall.NewLazyDLL("psapi.dll")
|
||||||
getModuleBaseNameA = psapi.NewProc("GetModuleBaseNameA")
|
getModuleBaseNameA = psapi.NewProc("GetModuleBaseNameA")
|
||||||
|
|
||||||
|
iphlpapi = syscall.NewLazyDLL("iphlpapi.dll")
|
||||||
|
hGetIfTable2 = iphlpapi.NewProc("GetIfTable2")
|
||||||
)
|
)
|
||||||
|
|
||||||
// enumWindows call enumWindows from user32 and returns all active windows
|
// enumWindows call enumWindows from user32 and returns all active windows
|
||||||
|
@ -189,7 +192,242 @@ func readWinAppLink(path string) (string, error) {
|
||||||
rb := (*GenericDataBuffer)(unsafe.Pointer(&rdb.DUMMYUNIONNAME))
|
rb := (*GenericDataBuffer)(unsafe.Pointer(&rdb.DUMMYUNIONNAME))
|
||||||
appExecLink := (*AppExecLinkReparseBuffer)(unsafe.Pointer(&rb.DataBuffer))
|
appExecLink := (*AppExecLinkReparseBuffer)(unsafe.Pointer(&rb.DataBuffer))
|
||||||
if appExecLink.Version != 3 {
|
if appExecLink.Version != 3 {
|
||||||
return " ", errors.New("unknown AppExecLink version")
|
return "", errors.New("unknown AppExecLink version")
|
||||||
}
|
}
|
||||||
return appExecLink.Path()
|
return appExecLink.Path()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// networks
|
||||||
|
|
||||||
|
func (env *ShellEnvironment) getConnections() []*Connection {
|
||||||
|
var pIFTable2 *MIN_IF_TABLE2
|
||||||
|
_, _, _ = hGetIfTable2.Call(uintptr(unsafe.Pointer(&pIFTable2)))
|
||||||
|
|
||||||
|
SSIDs, _ := env.getAllWifiSSID()
|
||||||
|
networks := make([]*Connection, 0)
|
||||||
|
|
||||||
|
for i := 0; i < int(pIFTable2.NumEntries); i++ {
|
||||||
|
networkInterface := pIFTable2.Table[i]
|
||||||
|
alias := strings.TrimRight(syscall.UTF16ToString(networkInterface.Alias[:]), "\x00")
|
||||||
|
description := strings.TrimRight(syscall.UTF16ToString(networkInterface.Description[:]), "\x00")
|
||||||
|
|
||||||
|
if networkInterface.OperStatus != 1 || // not connected or functional
|
||||||
|
!networkInterface.InterfaceAndOperStatusFlags.HardwareInterface || // rule out software interfaces
|
||||||
|
strings.HasPrefix(alias, "Local Area Connection") || // not relevant
|
||||||
|
strings.Index(alias, "-") >= 3 { // rule out parts of Ethernet filter interfaces
|
||||||
|
// e.g. : "Ethernet-WFP Native MAC Layer LightWeight Filter-0000"
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var connectionType ConnectionType
|
||||||
|
switch networkInterface.Type {
|
||||||
|
case 6:
|
||||||
|
connectionType = ETHERNET
|
||||||
|
case 71:
|
||||||
|
connectionType = WIFI
|
||||||
|
case 237, 234, 244:
|
||||||
|
connectionType = CELLULAR
|
||||||
|
}
|
||||||
|
|
||||||
|
if networkInterface.PhysicalMediumType == 10 {
|
||||||
|
connectionType = BLUETOOTH
|
||||||
|
}
|
||||||
|
|
||||||
|
// skip connections which aren't relevant
|
||||||
|
if len(connectionType) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
network := &Connection{
|
||||||
|
Type: connectionType,
|
||||||
|
Name: description, // we want a relatable name, alias isn't that
|
||||||
|
TransmitRate: networkInterface.TransmitLinkSpeed,
|
||||||
|
ReceiveRate: networkInterface.ReceiveLinkSpeed,
|
||||||
|
}
|
||||||
|
|
||||||
|
if SSID, OK := SSIDs[network.Name]; OK {
|
||||||
|
network.SSID = SSID
|
||||||
|
}
|
||||||
|
|
||||||
|
networks = append(networks, network)
|
||||||
|
}
|
||||||
|
return networks
|
||||||
|
}
|
||||||
|
|
||||||
|
type MIN_IF_TABLE2 struct { //nolint: revive
|
||||||
|
NumEntries uint64
|
||||||
|
Table [256]MIB_IF_ROW2
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
IF_MAX_STRING_SIZE uint64 = 256 //nolint: revive
|
||||||
|
IF_MAX_PHYS_ADDRESS_LENGTH uint64 = 32 //nolint: revive
|
||||||
|
)
|
||||||
|
|
||||||
|
type MIB_IF_ROW2 struct { //nolint: revive
|
||||||
|
InterfaceLuid uint64
|
||||||
|
InterfaceIndex uint32
|
||||||
|
InterfaceGUID windows.GUID
|
||||||
|
Alias [IF_MAX_STRING_SIZE + 1]uint16
|
||||||
|
Description [IF_MAX_STRING_SIZE + 1]uint16
|
||||||
|
PhysicalAddressLength uint32
|
||||||
|
PhysicalAddress [IF_MAX_PHYS_ADDRESS_LENGTH]uint8
|
||||||
|
PermanentPhysicalAddress [IF_MAX_PHYS_ADDRESS_LENGTH]uint8
|
||||||
|
|
||||||
|
Mtu uint32
|
||||||
|
Type uint32
|
||||||
|
TunnelType uint32
|
||||||
|
MediaType uint32
|
||||||
|
PhysicalMediumType uint32
|
||||||
|
AccessType uint32
|
||||||
|
DirectionType uint32
|
||||||
|
|
||||||
|
InterfaceAndOperStatusFlags struct {
|
||||||
|
HardwareInterface bool
|
||||||
|
FilterInterface bool
|
||||||
|
ConnectorPresent bool
|
||||||
|
NotAuthenticated bool
|
||||||
|
NotMediaConnected bool
|
||||||
|
Paused bool
|
||||||
|
LowPower bool
|
||||||
|
EndPointInterface bool
|
||||||
|
}
|
||||||
|
|
||||||
|
OperStatus uint32
|
||||||
|
AdminStatus uint32
|
||||||
|
MediaConnectState uint32
|
||||||
|
NetworkGUID windows.GUID
|
||||||
|
ConnectionType uint32
|
||||||
|
|
||||||
|
TransmitLinkSpeed uint64
|
||||||
|
ReceiveLinkSpeed uint64
|
||||||
|
|
||||||
|
InOctets uint64
|
||||||
|
InUcastPkts uint64
|
||||||
|
InNUcastPkts uint64
|
||||||
|
InDiscards uint64
|
||||||
|
InErrors uint64
|
||||||
|
InUnknownProtos uint64
|
||||||
|
InUcastOctets uint64
|
||||||
|
InMulticastOctets uint64
|
||||||
|
InBroadcastOctets uint64
|
||||||
|
OutOctets uint64
|
||||||
|
OutUcastPkts uint64
|
||||||
|
OutNUcastPkts uint64
|
||||||
|
OutDiscards uint64
|
||||||
|
OutErrors uint64
|
||||||
|
OutUcastOctets uint64
|
||||||
|
OutMulticastOctets uint64
|
||||||
|
OutBroadcastOctets uint64
|
||||||
|
OutQLen uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (env *ShellEnvironment) getAllWifiSSID() (map[string]string, error) {
|
||||||
|
var pdwNegotiatedVersion uint32
|
||||||
|
var phClientHandle uint32
|
||||||
|
e, _, err := hWlanOpenHandle.Call(uintptr(uint32(2)), uintptr(unsafe.Pointer(nil)), uintptr(unsafe.Pointer(&pdwNegotiatedVersion)), uintptr(unsafe.Pointer(&phClientHandle)))
|
||||||
|
if e != 0 {
|
||||||
|
env.Log(Error, "getAllWifiSSID", err.Error())
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// defer closing handle
|
||||||
|
defer func() {
|
||||||
|
_, _, _ = hWlanCloseHandle.Call(uintptr(phClientHandle), uintptr(unsafe.Pointer(nil)))
|
||||||
|
}()
|
||||||
|
|
||||||
|
ssid := make(map[string]string)
|
||||||
|
// list interfaces
|
||||||
|
var interfaceList *WLAN_INTERFACE_INFO_LIST
|
||||||
|
e, _, err = hWlanEnumInterfaces.Call(uintptr(phClientHandle), uintptr(unsafe.Pointer(nil)), uintptr(unsafe.Pointer(&interfaceList)))
|
||||||
|
if e != 0 {
|
||||||
|
env.Log(Error, "getAllWifiSSID", err.Error())
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// use first interface that is connected
|
||||||
|
numberOfInterfaces := int(interfaceList.dwNumberOfItems)
|
||||||
|
infoSize := unsafe.Sizeof(interfaceList.InterfaceInfo[0])
|
||||||
|
for i := 0; i < numberOfInterfaces; i++ {
|
||||||
|
network := (*WLAN_INTERFACE_INFO)(unsafe.Pointer(uintptr(unsafe.Pointer(&interfaceList.InterfaceInfo[0])) + uintptr(i)*infoSize))
|
||||||
|
if network.isState == 1 {
|
||||||
|
wifiInterface := strings.TrimRight(string(utf16.Decode(network.strInterfaceDescription[:])), "\x00")
|
||||||
|
ssid[wifiInterface] = env.getWiFiSSID(network, phClientHandle)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ssid, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
wlanapi = syscall.NewLazyDLL("wlanapi.dll")
|
||||||
|
hWlanOpenHandle = wlanapi.NewProc("WlanOpenHandle")
|
||||||
|
hWlanCloseHandle = wlanapi.NewProc("WlanCloseHandle")
|
||||||
|
hWlanEnumInterfaces = wlanapi.NewProc("WlanEnumInterfaces")
|
||||||
|
hWlanQueryInterface = wlanapi.NewProc("WlanQueryInterface")
|
||||||
|
)
|
||||||
|
|
||||||
|
func (env *ShellEnvironment) getWiFiSSID(network *WLAN_INTERFACE_INFO, clientHandle uint32) string {
|
||||||
|
// Query wifi connection state
|
||||||
|
var dataSize uint16
|
||||||
|
var wlanAttr *WLAN_CONNECTION_ATTRIBUTES
|
||||||
|
e, _, _ := hWlanQueryInterface.Call(uintptr(clientHandle),
|
||||||
|
uintptr(unsafe.Pointer(&network.InterfaceGuid)),
|
||||||
|
uintptr(7), // wlan_intf_opcode_current_connection
|
||||||
|
uintptr(unsafe.Pointer(nil)),
|
||||||
|
uintptr(unsafe.Pointer(&dataSize)),
|
||||||
|
uintptr(unsafe.Pointer(&wlanAttr)),
|
||||||
|
uintptr(unsafe.Pointer(nil)))
|
||||||
|
if e != 0 {
|
||||||
|
env.Log(Error, "parseWlanInterface", "wlan_intf_opcode_current_connection error")
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
ssid := wlanAttr.wlanAssociationAttributes.dot11Ssid
|
||||||
|
if ssid.uSSIDLength <= 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return string(ssid.ucSSID[0:ssid.uSSIDLength])
|
||||||
|
}
|
||||||
|
|
||||||
|
type WLAN_INTERFACE_INFO_LIST struct { //nolint: revive
|
||||||
|
dwNumberOfItems uint32
|
||||||
|
dwIndex uint32 //nolint: unused
|
||||||
|
InterfaceInfo [256]WLAN_INTERFACE_INFO
|
||||||
|
}
|
||||||
|
|
||||||
|
type WLAN_INTERFACE_INFO struct { //nolint: revive
|
||||||
|
InterfaceGuid syscall.GUID //nolint: revive
|
||||||
|
strInterfaceDescription [256]uint16
|
||||||
|
isState uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
type WLAN_CONNECTION_ATTRIBUTES struct { //nolint: revive
|
||||||
|
isState uint32 //nolint: unused
|
||||||
|
wlanConnectionMode uint32 //nolint: unused
|
||||||
|
strProfileName [256]uint16 //nolint: unused
|
||||||
|
wlanAssociationAttributes WLAN_ASSOCIATION_ATTRIBUTES
|
||||||
|
wlanSecurityAttributes WLAN_SECURITY_ATTRIBUTES //nolint: unused
|
||||||
|
}
|
||||||
|
|
||||||
|
type WLAN_ASSOCIATION_ATTRIBUTES struct { //nolint: revive
|
||||||
|
dot11Ssid DOT11_SSID
|
||||||
|
dot11BssType uint32 //nolint: unused
|
||||||
|
dot11Bssid [6]uint8 //nolint: unused
|
||||||
|
dot11PhyType uint32 //nolint: unused
|
||||||
|
uDot11PhyIndex uint32 //nolint: unused
|
||||||
|
wlanSignalQuality uint32 //nolint: unused
|
||||||
|
ulRxRate uint32 //nolint: unused
|
||||||
|
ulTxRate uint32 //nolint: unused
|
||||||
|
}
|
||||||
|
|
||||||
|
type WLAN_SECURITY_ATTRIBUTES struct { //nolint: revive
|
||||||
|
bSecurityEnabled uint32 //nolint: unused
|
||||||
|
bOneXEnabled uint32 //nolint: unused
|
||||||
|
dot11AuthAlgorithm uint32 //nolint: unused
|
||||||
|
dot11CipherAlgorithm uint32 //nolint: unused
|
||||||
|
}
|
||||||
|
|
||||||
|
type DOT11_SSID struct { //nolint: revive
|
||||||
|
uSSIDLength uint32
|
||||||
|
ucSSID [32]uint8
|
||||||
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@ require (
|
||||||
github.com/hashicorp/hcl/v2 v2.14.0
|
github.com/hashicorp/hcl/v2 v2.14.0
|
||||||
github.com/mattn/go-runewidth v0.0.13
|
github.com/mattn/go-runewidth v0.0.13
|
||||||
github.com/spf13/cobra v1.5.0
|
github.com/spf13/cobra v1.5.0
|
||||||
golang.org/x/mod v0.5.1
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -60,7 +60,6 @@ require (
|
||||||
github.com/tklauser/go-sysconf v0.3.10 // indirect
|
github.com/tklauser/go-sysconf v0.3.10 // indirect
|
||||||
github.com/tklauser/numcpus v0.5.0 // indirect
|
github.com/tklauser/numcpus v0.5.0 // indirect
|
||||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
|
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
|
||||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
|
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
|
|
@ -222,8 +222,8 @@ golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0
|
||||||
golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561 h1:MDc5xs78ZrZr3HMQugiXOAkSZtfTpbJLDr/lwfgO53E=
|
golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561 h1:MDc5xs78ZrZr3HMQugiXOAkSZtfTpbJLDr/lwfgO53E=
|
||||||
golang.org/x/image v0.0.0-20220902085622-e7cb96979f69 h1:Lj6HJGCSn5AjxRAH2+r35Mir4icalbqku+CLUtjnvXY=
|
golang.org/x/image v0.0.0-20220902085622-e7cb96979f69 h1:Lj6HJGCSn5AjxRAH2+r35Mir4icalbqku+CLUtjnvXY=
|
||||||
golang.org/x/image v0.0.0-20220902085622-e7cb96979f69/go.mod h1:doUCurBvlfPMKfmIpRIywoHmhN3VyhnoFDbvIEWF4hY=
|
golang.org/x/image v0.0.0-20220902085622-e7cb96979f69/go.mod h1:doUCurBvlfPMKfmIpRIywoHmhN3VyhnoFDbvIEWF4hY=
|
||||||
golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38=
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
|
||||||
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||||
|
@ -265,8 +265,6 @@ golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk=
|
|
||||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
|
|
||||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
|
|
@ -208,9 +208,9 @@ func (env *MockedEnvironment) ConvertToLinuxPath(path string) string {
|
||||||
return args.String(0)
|
return args.String(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (env *MockedEnvironment) WifiNetwork() (*environment.WifiInfo, error) {
|
func (env *MockedEnvironment) Connection(connectionType environment.ConnectionType) (*environment.Connection, error) {
|
||||||
args := env.Called()
|
args := env.Called(connectionType)
|
||||||
return args.Get(0).(*environment.WifiInfo), args.Error(1)
|
return args.Get(0).(*environment.Connection), args.Error(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (env *MockedEnvironment) TemplateCache() *environment.TemplateCache {
|
func (env *MockedEnvironment) TemplateCache() *environment.TemplateCache {
|
||||||
|
|
|
@ -60,15 +60,7 @@ func (m Map) GetString(property Property, defaultValue string) string {
|
||||||
if !found {
|
if !found {
|
||||||
return defaultValue
|
return defaultValue
|
||||||
}
|
}
|
||||||
return ParseString(val, defaultValue)
|
return fmt.Sprint(val)
|
||||||
}
|
|
||||||
|
|
||||||
func ParseString(value interface{}, defaultValue string) string {
|
|
||||||
stringValue, ok := value.(string)
|
|
||||||
if !ok {
|
|
||||||
return defaultValue
|
|
||||||
}
|
|
||||||
return stringValue
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m Map) GetColor(property Property, defaultValue string) string {
|
func (m Map) GetColor(property Property, defaultValue string) string {
|
||||||
|
@ -76,7 +68,7 @@ func (m Map) GetColor(property Property, defaultValue string) string {
|
||||||
if !found {
|
if !found {
|
||||||
return defaultValue
|
return defaultValue
|
||||||
}
|
}
|
||||||
colorString := ParseString(val, defaultValue)
|
colorString := fmt.Sprint(val)
|
||||||
if color.IsAnsiColorName(colorString) {
|
if color.IsAnsiColorName(colorString) {
|
||||||
return colorString
|
return colorString
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ func TestGetStringNoEntry(t *testing.T) {
|
||||||
func TestGetStringNoTextEntry(t *testing.T) {
|
func TestGetStringNoTextEntry(t *testing.T) {
|
||||||
var properties = Map{Foo: true}
|
var properties = Map{Foo: true}
|
||||||
value := properties.GetString(Foo, expected)
|
value := properties.GetString(Foo, expected)
|
||||||
assert.Equal(t, expected, value)
|
assert.Equal(t, "true", value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetHexColor(t *testing.T) {
|
func TestGetHexColor(t *testing.T) {
|
||||||
|
|
41
src/segments/connection.go
Normal file
41
src/segments/connection.go
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
package segments
|
||||||
|
|
||||||
|
import (
|
||||||
|
"oh-my-posh/environment"
|
||||||
|
"oh-my-posh/properties"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Connection struct {
|
||||||
|
props properties.Properties
|
||||||
|
env environment.Environment
|
||||||
|
|
||||||
|
environment.Connection
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
Type properties.Property = "type"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c *Connection) Template() string {
|
||||||
|
return " {{ if eq .Type \"wifi\"}}\uf1eb{{ else if eq .Type \"ethernet\"}}\uf6ff{{ end }} "
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Connection) Enabled() bool {
|
||||||
|
types := c.props.GetString(Type, "wifi|ethernet")
|
||||||
|
connectionTypes := strings.Split(types, "|")
|
||||||
|
for _, connectionType := range connectionTypes {
|
||||||
|
network, err := c.env.Connection(environment.ConnectionType(connectionType))
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
c.Connection = *network
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Connection) Init(props properties.Properties, env environment.Environment) {
|
||||||
|
c.props = props
|
||||||
|
c.env = env
|
||||||
|
}
|
105
src/segments/connection_test.go
Normal file
105
src/segments/connection_test.go
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
package segments
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"oh-my-posh/environment"
|
||||||
|
"oh-my-posh/mock"
|
||||||
|
"oh-my-posh/properties"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestConnection(t *testing.T) {
|
||||||
|
type connectionResponse struct {
|
||||||
|
Connection *environment.Connection
|
||||||
|
Error error
|
||||||
|
}
|
||||||
|
cases := []struct {
|
||||||
|
Case string
|
||||||
|
ExpectedString string
|
||||||
|
ExpectedEnabled bool
|
||||||
|
ConnectionType string
|
||||||
|
Connections []*connectionResponse
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
Case: "WiFi only, enabled",
|
||||||
|
ExpectedString: "\uf1eb",
|
||||||
|
ExpectedEnabled: true,
|
||||||
|
ConnectionType: "wifi",
|
||||||
|
Connections: []*connectionResponse{
|
||||||
|
{
|
||||||
|
Connection: &environment.Connection{
|
||||||
|
Name: "WiFi",
|
||||||
|
Type: "wifi",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Case: "WiFi only, disabled",
|
||||||
|
ConnectionType: "wifi",
|
||||||
|
Connections: []*connectionResponse{
|
||||||
|
{
|
||||||
|
Connection: &environment.Connection{
|
||||||
|
Type: environment.WIFI,
|
||||||
|
},
|
||||||
|
Error: fmt.Errorf("no connection"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Case: "WiFi and Ethernet, enabled",
|
||||||
|
ConnectionType: "wifi|ethernet",
|
||||||
|
ExpectedString: "\uf6ff",
|
||||||
|
ExpectedEnabled: true,
|
||||||
|
Connections: []*connectionResponse{
|
||||||
|
{
|
||||||
|
Connection: &environment.Connection{
|
||||||
|
Type: environment.WIFI,
|
||||||
|
},
|
||||||
|
Error: fmt.Errorf("no connection"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Connection: &environment.Connection{
|
||||||
|
Type: environment.ETHERNET,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Case: "WiFi and Ethernet, disabled",
|
||||||
|
ConnectionType: "wifi|ethernet",
|
||||||
|
Connections: []*connectionResponse{
|
||||||
|
{
|
||||||
|
Connection: &environment.Connection{
|
||||||
|
Type: environment.WIFI,
|
||||||
|
},
|
||||||
|
Error: fmt.Errorf("no connection"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Connection: &environment.Connection{
|
||||||
|
Type: environment.ETHERNET,
|
||||||
|
},
|
||||||
|
Error: fmt.Errorf("no connection"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tc := range cases {
|
||||||
|
env := &mock.MockedEnvironment{}
|
||||||
|
for _, con := range tc.Connections {
|
||||||
|
env.On("Connection", con.Connection.Type).Return(con.Connection, con.Error)
|
||||||
|
}
|
||||||
|
c := &Connection{
|
||||||
|
env: env,
|
||||||
|
props: &properties.Map{
|
||||||
|
Type: tc.ConnectionType,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
assert.Equal(t, tc.ExpectedEnabled, c.Enabled(), fmt.Sprintf("Failed in case: %s", tc.Case))
|
||||||
|
if tc.ExpectedEnabled {
|
||||||
|
assert.Equal(t, tc.ExpectedString, renderTemplate(env, c.Template(), c), fmt.Sprintf("Failed in case: %s", tc.Case))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,7 +3,7 @@
|
||||||
package segments
|
package segments
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"oh-my-posh/environment"
|
||||||
"oh-my-posh/mock"
|
"oh-my-posh/mock"
|
||||||
"oh-my-posh/properties"
|
"oh-my-posh/properties"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -40,7 +40,7 @@ func TestSpotifyWindowsNative(t *testing.T) {
|
||||||
for _, tc := range cases {
|
for _, tc := range cases {
|
||||||
env := new(mock.MockedEnvironment)
|
env := new(mock.MockedEnvironment)
|
||||||
env.On("QueryWindowTitles", "spotify.exe", `^(Spotify.*)|(.*\s-\s.*)$`).Return(tc.Title, tc.Error)
|
env.On("QueryWindowTitles", "spotify.exe", `^(Spotify.*)|(.*\s-\s.*)$`).Return(tc.Title, tc.Error)
|
||||||
env.On("QueryWindowTitles", "msedge.exe", `^(Spotify.*)`).Return("", errors.New("not implemented"))
|
env.On("QueryWindowTitles", "msedge.exe", `^(Spotify.*)`).Return("", &environment.NotImplemented{})
|
||||||
s := &Spotify{
|
s := &Spotify{
|
||||||
env: env,
|
env: env,
|
||||||
props: properties.Map{},
|
props: properties.Map{},
|
||||||
|
@ -74,7 +74,7 @@ func TestSpotifyWindowsPWA(t *testing.T) {
|
||||||
}
|
}
|
||||||
for _, tc := range cases {
|
for _, tc := range cases {
|
||||||
env := new(mock.MockedEnvironment)
|
env := new(mock.MockedEnvironment)
|
||||||
env.On("QueryWindowTitles", "spotify.exe", "^(Spotify.*)|(.*\\s-\\s.*)$").Return("", errors.New("not implemented"))
|
env.On("QueryWindowTitles", "spotify.exe", "^(Spotify.*)|(.*\\s-\\s.*)$").Return("", &environment.NotImplemented{})
|
||||||
env.On("QueryWindowTitles", "msedge.exe", "^(Spotify.*)").Return(tc.Title, tc.Error)
|
env.On("QueryWindowTitles", "msedge.exe", "^(Spotify.*)").Return(tc.Title, tc.Error)
|
||||||
s := &Spotify{
|
s := &Spotify{
|
||||||
env: env,
|
env: env,
|
||||||
|
|
|
@ -1,46 +0,0 @@
|
||||||
package segments
|
|
||||||
|
|
||||||
import (
|
|
||||||
"oh-my-posh/environment"
|
|
||||||
"oh-my-posh/properties"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Wifi struct {
|
|
||||||
props properties.Properties
|
|
||||||
env environment.Environment
|
|
||||||
|
|
||||||
Error string
|
|
||||||
|
|
||||||
environment.WifiInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
defaultTemplate = " {{ if .Error }}{{ .Error }}{{ else }}\uFAA8 {{ .SSID }} {{ .Signal }}% {{ .ReceiveRate }}Mbps{{ end }} "
|
|
||||||
)
|
|
||||||
|
|
||||||
func (w *Wifi) Template() string {
|
|
||||||
return defaultTemplate
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *Wifi) Enabled() bool {
|
|
||||||
// This segment only supports Windows/WSL for now
|
|
||||||
if w.env.Platform() != environment.WINDOWS && !w.env.IsWsl() {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
wifiInfo, err := w.env.WifiNetwork()
|
|
||||||
displayError := w.props.GetBool(properties.DisplayError, false)
|
|
||||||
if err != nil && displayError {
|
|
||||||
w.Error = err.Error()
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if err != nil || wifiInfo == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
w.WifiInfo = *wifiInfo
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *Wifi) Init(props properties.Properties, env environment.Environment) {
|
|
||||||
w.props = props
|
|
||||||
w.env = env
|
|
||||||
}
|
|
|
@ -1,64 +0,0 @@
|
||||||
package segments
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"oh-my-posh/environment"
|
|
||||||
"oh-my-posh/mock"
|
|
||||||
"oh-my-posh/properties"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestWiFiSegment(t *testing.T) {
|
|
||||||
cases := []struct {
|
|
||||||
Case string
|
|
||||||
ExpectedString string
|
|
||||||
ExpectedEnabled bool
|
|
||||||
Network *environment.WifiInfo
|
|
||||||
WifiError error
|
|
||||||
DisplayError bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
Case: "No error and nil network",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Case: "Error and nil network",
|
|
||||||
WifiError: errors.New("oh noes"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Case: "Display error and nil network",
|
|
||||||
WifiError: errors.New("oh noes"),
|
|
||||||
ExpectedString: "oh noes",
|
|
||||||
DisplayError: true,
|
|
||||||
ExpectedEnabled: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Case: "Display wifi state",
|
|
||||||
ExpectedString: "pretty fly for a wifi",
|
|
||||||
ExpectedEnabled: true,
|
|
||||||
Network: &environment.WifiInfo{
|
|
||||||
SSID: "pretty fly for a wifi",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range cases {
|
|
||||||
env := new(mock.MockedEnvironment)
|
|
||||||
env.On("Platform").Return(environment.WINDOWS)
|
|
||||||
env.On("IsWsl").Return(false)
|
|
||||||
env.On("WifiNetwork").Return(tc.Network, tc.WifiError)
|
|
||||||
|
|
||||||
w := &Wifi{
|
|
||||||
env: env,
|
|
||||||
props: properties.Map{
|
|
||||||
properties.DisplayError: tc.DisplayError,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
assert.Equal(t, tc.ExpectedEnabled, w.Enabled(), tc.Case)
|
|
||||||
if tc.Network != nil || tc.DisplayError {
|
|
||||||
assert.Equal(t, tc.ExpectedString, renderTemplate(env, "{{ if .Error }}{{ .Error }}{{ else }}{{ .SSID }}{{ end }}", w), tc.Case)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -225,6 +225,7 @@
|
||||||
"angular",
|
"angular",
|
||||||
"battery",
|
"battery",
|
||||||
"command",
|
"command",
|
||||||
|
"connection",
|
||||||
"crystal",
|
"crystal",
|
||||||
"cds",
|
"cds",
|
||||||
"cf",
|
"cf",
|
||||||
|
@ -274,7 +275,6 @@
|
||||||
"terraform",
|
"terraform",
|
||||||
"ui5tooling",
|
"ui5tooling",
|
||||||
"wakatime",
|
"wakatime",
|
||||||
"wifi",
|
|
||||||
"winreg",
|
"winreg",
|
||||||
"withings",
|
"withings",
|
||||||
"ytm"
|
"ytm"
|
||||||
|
@ -575,6 +575,55 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"if": {
|
||||||
|
"properties": {
|
||||||
|
"type": {
|
||||||
|
"const": "connection"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"then": {
|
||||||
|
"title": "Connection Segment",
|
||||||
|
"description": "https://ohmyposh.dev/docs/segments/connection",
|
||||||
|
"properties": {
|
||||||
|
"properties": {
|
||||||
|
"properties": {
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"title": "Connection type",
|
||||||
|
"description": "The connection type to display",
|
||||||
|
"enum": [
|
||||||
|
"ethernet",
|
||||||
|
"wifi",
|
||||||
|
"cellular",
|
||||||
|
"bluetooth"
|
||||||
|
],
|
||||||
|
"default": "wifi|ethernet"
|
||||||
|
},
|
||||||
|
"unit": {
|
||||||
|
"type": "string",
|
||||||
|
"title": "Transfer speed unit",
|
||||||
|
"enum": [
|
||||||
|
"none",
|
||||||
|
"b",
|
||||||
|
"bps",
|
||||||
|
"K",
|
||||||
|
"Kbps",
|
||||||
|
"M",
|
||||||
|
"Mbps",
|
||||||
|
"G",
|
||||||
|
"Gbps",
|
||||||
|
"T",
|
||||||
|
"Tbps"
|
||||||
|
],
|
||||||
|
"default": "none"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"if": {
|
"if": {
|
||||||
"properties": {
|
"properties": {
|
||||||
|
@ -2164,19 +2213,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"if": {
|
|
||||||
"properties": {
|
|
||||||
"type": {
|
|
||||||
"const": "wifi"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"then": {
|
|
||||||
"title": "WiFi Segment",
|
|
||||||
"description": "https://ohmyposh.dev/docs/segments/wifi"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"if": {
|
"if": {
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
|
@ -85,7 +85,7 @@ go build -o $GOPATH/bin/oh-my-posh
|
||||||
|
|
||||||
## Add the documentation
|
## Add the documentation
|
||||||
|
|
||||||
Create a new `markdown` file underneath the [`docs/docs/segments`][docs] folder called `new.md`.
|
Create a new `markdown` file underneath the [`website/docs/segments`][docs] folder called `new.md`.
|
||||||
Use the following template as a guide.
|
Use the following template as a guide.
|
||||||
|
|
||||||
````markdown
|
````markdown
|
||||||
|
|
51
website/docs/segments/connection.mdx
Normal file
51
website/docs/segments/connection.mdx
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
---
|
||||||
|
id: connection
|
||||||
|
title: Connection
|
||||||
|
sidebar_label: Connection
|
||||||
|
---
|
||||||
|
|
||||||
|
## Connection
|
||||||
|
|
||||||
|
Show details about the currently connected network.
|
||||||
|
|
||||||
|
:::info
|
||||||
|
Currently only supports Windows. Pull requests for Darwin and Linux support are welcome :)
|
||||||
|
:::
|
||||||
|
|
||||||
|
## Sample Configuration
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "connection",
|
||||||
|
"style": "powerline",
|
||||||
|
"background": "#8822ee",
|
||||||
|
"foreground": "#222222",
|
||||||
|
"powerline_symbol": "\uE0B0"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Properties
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
| ------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
|
| `type` | `string` | the type of connection to display. Can be a single value or multiple joined by <inlineCode>\|</inlineCode> . The first to resolve is shown (**default value** is <inlineCode>wifi\|ethernet</inlineCode>). Possible values:<ul><li>`wifi`</li><li>`ethernet`</li><li>`bluetooth`</li><li>`cellular`</li></ul> |
|
||||||
|
|
||||||
|
## Template ([info][templates])
|
||||||
|
|
||||||
|
:::note default template
|
||||||
|
|
||||||
|
```template
|
||||||
|
{{ if eq .Type \"wifi\"}}\uf1eb{{ else if eq .Type \"ethernet\"}}\uf6ff{{ end }}
|
||||||
|
```
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
|
### Properties
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
| ------- | -------- | ------------------------------------------------------- |
|
||||||
|
| `.Type` | `string` | the connection type type. Single values of `type` above |
|
||||||
|
| `.Name` | `string` | the name of the connection |
|
||||||
|
| `.SSID` | `string` | the SSID of the current wifi network |
|
||||||
|
|
||||||
|
[templates]: /docs/configuration/templates
|
|
@ -24,13 +24,13 @@ Display the currently active golang version.
|
||||||
## Properties
|
## Properties
|
||||||
|
|
||||||
| Name | Type | Description |
|
| Name | Type | Description |
|
||||||
| ---------------------- | ---------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
| ---------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||||
| `home_enabled` | `boolean` | display the segment in the HOME folder or not - defaults to `false` |
|
| `home_enabled` | `boolean` | display the segment in the HOME folder or not - defaults to `false` |
|
||||||
| `fetch_version` | `boolean` | display the golang version - defaults to `true` |
|
| `fetch_version` | `boolean` | display the golang version - defaults to `true` |
|
||||||
| `missing_command_text` | `string` | text to display when the command is missing - defaults to empty |
|
| `missing_command_text` | `string` | text to display when the command is missing - defaults to empty |
|
||||||
| `display_mode` | `string` | <ul><li>`always`: the segment is always displayed</li><li>`files`: the segment is only displayed when `*.go` or `go.mod` files are present (**default**)</li></ul> |
|
| `display_mode` | `string` | <ul><li>`always`: the segment is always displayed</li><li>`files`: the segment is only displayed when `*.go` or `go.mod` files are present (**default**)</li></ul> |
|
||||||
| `version_url_template` | `string` | a go [text/template][go-text-template] [template][templates] that creates the URL of the version info / release notes |
|
| `version_url_template` | `string` | a go [text/template][go-text-template] [template][templates] that creates the URL of the version info / release notes |
|
||||||
| `parse_mod_file` | `boolean`: parse the go.mod file instead of calling `go version` |
|
| `parse_mod_file` | `boolean` | parse the go.mod file instead of calling `go version` |
|
||||||
|
|
||||||
## Template ([info][templates])
|
## Template ([info][templates])
|
||||||
|
|
||||||
|
|
|
@ -1,53 +0,0 @@
|
||||||
---
|
|
||||||
id: wifi
|
|
||||||
title: WiFi
|
|
||||||
sidebar_label: WiFi
|
|
||||||
---
|
|
||||||
|
|
||||||
## What
|
|
||||||
|
|
||||||
Show details about the currently connected WiFi network.
|
|
||||||
|
|
||||||
:::info
|
|
||||||
Currently only supports Windows and WSL. Pull requests for Darwin and Linux support are welcome :)
|
|
||||||
:::
|
|
||||||
|
|
||||||
## Sample Configuration
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"type": "wifi",
|
|
||||||
"style": "powerline",
|
|
||||||
"background": "#8822ee",
|
|
||||||
"foreground": "#222222",
|
|
||||||
"background_templates": [
|
|
||||||
"{{ if (lt .Signal 60) }}#DDDD11{{ else if (lt .Signal 90) }}#DD6611{{ else }}#11CC11{{ end }}"
|
|
||||||
],
|
|
||||||
"powerline_symbol": "\uE0B0",
|
|
||||||
"template": "\uFAA8 {{ .SSID }} {{ .Signal }}% {{ .ReceiveRate }}Mbps"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Template ([info][templates])
|
|
||||||
|
|
||||||
:::note default template
|
|
||||||
|
|
||||||
```template
|
|
||||||
{{ if .Error }}{{ .Error }}{{ else }}\uFAA8 {{ .SSID }} {{ .Signal }}% {{ .ReceiveRate }}Mbps{{ end }}
|
|
||||||
```
|
|
||||||
|
|
||||||
:::
|
|
||||||
|
|
||||||
### Properties
|
|
||||||
|
|
||||||
| Name | Type | Description |
|
|
||||||
| ----------------- | -------- | --------------------------------------------------------------------- |
|
|
||||||
| `.SSID` | `string` | the SSID of the current wifi network |
|
|
||||||
| `.RadioType` | `string` | the radio type - _e.g. 802.11ac, 802.11ax, 802.11n, etc._ |
|
|
||||||
| `.Authentication` | `string` | the authentication type - _e.g. WPA2-Personal, WPA2-Enterprise, etc._ |
|
|
||||||
| `.Channel` | `int` | the current channel number |
|
|
||||||
| `.ReceiveRate` | `int` | the receive rate (Mbps) |
|
|
||||||
| `.TransmitRate` | `int` | the transmit rate (Mbps) |
|
|
||||||
| `.Signal` | `int` | the signal strength (%) |
|
|
||||||
|
|
||||||
[templates]: /docs/configuration/templates
|
|
|
@ -58,10 +58,11 @@ module.exports = {
|
||||||
"segments/battery",
|
"segments/battery",
|
||||||
"segments/brewfather",
|
"segments/brewfather",
|
||||||
"segments/cds",
|
"segments/cds",
|
||||||
"segments/command",
|
|
||||||
"segments/cf",
|
"segments/cf",
|
||||||
"segments/cftarget",
|
"segments/cftarget",
|
||||||
"segments/cmake",
|
"segments/cmake",
|
||||||
|
"segments/command",
|
||||||
|
"segments/connection",
|
||||||
"segments/crystal",
|
"segments/crystal",
|
||||||
"segments/dart",
|
"segments/dart",
|
||||||
"segments/deno",
|
"segments/deno",
|
||||||
|
@ -110,7 +111,6 @@ module.exports = {
|
||||||
"segments/time",
|
"segments/time",
|
||||||
"segments/ui5tooling",
|
"segments/ui5tooling",
|
||||||
"segments/wakatime",
|
"segments/wakatime",
|
||||||
"segments/wifi",
|
|
||||||
"segments/withings",
|
"segments/withings",
|
||||||
"segments/winreg",
|
"segments/winreg",
|
||||||
"segments/ytm",
|
"segments/ytm",
|
||||||
|
|
Loading…
Reference in a new issue