Merge pull request #15 from lwch/dev

v0.7.2
This commit is contained in:
李文超
2021-12-08 10:18:01 +08:00
committed by GitHub
27 changed files with 272 additions and 538 deletions
+10 -1
View File
@@ -67,4 +67,13 @@
# v0.7.1
1. vnc页面支持远程设置或读取剪贴板(仅支持文本内容)
1. vnc页面支持远程设置或读取剪贴板(仅支持文本内容)
# v0.7.2
1. 截屏库统一抽取到https://github.com/lwch/rdesktop
2. 修正windows下的错误日志显示格式问题
3. 修正windows下的配置文件include问题
4. 支持linux远程桌面
**注:linux受控端需使用np-cli.vnc程序进行启动,且目前无法以systemd等方式运行**
+12
View File
@@ -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)
+1 -1
View File
@@ -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 \
+1 -1
View File
@@ -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 \
@@ -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
)
@@ -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
)
+2 -57
View File
@@ -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
)
+61
View File
@@ -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
}
}
@@ -0,0 +1,6 @@
package process
// CreateWorker create worker process
func CreateWorker(name, confDir string, showCursor bool) (*Process, error) {
return nil, ErrNotSupported
}
@@ -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
}
@@ -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
}
}
@@ -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
}
@@ -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
}
@@ -3,13 +3,6 @@
package worker
type workerOsBased struct {
}
func (worker *Worker) init() error {
return nil
}
func attachDesktop() (func(), error) {
return func() {}, nil
}
+37
View File
@@ -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,
}
}
@@ -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)
}
}
-10
View File
@@ -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{}
}
+6 -14
View File
@@ -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:
@@ -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
}
+6 -1
View File
@@ -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
+23
View File
@@ -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))
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 312 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

+6 -2
View File
@@ -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*地址
+7 -7
View File
@@ -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
+21 -16
View File
@@ -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=