diff --git a/CHANGELOG.md b/CHANGELOG.md index 44fd5a7..1c5564f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -67,4 +67,13 @@ # v0.7.1 -1. vnc页面支持远程设置或读取剪贴板(仅支持文本内容) \ No newline at end of file +1. vnc页面支持远程设置或读取剪贴板(仅支持文本内容) + +# v0.7.2 + +1. 截屏库统一抽取到https://github.com/lwch/rdesktop +2. 修正windows下的错误日志显示格式问题 +3. 修正windows下的配置文件include问题 +4. 支持linux远程桌面 + +**注:linux受控端需使用np-cli.vnc程序进行启动,且目前无法以systemd等方式运行** \ No newline at end of file diff --git a/README.md b/README.md index 7be4840..dc7f55d 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,18 @@ windows11远程桌面 ![win11-vnc](docs/imgs/vnc_win11.png) +ubuntu远程桌面 + +![ubuntu-vnc](docs/imgs/vnc_ubuntu.png) + +fedora远程桌面 + +![fedora-vnc](docs/imgs/vnc_fedora.png) + +deepin远程桌面 + +![deepin-vnc](docs/imgs/vnc_deepin.png) + windows读取剪贴板内容 ![vnc-clipboard](docs/imgs/vnc_clipboard.png) diff --git a/build b/build index 188cf3f..0880598 100755 --- a/build +++ b/build @@ -1,6 +1,6 @@ #!/bin/sh -VERSION=0.7.1 +VERSION=0.7.2 DOCKER_BUILDKIT=1 docker build -t natpass -f contrib/build/Dockerfile . docker run --rm \ diff --git a/build_all b/build_all index f1f0def..a7c79bd 100755 --- a/build_all +++ b/build_all @@ -1,6 +1,6 @@ #!/bin/sh -VERSION=0.7.1 +VERSION=0.7.2 DOCKER_BUILDKIT=1 docker build -t natpass -f contrib/build/Dockerfile . docker run --rm \ diff --git a/code/client/rule/vnc/define/gdi32_windows.go b/code/client/rule/vnc/define/gdi32_windows.go deleted file mode 100644 index 64271a2..0000000 --- a/code/client/rule/vnc/define/gdi32_windows.go +++ /dev/null @@ -1,44 +0,0 @@ -package define - -import "syscall" - -var ( - libGdi32, _ = syscall.LoadLibrary("Gdi32.dll") - // FuncGetDeviceCaps https://docs.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-getdevicecaps - FuncGetDeviceCaps, _ = syscall.GetProcAddress(syscall.Handle(libGdi32), "GetDeviceCaps") - // FuncCreateCompatibleDC https://docs.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-createcompatibledc - FuncCreateCompatibleDC, _ = syscall.GetProcAddress(syscall.Handle(libGdi32), "CreateCompatibleDC") - // FuncCreateCompatibleBitmap https://docs.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-createcompatiblebitmap - FuncCreateCompatibleBitmap, _ = syscall.GetProcAddress(syscall.Handle(libGdi32), "CreateCompatibleBitmap") - // FuncSelectObject https://docs.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-selectobject - FuncSelectObject, _ = syscall.GetProcAddress(syscall.Handle(libGdi32), "SelectObject") - // FuncDeleteDC https://docs.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-deletedc - FuncDeleteDC, _ = syscall.GetProcAddress(syscall.Handle(libGdi32), "DeleteDC") - // FuncDeleteObject https://docs.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-deleteobject - FuncDeleteObject, _ = syscall.GetProcAddress(syscall.Handle(libGdi32), "DeleteObject") - // FuncBitBlt https://docs.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-bitblt - FuncBitBlt, _ = syscall.GetProcAddress(syscall.Handle(libGdi32), "BitBlt") - // FuncGetDIBits https://docs.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-getdibits - FuncGetDIBits, _ = syscall.GetProcAddress(syscall.Handle(libGdi32), "GetDIBits") -) - -const ( - // HORZRES https://docs.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-getdevicecaps - HORZRES = 8 - // VERTRES https://docs.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-getdevicecaps - VERTRES = 10 - // BITSPIXEL https://docs.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-getdevicecaps - BITSPIXEL = 12 -) - -const ( - // SRCCOPY https://docs.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-bitblt - SRCCOPY = 0x00CC0020 -) - -const ( - // BIRGB https://docs.microsoft.com/en-us/previous-versions/dd183376(v=vs.85) - BIRGB = 0 - // DIBRGBCOLORS https://docs.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-getdibits - DIBRGBCOLORS = 0 -) diff --git a/code/client/rule/vnc/define/kernel32_windows.go b/code/client/rule/vnc/define/kernel32_windows.go index b3e0970..d01c505 100644 --- a/code/client/rule/vnc/define/kernel32_windows.go +++ b/code/client/rule/vnc/define/kernel32_windows.go @@ -6,24 +6,7 @@ var ( libKernel32, _ = syscall.LoadLibrary("kernel32.dll") // FuncWTSGetActiveConsoleSessionID https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-wtsgetactiveconsolesessionid FuncWTSGetActiveConsoleSessionID, _ = syscall.GetProcAddress(syscall.Handle(libKernel32), "WTSGetActiveConsoleSessionId") - // FuncGlobalAlloc https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-globalalloc - FuncGlobalAlloc, _ = syscall.GetProcAddress(syscall.Handle(libKernel32), "GlobalAlloc") - // FuncGlobalFree https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-globalfree - FuncGlobalFree, _ = syscall.GetProcAddress(syscall.Handle(libKernel32), "GlobalFree") ) // PROCESSALLACCESS https://docs.microsoft.com/en-us/windows/win32/procthread/process-security-and-access-rights const PROCESSALLACCESS = 0x1F0FFF - -const ( - // GHND https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-globalalloc - GHND = 0x0042 - // GMEMFIXED https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-globalalloc - GMEMFIXED = 0x0000 - // GMEMMOVEABLE https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-globalalloc - GMEMMOVEABLE = 0x0002 - // GMEMZEROINIT https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-globalalloc - GMEMZEROINIT = 0x0040 - // GPTR https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-globalalloc - GPTR = 0x0040 -) diff --git a/code/client/rule/vnc/define/user32_windows.go b/code/client/rule/vnc/define/user32_windows.go index 9fde20a..e0b612d 100644 --- a/code/client/rule/vnc/define/user32_windows.go +++ b/code/client/rule/vnc/define/user32_windows.go @@ -4,67 +4,12 @@ import "syscall" var ( libUser32, _ = syscall.LoadLibrary("user32.dll") + // FuncGetThreadDesktop https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getthreaddesktop + FuncGetThreadDesktop, _ = syscall.GetProcAddress(syscall.Handle(libUser32), "GetThreadDesktop") // FuncOpenInputDesktop https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-openinputdesktop FuncOpenInputDesktop, _ = syscall.GetProcAddress(syscall.Handle(libUser32), "OpenInputDesktop") // FuncSetThreadDesktop https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setthreaddesktop FuncSetThreadDesktop, _ = syscall.GetProcAddress(syscall.Handle(libUser32), "SetThreadDesktop") - // FuncGetThreadDesktop https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getthreaddesktop - FuncGetThreadDesktop, _ = syscall.GetProcAddress(syscall.Handle(libUser32), "GetThreadDesktop") // FuncCloseDesktop https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-closedesktop FuncCloseDesktop, _ = syscall.GetProcAddress(syscall.Handle(libUser32), "CloseDesktop") - // FuncGetDesktopWindow https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getdesktopwindow - FuncGetDesktopWindow, _ = syscall.GetProcAddress(syscall.Handle(libUser32), "GetDesktopWindow") - // FuncGetDC https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getdc - FuncGetDC, _ = syscall.GetProcAddress(syscall.Handle(libUser32), "GetDC") - // FuncReleaseDC https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-releasedc - FuncReleaseDC, _ = syscall.GetProcAddress(syscall.Handle(libUser32), "ReleaseDC") - // FuncGetCursorInfo https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getcursorinfo - FuncGetCursorInfo, _ = syscall.GetProcAddress(syscall.Handle(libUser32), "GetCursorInfo") - // FuncGetIconInfo https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-geticoninfo - FuncGetIconInfo, _ = syscall.GetProcAddress(syscall.Handle(libUser32), "GetIconInfo") - // FuncDrawIcon https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-drawicon - FuncDrawIcon, _ = syscall.GetProcAddress(syscall.Handle(libUser32), "DrawIcon") -) - -type ( - // HANDLE handle object - HANDLE uintptr - // BOOL bool - BOOL int32 - // DWORD double word - DWORD uint32 - // LONG long - LONG int32 - // HCURSOR cursor handle - HCURSOR HANDLE - // HBITMAP bitmap handle - HBITMAP HANDLE -) - -// POINT pointer -type POINT struct { - X LONG - Y LONG -} - -// CURSORINFO cursor info -type CURSORINFO struct { - CbSize DWORD - Flags DWORD - HCursor HCURSOR - PTScreenPos POINT -} - -// ICONINFO icon info -type ICONINFO struct { - FIcon BOOL - XHotspot DWORD - YHotspot DWORD - HbmMask HBITMAP - HbmColor HBITMAP -} - -const ( - // CURSORSHOWING https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-cursorinfo - CURSORSHOWING = 0x00000001 ) diff --git a/code/client/rule/vnc/process/process.go b/code/client/rule/vnc/process/process.go index 722b7fe..7560048 100644 --- a/code/client/rule/vnc/process/process.go +++ b/code/client/rule/vnc/process/process.go @@ -3,12 +3,15 @@ package process import ( "errors" "fmt" + "image" + "image/jpeg" "natpass/code/client/rule/vnc/vncnetwork" "natpass/code/utils" "net" "net/http" "os" "sync" + "time" "github.com/gorilla/websocket" "github.com/lwch/logging" @@ -112,3 +115,61 @@ func (p *Process) kill() { ps.Kill() } } + +// Close close process +func (p *Process) Close() { + if p.srv != nil { + p.srv.Close() + } + if p.chImage != nil { + close(p.chImage) + p.chImage = nil + } + if p.chClipboard != nil { + close(p.chClipboard) + p.chClipboard = nil + } + if p.chWrite != nil { + close(p.chWrite) + p.chWrite = nil + } + p.kill() +} + +// Capture capture desktop image +func (p *Process) Capture(timeout time.Duration) (*image.RGBA, error) { + var msg vncnetwork.VncMsg + msg.XType = vncnetwork.VncMsg_capture_req + p.chWrite <- &msg + trans := func(data *vncnetwork.ImageData) *image.RGBA { + img := image.NewRGBA(image.Rect(0, 0, int(data.GetWidth()), int(data.GetHeight()))) + copy(img.Pix, data.GetData()) + // dumpImage(img) + return img + } + if timeout > 0 { + select { + case data := <-p.chImage: + return trans(data), nil + case <-time.After(timeout): + return nil, errors.New("timeout") + } + } else { + data := <-p.chImage + return trans(data), nil + } +} + +func dumpImage(img image.Image) { + f, err := os.Create(`C:\Users\lwch\Pictures\debug.jpeg`) + if err != nil { + logging.Error("debug: %v", err) + return + } + defer f.Close() + err = jpeg.Encode(f, img, nil) + if err != nil { + logging.Error("encode: %v", err) + return + } +} diff --git a/code/client/rule/vnc/process/process_darwin.go b/code/client/rule/vnc/process/process_darwin.go new file mode 100644 index 0000000..c640fce --- /dev/null +++ b/code/client/rule/vnc/process/process_darwin.go @@ -0,0 +1,6 @@ +package process + +// CreateWorker create worker process +func CreateWorker(name, confDir string, showCursor bool) (*Process, error) { + return nil, ErrNotSupported +} diff --git a/code/client/rule/vnc/process/process_linux.go b/code/client/rule/vnc/process/process_linux.go new file mode 100644 index 0000000..e043a0b --- /dev/null +++ b/code/client/rule/vnc/process/process_linux.go @@ -0,0 +1,34 @@ +package process + +import ( + "fmt" + "natpass/code/client/rule/vnc/vncnetwork" + "os" + "os/exec" +) + +// CreateWorker create worker process +func CreateWorker(name, confDir string, showCursor bool) (*Process, error) { + dir, err := os.Executable() + if err != nil { + return nil, err + } + var p Process + p.chWrite = make(chan *vncnetwork.VncMsg) + p.chImage = make(chan *vncnetwork.ImageData) + p.chClipboard = make(chan *vncnetwork.ClipboardData) + port, err := p.listenAndServe() + if err != nil { + return nil, err + } + cmd := exec.Command(dir, "-conf", confDir, + "-action", "vnc.worker", + "-name", name, + "-vport", fmt.Sprintf("%d", port)) + err = cmd.Start() + if err != nil { + p.Close() + return nil, err + } + return &p, nil +} diff --git a/code/client/rule/vnc/process/process_windows.go b/code/client/rule/vnc/process/process_windows.go index 9f6204d..879a93b 100644 --- a/code/client/rule/vnc/process/process_windows.go +++ b/code/client/rule/vnc/process/process_windows.go @@ -1,20 +1,15 @@ package process import ( - "errors" "fmt" - "image" - "image/jpeg" "natpass/code/client/rule/vnc/define" "natpass/code/client/rule/vnc/vncnetwork" "os" "strings" "syscall" - "time" "unicode/utf16" "unsafe" - "github.com/lwch/logging" "golang.org/x/sys/windows" ) @@ -123,61 +118,3 @@ func createWorker(name, confDir string, tk windows.Token, showCursor bool) (*Pro p.pid = int(process.ProcessId) return &p, nil } - -// Close close process -func (p *Process) Close() { - if p.srv != nil { - p.srv.Close() - } - if p.chImage != nil { - close(p.chImage) - p.chImage = nil - } - if p.chClipboard != nil { - close(p.chClipboard) - p.chClipboard = nil - } - if p.chWrite != nil { - close(p.chWrite) - p.chWrite = nil - } - p.kill() -} - -// Capture capture desktop image -func (p *Process) Capture(timeout time.Duration) (*image.RGBA, error) { - var msg vncnetwork.VncMsg - msg.XType = vncnetwork.VncMsg_capture_req - p.chWrite <- &msg - trans := func(data *vncnetwork.ImageData) *image.RGBA { - img := image.NewRGBA(image.Rect(0, 0, int(data.GetWidth()), int(data.GetHeight()))) - copy(img.Pix, data.GetData()) - // dumpImage(img) - return img - } - if timeout > 0 { - select { - case data := <-p.chImage: - return trans(data), nil - case <-time.After(timeout): - return nil, errors.New("timeout") - } - } else { - data := <-p.chImage - return trans(data), nil - } -} - -func dumpImage(img image.Image) { - f, err := os.Create(`C:\Users\lwch\Pictures\debug.jpeg`) - if err != nil { - logging.Error("debug: %v", err) - return - } - defer f.Close() - err = jpeg.Encode(f, img, nil) - if err != nil { - logging.Error("encode: %v", err) - return - } -} diff --git a/code/client/rule/vnc/process/process_xx.go b/code/client/rule/vnc/process/process_xx.go deleted file mode 100644 index b2e6eaf..0000000 --- a/code/client/rule/vnc/process/process_xx.go +++ /dev/null @@ -1,23 +0,0 @@ -//go:build !windows -// +build !windows - -package process - -import ( - "image" - "time" -) - -// CreateWorker create worker process -func CreateWorker(name, confDir string, showCursor bool) (*Process, error) { - return nil, ErrNotSupported -} - -// Close close process -func (p *Process) Close() { -} - -// Capture capture desktop image -func (p *Process) Capture(timeout time.Duration) (*image.RGBA, error) { - return nil, nil -} diff --git a/code/client/rule/vnc/worker/attach_windows.go b/code/client/rule/vnc/worker/attach_windows.go new file mode 100644 index 0000000..a0e5866 --- /dev/null +++ b/code/client/rule/vnc/worker/attach_windows.go @@ -0,0 +1,39 @@ +package worker + +import ( + "fmt" + "natpass/code/client/rule/vnc/define" + "runtime" + "syscall" + + "golang.org/x/sys/windows" +) + +func attachDesktop() (func(), error) { + runtime.LockOSThread() + locked := true + oldDesktop, _, err := syscall.Syscall(define.FuncGetThreadDesktop, 1, uintptr(windows.GetCurrentThreadId()), 0, 0) + if oldDesktop == 0 { + runtime.UnlockOSThread() + return nil, fmt.Errorf("get thread desktop: %v", err) + } + desktop, _, err := syscall.Syscall(define.FuncOpenInputDesktop, 3, 0, 0, windows.GENERIC_ALL) + if desktop == 0 { + runtime.UnlockOSThread() + return nil, fmt.Errorf("open input desktop: %v", err) + } + ok, _, err := syscall.Syscall(define.FuncSetThreadDesktop, 1, desktop, 0, 0) + if ok == 0 { + syscall.Syscall(define.FuncCloseDesktop, 1, desktop, 0, 0) + runtime.UnlockOSThread() + return nil, fmt.Errorf("set thread desktop: %v", err) + } + return func() { + syscall.Syscall(define.FuncSetThreadDesktop, 1, oldDesktop, 0, 0) + syscall.Syscall(define.FuncCloseDesktop, 1, desktop, 0, 0) + if locked { + runtime.UnlockOSThread() + locked = false + } + }, nil +} diff --git a/code/client/rule/vnc/worker/worker_xx.go b/code/client/rule/vnc/worker/attach_xx.go similarity index 59% rename from code/client/rule/vnc/worker/worker_xx.go rename to code/client/rule/vnc/worker/attach_xx.go index 33dc121..4b8199e 100644 --- a/code/client/rule/vnc/worker/worker_xx.go +++ b/code/client/rule/vnc/worker/attach_xx.go @@ -3,13 +3,6 @@ package worker -type workerOsBased struct { -} - -func (worker *Worker) init() error { - return nil -} - func attachDesktop() (func(), error) { return func() {}, nil } diff --git a/code/client/rule/vnc/worker/capture.go b/code/client/rule/vnc/worker/capture.go new file mode 100644 index 0000000..9506553 --- /dev/null +++ b/code/client/rule/vnc/worker/capture.go @@ -0,0 +1,37 @@ +package worker + +import ( + "fmt" + "natpass/code/client/rule/vnc/vncnetwork" + + "github.com/lwch/logging" +) + +func (worker *Worker) runCapture() vncnetwork.ImageData { + detach, err := attachDesktop() + if err != nil { + logging.Error("attach desktop: " + err.Error()) + return vncnetwork.ImageData{ + Ok: false, + Msg: fmt.Sprintf("attach desktop: " + err.Error()), + } + } + defer detach() + img, err := worker.cli.Screenshot() + if err != nil { + logging.Error("screenshot: " + err.Error()) + return vncnetwork.ImageData{ + Ok: false, + Msg: fmt.Sprintf("screenshot: " + err.Error()), + } + } + data := make([]byte, len(img.Pix)) + copy(data, img.Pix) + return vncnetwork.ImageData{ + Ok: true, + Bits: 32, + Width: uint32(img.Rect.Max.X), + Height: uint32(img.Rect.Max.Y), + Data: data, + } +} diff --git a/code/client/rule/vnc/worker/capture_windows.go b/code/client/rule/vnc/worker/capture_windows.go deleted file mode 100644 index ae108a1..0000000 --- a/code/client/rule/vnc/worker/capture_windows.go +++ /dev/null @@ -1,162 +0,0 @@ -package worker - -import ( - "errors" - "natpass/code/client/rule/vnc/define" - "natpass/code/client/rule/vnc/vncnetwork" - "syscall" - "unsafe" - - "github.com/lwch/logging" -) - -func (worker *Worker) runCapture() vncnetwork.ImageData { - err := worker.capture() - if err != nil { - return vncnetwork.ImageData{ - Ok: false, - Msg: err.Error(), - } - } - data := make([]byte, worker.info.width*worker.info.height*worker.info.bits/8) - for i := 0; i < len(data); i++ { - data[i] = *(*uint8)(unsafe.Pointer(worker.buffer + uintptr(i))) - } - // BGR => RGB - for i := 0; i < len(data); i += (worker.info.bits / 8) { - data[i], data[i+2] = data[i+2], data[i] - } - return vncnetwork.ImageData{ - Ok: true, - Bits: uint32(worker.info.bits), - Width: uint32(worker.info.width), - Height: uint32(worker.info.height), - Data: data, - } -} - -func (worker *Worker) capture() error { - detach, err := attachDesktop() - if err != nil { - return errors.New("attach desktop: " + err.Error()) - } - defer detach() - cancel, hdc, err := worker.getHandle() - if err != nil { - return errors.New("get handle: " + err.Error()) - } - defer cancel() - info := worker.info - err = worker.updateInfo(hdc) - if err != nil { - return errors.New("update info: " + err.Error()) - } - if info.bits != worker.info.bits || - info.width != worker.info.width || - info.height != worker.info.height { - err = worker.updateBuffer() - if err != nil { - return errors.New("update buffer: " + err.Error()) - } - } - // logging.Info("width=%d, height=%d, bits=%d", info.width, info.height, info.bits) - memDC, bitmap, free, err := worker.bitblt(hdc) - if err != nil { - return err - } - defer free() - defer worker.copyImageData(hdc, bitmap) - return worker.drawCursor(memDC) -} - -func (worker *Worker) bitblt(hdc uintptr) (uintptr, uintptr, func(), error) { - memDC, _, err := syscall.Syscall(define.FuncCreateCompatibleDC, 1, hdc, 0, 0) - if memDC == 0 { - return 0, 0, nil, errors.New("create dc: " + err.Error()) - } - bitmap, _, err := syscall.Syscall(define.FuncCreateCompatibleBitmap, 3, hdc, - uintptr(worker.info.width), uintptr(worker.info.height)) - if bitmap == 0 { - syscall.Syscall(define.FuncDeleteDC, 1, memDC, 0, 0) - return 0, 0, nil, errors.New("create bitmap: " + err.Error()) - } - oldDC, _, err := syscall.Syscall(define.FuncSelectObject, 2, memDC, bitmap, 0) - if oldDC == 0 { - syscall.Syscall(define.FuncDeleteObject, 1, bitmap, 0, 0) - syscall.Syscall(define.FuncDeleteDC, 1, memDC, 0, 0) - return 0, 0, nil, errors.New("select object: " + err.Error()) - } - ok, _, err := syscall.Syscall9(define.FuncBitBlt, 9, memDC, 0, 0, - uintptr(worker.info.width), uintptr(worker.info.height), hdc, 0, 0, define.SRCCOPY) - if ok == 0 { - syscall.Syscall(define.FuncSelectObject, 2, memDC, oldDC, 0) - syscall.Syscall(define.FuncDeleteObject, 1, bitmap, 0, 0) - syscall.Syscall(define.FuncDeleteDC, 1, memDC, 0, 0) - return 0, 0, nil, errors.New("bitblt: " + err.Error()) - } - return memDC, bitmap, func() { - syscall.Syscall(define.FuncSelectObject, 2, memDC, oldDC, 0) - syscall.Syscall(define.FuncDeleteObject, 1, bitmap, 0, 0) - syscall.Syscall(define.FuncDeleteDC, 1, memDC, 0, 0) - }, nil -} - -func (worker *Worker) drawCursor(memDC uintptr) error { - if !worker.showCursor { - return nil - } - var curInfo define.CURSORINFO - curInfo.CbSize = define.DWORD(unsafe.Sizeof(curInfo)) - ok, _, err := syscall.Syscall(define.FuncGetCursorInfo, 1, uintptr(unsafe.Pointer(&curInfo)), 0, 0) - if ok == 0 { - logging.Error("get cursor info: %v", err) - return nil - } - if curInfo.Flags == define.CURSORSHOWING { - var info define.ICONINFO - ok, _, err = syscall.Syscall(define.FuncGetIconInfo, 2, uintptr(curInfo.HCursor), uintptr(unsafe.Pointer(&info)), 0) - if ok == 0 { - logging.Error("get icon info: %v", err) - return nil - } - x := curInfo.PTScreenPos.X - define.LONG(info.XHotspot) - y := curInfo.PTScreenPos.Y - define.LONG(info.YHotspot) - ok, _, err = syscall.Syscall6(define.FuncDrawIcon, 4, memDC, uintptr(x), uintptr(y), uintptr(curInfo.HCursor), 0, 0) - if ok == 0 { - logging.Error("draw icon: %v", err) - return nil - } - } - return nil -} - -// BITMAPINFOHEADER https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader -type BITMAPINFOHEADER struct { - BiSize uint32 - BiWidth int32 - BiHeight int32 - BiPlanes uint16 - BiBitCount uint16 - BiCompression uint32 - BiSizeImage uint32 - BiXPelsPerMeter int32 - BiYPelsPerMeter int32 - BiClrUsed uint32 - BiClrImportant uint32 -} - -func (worker *Worker) copyImageData(hdc, bitmap uintptr) { - var hdr BITMAPINFOHEADER - hdr.BiSize = uint32(unsafe.Sizeof(hdr)) - hdr.BiPlanes = 1 - hdr.BiBitCount = uint16(worker.info.bits) - hdr.BiWidth = int32(worker.info.width) - hdr.BiHeight = int32(-worker.info.height) - hdr.BiCompression = define.BIRGB - hdr.BiSizeImage = 0 - lines, _, err := syscall.Syscall9(define.FuncGetDIBits, 7, hdc, bitmap, 0, uintptr(worker.info.height), - worker.buffer, uintptr(unsafe.Pointer(&hdr)), define.DIBRGBCOLORS, 0, 0) - if lines == 0 { - logging.Error("get bits: %v", err) - } -} diff --git a/code/client/rule/vnc/worker/capture_xx.go b/code/client/rule/vnc/worker/capture_xx.go deleted file mode 100644 index 449628a..0000000 --- a/code/client/rule/vnc/worker/capture_xx.go +++ /dev/null @@ -1,10 +0,0 @@ -//go:build !windows -// +build !windows - -package worker - -import "natpass/code/client/rule/vnc/vncnetwork" - -func (worker *Worker) runCapture() vncnetwork.ImageData { - return vncnetwork.ImageData{} -} diff --git a/code/client/rule/vnc/worker/worker.go b/code/client/rule/vnc/worker/worker.go index 183468a..9463750 100644 --- a/code/client/rule/vnc/worker/worker.go +++ b/code/client/rule/vnc/worker/worker.go @@ -8,32 +8,24 @@ import ( "github.com/gorilla/websocket" "github.com/lwch/logging" + "github.com/lwch/rdesktop" "github.com/lwch/runtime" "google.golang.org/protobuf/proto" ) -type desktopInfo struct { - bits int - width int - height int -} - // Worker worker object type Worker struct { - workerOsBased - info desktopInfo - showCursor bool + cli *rdesktop.Client } // NewWorker create worker func NewWorker(showCursor bool) *Worker { - worker := &Worker{ - showCursor: showCursor, - } - err := worker.init() + worker := &Worker{} + cli, err := rdesktop.New() if err != nil { return nil } + worker.cli = cli return worker } @@ -69,7 +61,7 @@ func (worker *Worker) Do(conn *websocket.Conn) { case vncnetwork.VncMsg_keyboard_event: runKeyboard(msg.GetKeyboard()) case vncnetwork.VncMsg_set_cursor: - worker.showCursor = msg.GetShowCursor() + worker.cli.ShowCursor(msg.GetShowCursor()) case vncnetwork.VncMsg_scroll_event: runScroll(msg.GetScroll()) case vncnetwork.VncMsg_clipboard_event: diff --git a/code/client/rule/vnc/worker/worker_windows.go b/code/client/rule/vnc/worker/worker_windows.go deleted file mode 100644 index de7c3df..0000000 --- a/code/client/rule/vnc/worker/worker_windows.go +++ /dev/null @@ -1,112 +0,0 @@ -package worker - -import ( - "fmt" - "natpass/code/client/rule/vnc/define" - "runtime" - "syscall" - - "github.com/lwch/logging" - "golang.org/x/sys/windows" -) - -type workerOsBased struct { - buffer uintptr -} - -func attachDesktop() (func(), error) { - runtime.LockOSThread() - locked := true - oldDesktop, _, err := syscall.Syscall(define.FuncGetThreadDesktop, 1, uintptr(windows.GetCurrentThreadId()), 0, 0) - if oldDesktop == 0 { - runtime.UnlockOSThread() - return nil, fmt.Errorf("get thread desktop: %v", err) - } - desktop, _, err := syscall.Syscall(define.FuncOpenInputDesktop, 3, 0, 0, windows.GENERIC_ALL) - if desktop == 0 { - runtime.UnlockOSThread() - return nil, fmt.Errorf("open input desktop: %v", err) - } - ok, _, err := syscall.Syscall(define.FuncSetThreadDesktop, 1, desktop, 0, 0) - if ok == 0 { - syscall.Syscall(define.FuncCloseDesktop, 1, desktop, 0, 0) - runtime.UnlockOSThread() - return nil, fmt.Errorf("set thread desktop: %v", err) - } - return func() { - syscall.Syscall(define.FuncSetThreadDesktop, 1, oldDesktop, 0, 0) - syscall.Syscall(define.FuncCloseDesktop, 1, desktop, 0, 0) - if locked { - runtime.UnlockOSThread() - locked = false - } - }, nil -} - -func (worker *Worker) init() error { - detach, err := attachDesktop() - if err != nil { - return err - } - defer detach() - cancel, hdc, err := worker.getHandle() - if err != nil { - return err - } - defer cancel() - err = worker.updateInfo(hdc) - if err != nil { - return err - } - detach() - return worker.updateBuffer() -} - -func (worker *workerOsBased) getHandle() (func(), uintptr, error) { - hwnd, _, err := syscall.Syscall(define.FuncGetDesktopWindow, 0, 0, 0, 0) - if hwnd == 0 { - return nil, 0, fmt.Errorf("get desktop window: %v", err) - } - hdc, _, err := syscall.Syscall(define.FuncGetDC, 1, hwnd, 0, 0) - if hdc == 0 { - return nil, 0, fmt.Errorf("get dc: %v", err) - } - return func() { - syscall.Syscall(define.FuncReleaseDC, 2, hwnd, hdc, 0) - }, hdc, nil -} - -func (worker *Worker) updateInfo(hdc uintptr) error { - bits, _, err := syscall.Syscall(define.FuncGetDeviceCaps, 2, hdc, define.BITSPIXEL, 0) - if bits == 0 { - return fmt.Errorf("get device caps(bits): %v", err) - } - width, _, err := syscall.Syscall(define.FuncGetDeviceCaps, 2, hdc, define.HORZRES, 0) - if width == 0 { - return fmt.Errorf("get device caps(width): %v", err) - } - height, _, err := syscall.Syscall(define.FuncGetDeviceCaps, 2, hdc, define.VERTRES, 0) - if height == 0 { - return fmt.Errorf("get device caps(height): %v", err) - } - worker.info.bits = int(bits) - worker.info.width = int(width) - worker.info.height = int(height) - if worker.info.bits != 32 { - worker.info.bits = 32 - logging.Info("reset bits to 32") - } - return nil -} - -func (worker *Worker) updateBuffer() error { - addr, _, err := syscall.Syscall(define.FuncGlobalAlloc, 2, define.GMEMFIXED, uintptr(worker.info.bits*worker.info.width*worker.info.height/8), 0) - if addr == 0 { - return fmt.Errorf("global alloc: %v", err) - } - if worker.buffer != 0 { - syscall.Syscall(define.FuncGlobalFree, 1, worker.buffer, 0, 0) - } - worker.buffer = addr - return nil -} diff --git a/contrib/build/Dockerfile b/contrib/build/Dockerfile index 3d353b9..6ad67d3 100644 --- a/contrib/build/Dockerfile +++ b/contrib/build/Dockerfile @@ -1,6 +1,6 @@ ARG APT_MIRROR=mirrors.ustc.edu.cn ARG LIBPNG_VERSION=1.6.37 -ARG GO_VERSION=1.17.3 +ARG GO_VERSION=1.17.4 ARG GO_PROXY=https://goproxy.cn,direct # build libpng @@ -38,6 +38,7 @@ WORKDIR /build RUN sed -i "s|deb.debian.org|$APT_MIRROR|g" /etc/apt/sources.list && \ sed -i "s|security.debian.org|$APT_MIRROR|g" /etc/apt/sources.list && \ + dpkg --add-architecture i386 && \ apt-get update && apt-get upgrade -y && \ apt-get install -y gcc libc6-dev && \ apt-get install -y libx11-dev xorg-dev libxtst-dev libpng++-dev && \ @@ -48,6 +49,10 @@ RUN sed -i "s|deb.debian.org|$APT_MIRROR|g" /etc/apt/sources.list && \ apt-get install -y gcc-mingw-w64 && \ apt-get install -y libz-mingw-w64-dev && \ apt-get install -y curl git && \ + apt-get update && \ + apt-get install -y libx11-dev:i386 libxtst-dev:i386 libpng-dev:i386 && \ + apt-get install -y xcb:i386 libxcb-xkb-dev:i386 x11-xkb-utils:i386 libx11-xcb-dev:i386 libxkbcommon-x11-dev:i386 && \ + apt-get install -y libxkbcommon-dev:i386 && \ curl -L https://dl.google.com/go/go$GO_VERSION.linux-amd64.tar.gz|tar -xz -C /usr/local && \ cp -f /usr/share/zoneinfo/Asia/Shanghai /etc/localtime diff --git a/contrib/build/build_all.go b/contrib/build/build_all.go index 32f02f6..d3b2abc 100644 --- a/contrib/build/build_all.go +++ b/contrib/build/build_all.go @@ -161,6 +161,8 @@ func build(t target) { runtime.Assert(err) err = copyFile("CHANGELOG.md", path.Join(buildDir, "CHANGELOG.md")) runtime.Assert(err) + err = copyFile("docs/startup.md", path.Join(buildDir, "startup.md")) + runtime.Assert(err) ldflags := "-X 'main.gitHash=" + gitHash() + "' " + "-X 'main.gitReversion=" + gitReversion() + "' " + @@ -199,6 +201,27 @@ func build(t target) { cmd.Env = env runtime.Assert(cmd.Run()) + if t.os == "linux" && !strings.Contains(t.arch, "arm") { + ldflags := "-X 'main.gitHash=" + gitHash() + "' " + + "-X 'main.gitReversion=" + gitReversion() + "' " + + "-X 'main.buildTime=" + buildTime() + "' " + + "-X 'main.version=" + version + "'" + logging.Info("build client.vnc...") + env := append(os.Environ(), + fmt.Sprintf("GOOS=%s", t.os), + fmt.Sprintf("GOARCH=%s", t.arch)) + args := []string{"build", "-o", path.Join(buildDir, "np-cli.vnc"), "-ldflags", ldflags} + args = append(args, "-tags", "vnc") + env = append(env, "CGO_ENABLED=1") + args = append(args, + path.Join("code", "client", "main.go")) + cmd = exec.Command("go", args...) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + cmd.Env = env + runtime.Assert(cmd.Run()) + } + logging.Info("packing...") pack(buildDir, path.Join(releaseDir, "natpass_"+version+"_"+t.os+"_"+t.arch+t.packExt)) } diff --git a/docs/imgs/vnc_deepin.png b/docs/imgs/vnc_deepin.png new file mode 100644 index 0000000..e7f49ee Binary files /dev/null and b/docs/imgs/vnc_deepin.png differ diff --git a/docs/imgs/vnc_fedora.png b/docs/imgs/vnc_fedora.png new file mode 100644 index 0000000..ae277f8 Binary files /dev/null and b/docs/imgs/vnc_fedora.png differ diff --git a/docs/imgs/vnc_ubuntu.png b/docs/imgs/vnc_ubuntu.png new file mode 100644 index 0000000..49e4510 Binary files /dev/null and b/docs/imgs/vnc_ubuntu.png differ diff --git a/docs/startup.md b/docs/startup.md index c328526..fb8ce8c 100644 --- a/docs/startup.md +++ b/docs/startup.md @@ -20,7 +20,7 @@ sudo systemctl enable np-svr sudo systemctl start np-svr -## 远端部署 +## 受控端部署 1. 在远端机器上[下载](https://github.com/lwch/natpass/releases)并解压到任意目录 2. 修改client.yaml配置文件,设置*id*为remote,设置*server*地址,并删除以下配置 @@ -35,7 +35,11 @@ sudo systemctl enable np-cli sudo systemctl start np-cli -## 本地部署 +**注:当受控端为linux操作系统时,请使用np-cli.vnc程序进行启动,暂不支持系统服务方式启动,手工启动命令如下** + + ./np-cli -conf client.yaml + +## 控制端部署 1. 在本地机器上[下载](https://github.com/lwch/natpass/releases)并解压到任意目录 2. 修改client.yaml配置文件,设置*id*为local,设置*server*地址 diff --git a/go.mod b/go.mod index 377e6c8..9d4f2f0 100644 --- a/go.mod +++ b/go.mod @@ -6,19 +6,19 @@ require ( github.com/creack/pty v1.1.17 github.com/dustin/go-humanize v1.0.0 github.com/go-bindata/go-bindata/v3 v3.1.3 - github.com/go-ole/go-ole v1.2.6 // indirect - github.com/go-vgo/robotgo v0.100.8 + github.com/go-vgo/robotgo v0.100.9 github.com/gorilla/websocket v1.4.2 github.com/kardianos/service v1.2.0 github.com/kisielk/errcheck v1.6.0 // indirect - github.com/lwch/logging v0.0.0-20211115073745-0db19179db17 + github.com/lwch/logging v0.0.0-20211203094902-ecb971ed7cdc + github.com/lwch/rdesktop v0.0.0-20211207101551-b892a4a5e2b5 github.com/lwch/runtime v0.0.0-20190520054850-8c97e19e0c6d - github.com/lwch/yaml v0.0.0-20211009070949-2d4c64e2b789 - github.com/shirou/gopsutil v3.21.10+incompatible // indirect - golang.org/x/image v0.0.0-20211028202545-6944b10bf410 // indirect + github.com/lwch/yaml v0.0.0-20211206085137-772f80e85a26 + github.com/shirou/gopsutil v3.21.11+incompatible // indirect + github.com/yusufpapurcu/wmi v1.2.2 // indirect golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect golang.org/x/mod v0.5.1 // indirect - golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1 + golang.org/x/sys v0.0.0-20211124211545-fe61309f8881 golang.org/x/text v0.3.7 golang.org/x/tools v0.1.7 // indirect google.golang.org/protobuf v1.27.1 diff --git a/go.sum b/go.sum index 91eb3ea..d159254 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,5 @@ github.com/BurntSushi/freetype-go v0.0.0-20160129220410-b763ddbfe298/go.mod h1:D+QujdIlUNfa0igpNMk6UIvlb6C252URs4yupRUV4lQ= github.com/BurntSushi/graphics-go v0.0.0-20160129215708-b43f31a4a966/go.mod h1:Mid70uvE93zn9wgF92A/r5ixgnvX8Lh68fxp9KQBaI0= -github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA= github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8= github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI= github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= @@ -14,8 +13,8 @@ github.com/go-bindata/go-bindata/v3 v3.1.3/go.mod h1:1/zrpXsLD8YDIbhZRqXzm1Ghc7N github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= -github.com/go-vgo/robotgo v0.100.8 h1:fBcmqPoQq/0vOr0C45T6SSScKwuYgAEJr9+T1PulHOA= -github.com/go-vgo/robotgo v0.100.8/go.mod h1:GCjwxRFoUkuekzm02WexYBV0paDLCbrrlKEfxt/CB10= +github.com/go-vgo/robotgo v0.100.9 h1:dgt4qaxBw6+vg4P5tUeH26VsL5M0v/IRwRmkingZ2YU= +github.com/go-vgo/robotgo v0.100.9/go.mod h1:7QeIpSHX7bjeXWRPxvQeKSx9mHI+3l80Ahq+CQF0C68= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= @@ -26,12 +25,15 @@ github.com/kardianos/service v1.2.0/go.mod h1:CIMRFEJVL+0DS1a3Nx06NaMn4Dz63Ng6O7 github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.6.0 h1:YTDO4pNy7AUN/021p+JGHycQyYNIyMoenM1YDVK6RlY= github.com/kisielk/errcheck v1.6.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= -github.com/lwch/logging v0.0.0-20211115073745-0db19179db17 h1:LJ8K1245kOPu1BGgEsmW/tr5gdkrX1vdQ+aztXjMjAA= github.com/lwch/logging v0.0.0-20211115073745-0db19179db17/go.mod h1:aXQui5bsF/d4I+z6szuiBWY5m4y9t6pyZ2Q/sLgkBBg= +github.com/lwch/logging v0.0.0-20211203094902-ecb971ed7cdc h1:QHC/AggBsu39IWcbzjgIc2ApNXuWhZhD1ieCkFgWfeM= +github.com/lwch/logging v0.0.0-20211203094902-ecb971ed7cdc/go.mod h1:aXQui5bsF/d4I+z6szuiBWY5m4y9t6pyZ2Q/sLgkBBg= +github.com/lwch/rdesktop v0.0.0-20211207101551-b892a4a5e2b5 h1:RF5uIUO37p6WVgqd3mrkPLYNvJCBHs9sOpBsbTYdzO4= +github.com/lwch/rdesktop v0.0.0-20211207101551-b892a4a5e2b5/go.mod h1:vZtkNUaG1bDuzJavu8OQQoBbHVS6cYJE7y4oxtmhYYM= github.com/lwch/runtime v0.0.0-20190520054850-8c97e19e0c6d h1:Xg+zzPtvX22DaoJD5Bp0tqPdB8gn5WypghIJ4fluqiQ= github.com/lwch/runtime v0.0.0-20190520054850-8c97e19e0c6d/go.mod h1:uEt0zu1MDC7WnVvodPBGSYAD/KMKk0v36xE8UE5veM8= -github.com/lwch/yaml v0.0.0-20211009070949-2d4c64e2b789 h1:Z9jucdBfDaTXBT+jxyOw08op3DYpr9lEZJkTbVJ3bmU= -github.com/lwch/yaml v0.0.0-20211009070949-2d4c64e2b789/go.mod h1:Dz0eixDQvioB5pqCXGQJ6sTJetbS6TCHegLuRh2Bw2U= +github.com/lwch/yaml v0.0.0-20211206085137-772f80e85a26 h1:sR3nbPhdfstDxYLp7c1EnsKH3z8+u+wgnhC3AI9/qf0= +github.com/lwch/yaml v0.0.0-20211206085137-772f80e85a26/go.mod h1:Dz0eixDQvioB5pqCXGQJ6sTJetbS6TCHegLuRh2Bw2U= github.com/lxn/win v0.0.0-20210218163916-a377121e959e h1:H+t6A/QJMbhCSEH5rAuRxh+CtW96g0Or0Fxa9IKr4uc= github.com/lxn/win v0.0.0-20210218163916-a377121e959e/go.mod h1:KxxjdtRkfNoYDCUP5ryK7XJJNTnpC8atvtmTheChOtk= github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= @@ -41,15 +43,15 @@ github.com/otiai10/mint v1.3.0 h1:Ady6MKVezQwHBkGzLFbrsywyp09Ah7rkmfjV3Bcr5uc= github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/robotn/gohook v0.31.2 h1:ADIppQ3T0Sd+kaDMb4Vnv6UeSmhNfK0H0HpPWCd8G5I= -github.com/robotn/gohook v0.31.2/go.mod h1:0BQit8783ey63WXFau8TvoaTYfNtsAhqZ0RJaqlYi6E= +github.com/robotn/gohook v0.31.3 h1:kGX8iukJ9ensVRwRKnTtdojAMQOpa6KFnXDi4OA4RaI= +github.com/robotn/gohook v0.31.3/go.mod h1:wyGik0yb4iwCfJjDprtNkTyxkgQWuKoVPQ3hkz6+6js= github.com/robotn/xgb v0.0.0-20190912153532-2cb92d044934 h1:2lhSR8N3T6I30q096DT7/5AKEIcf1vvnnWAmS0wfnNY= github.com/robotn/xgb v0.0.0-20190912153532-2cb92d044934/go.mod h1:SxQhJskUJ4rleVU44YvnrdvxQr0tKy5SRSigBrCgyyQ= github.com/robotn/xgbutil v0.0.0-20190912154524-c861d6f87770 h1:2uX8QRLkkxn2EpAQ6I3KhA79BkdRZfvugJUzJadiJwk= github.com/robotn/xgbutil v0.0.0-20190912154524-c861d6f87770/go.mod h1:svkDXUDQjUiWzLrA0OZgHc4lbOts3C+uRfP6/yjwYnU= -github.com/shirou/gopsutil v3.21.8+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= -github.com/shirou/gopsutil v3.21.10+incompatible h1:AL2kpVykjkqeN+MFe1WcwSBVUjGjvdU8/ubvCuXAjrU= github.com/shirou/gopsutil v3.21.10+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= +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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= @@ -57,14 +59,18 @@ github.com/tklauser/go-sysconf v0.3.9 h1:JeUVdAOWhhxVcU6Eqr/ATFHgXk/mmiItdKeJPev github.com/tklauser/go-sysconf v0.3.9/go.mod h1:11DU/5sG7UexIrp/O6g35hrWzu0JxlwQ3LSFUzyeuhs= github.com/tklauser/numcpus v0.3.0 h1:ILuRUQBtssgnxw0XXIjKUC56fgnOrFoQQ/4+DeU2biQ= github.com/tklauser/numcpus v0.3.0/go.mod h1:yFGUr7TUHQRAhyqBcEg0Ge34zDBAsIvJJcyE6boqnA8= -github.com/vcaesar/gops v0.21.2 h1:OwWoJR0zb+AK41TN2adhZUP9lAmaRMzkWwf7Ux5Mx00= -github.com/vcaesar/gops v0.21.2/go.mod h1:BEJGigAc9GORbEegWX9rRon/qwibjDs8p50WYm2KlXw= +github.com/vcaesar/gops v0.21.3 h1:VR7amkxVv9CQfsotkXrmMyT19dVuNTa1PM/oopJeIc0= +github.com/vcaesar/gops v0.21.3/go.mod h1:3e2EnlZTI9/44bqzRwkeZ3s0ZQwK2Cn4QPLx8Ii8Agk= github.com/vcaesar/imgo v0.30.0 h1:ODQVX0EFJEh+WkKahCBtE0SqcDCIjl/kjiOplR0Ouh8= github.com/vcaesar/imgo v0.30.0/go.mod h1:8TGnt5hjaMgwDByvMFIzUDSh5uSea4n1tAbSvnhvA6U= +github.com/vcaesar/keycode v0.10.0 h1:Qx5QE8ZXHyRyjoA2QOxBp25OKMKB+zxMVqm0FWGV0d4= +github.com/vcaesar/keycode v0.10.0/go.mod h1:JNlY7xbKsh+LAGfY2j4M3znVrGEm5W1R8s/Uv6BJcfQ= github.com/vcaesar/tt v0.20.0 h1:9t2Ycb9RNHcP0WgQgIaRKJBB+FrRdejuaL6uWIHuoBA= github.com/vcaesar/tt v0.20.0/go.mod h1:GHPxQYhn+7OgKakRusH7KJ0M5MhywoeLb8Fcffs/Gtg= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg= +github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -98,10 +104,9 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210816074244-15123e1e1f71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210915083310-ed5796bab164/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210925032602-92d5a993a665/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1 h1:kwrAHlwJ0DUBZwQ238v+Uod/3eZ8B2K5rYsUHBQvzmI= -golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211123173158-ef496fb156ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211124211545-fe61309f8881 h1:TyHqChC80pFkXWraUUf6RuB5IqFdQieMLwwCJokV2pc= +golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=