mirror of
https://github.com/wavetermdev/waveterm.git
synced 2025-01-02 18:39:05 +01:00
Add Unix Domain Socket Listener when Establishing Connections (#243)
This makes it possible to send wsh commands from wsh on a remote session to wavesrv running locally. The exact behavior of running those commands isn't implemented, but the underlying interface is added here.
This commit is contained in:
parent
6df50a5790
commit
c30188552f
@ -244,7 +244,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
go wshserver.RunWshRpcOverListener(unixListener)
|
go wshutil.RunWshRpcOverListener(unixListener)
|
||||||
web.RunWebServer(webListener) // blocking
|
web.RunWebServer(webListener) // blocking
|
||||||
runtime.KeepAlive(waveLock)
|
runtime.KeepAlive(waveLock)
|
||||||
}
|
}
|
||||||
|
2
frontend/types/gotypes.d.ts
vendored
2
frontend/types/gotypes.d.ts
vendored
@ -398,7 +398,7 @@ declare global {
|
|||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
// shellexec.TermSize
|
// wstore.TermSize
|
||||||
type TermSize = {
|
type TermSize = {
|
||||||
rows: number;
|
rows: number;
|
||||||
cols: number;
|
cols: number;
|
||||||
|
@ -6,9 +6,7 @@ package blockcontroller
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"crypto/rand"
|
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/hex"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
@ -55,9 +53,9 @@ var globalLock = &sync.Mutex{}
|
|||||||
var blockControllerMap = make(map[string]*BlockController)
|
var blockControllerMap = make(map[string]*BlockController)
|
||||||
|
|
||||||
type BlockInputUnion struct {
|
type BlockInputUnion struct {
|
||||||
InputData []byte `json:"inputdata,omitempty"`
|
InputData []byte `json:"inputdata,omitempty"`
|
||||||
SigName string `json:"signame,omitempty"`
|
SigName string `json:"signame,omitempty"`
|
||||||
TermSize *shellexec.TermSize `json:"termsize,omitempty"`
|
TermSize *wstore.TermSize `json:"termsize,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type BlockController struct {
|
type BlockController struct {
|
||||||
@ -116,7 +114,7 @@ func (bc *BlockController) getShellProc() *shellexec.ShellProc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type RunShellOpts struct {
|
type RunShellOpts struct {
|
||||||
TermSize shellexec.TermSize `json:"termsize,omitempty"`
|
TermSize wstore.TermSize `json:"termsize,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bc *BlockController) UpdateControllerAndSendUpdate(updateFn func() bool) {
|
func (bc *BlockController) UpdateControllerAndSendUpdate(updateFn func() bool) {
|
||||||
@ -205,18 +203,6 @@ func (bc *BlockController) resetTerminalState() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// every byte is 4-bits of randomness
|
|
||||||
func randomHexString(numHexDigits int) (string, error) {
|
|
||||||
numBytes := (numHexDigits + 1) / 2 // Calculate the number of bytes needed
|
|
||||||
bytes := make([]byte, numBytes)
|
|
||||||
if _, err := rand.Read(bytes); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
hexStr := hex.EncodeToString(bytes)
|
|
||||||
return hexStr[:numHexDigits], nil // Return the exact number of hex digits
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bc *BlockController) DoRunShellCommand(rc *RunShellOpts, blockMeta waveobj.MetaMapType) error {
|
func (bc *BlockController) DoRunShellCommand(rc *RunShellOpts, blockMeta waveobj.MetaMapType) error {
|
||||||
// create a circular blockfile for the output
|
// create a circular blockfile for the output
|
||||||
ctx, cancelFn := context.WithTimeout(context.Background(), 2*time.Second)
|
ctx, cancelFn := context.WithTimeout(context.Background(), 2*time.Second)
|
||||||
@ -244,35 +230,11 @@ func (bc *BlockController) DoRunShellCommand(rc *RunShellOpts, blockMeta waveobj
|
|||||||
if shellProcErr != nil {
|
if shellProcErr != nil {
|
||||||
return shellProcErr
|
return shellProcErr
|
||||||
}
|
}
|
||||||
var remoteDomainSocketName string
|
|
||||||
remoteName := blockMeta.GetString(wstore.MetaKey_Connection, "")
|
remoteName := blockMeta.GetString(wstore.MetaKey_Connection, "")
|
||||||
isRemote := remoteName != ""
|
|
||||||
if isRemote {
|
|
||||||
randStr, err := randomHexString(16) // 64-bits of randomness
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("error generating random string: %w", err)
|
|
||||||
}
|
|
||||||
remoteDomainSocketName = fmt.Sprintf("/tmp/waveterm-%s.sock", randStr)
|
|
||||||
}
|
|
||||||
var cmdStr string
|
var cmdStr string
|
||||||
cmdOpts := shellexec.CommandOptsType{
|
cmdOpts := shellexec.CommandOptsType{
|
||||||
Env: make(map[string]string),
|
Env: make(map[string]string),
|
||||||
}
|
}
|
||||||
if !blockMeta.GetBool(wstore.MetaKey_CmdNoWsh, false) {
|
|
||||||
if isRemote {
|
|
||||||
jwtStr, err := wshutil.MakeClientJWTToken(wshrpc.RpcContext{TabId: bc.TabId, BlockId: bc.BlockId}, remoteDomainSocketName)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("error making jwt token: %w", err)
|
|
||||||
}
|
|
||||||
cmdOpts.Env[wshutil.WaveJwtTokenVarName] = jwtStr
|
|
||||||
} else {
|
|
||||||
jwtStr, err := wshutil.MakeClientJWTToken(wshrpc.RpcContext{TabId: bc.TabId, BlockId: bc.BlockId}, wavebase.GetDomainSocketName())
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("error making jwt token: %w", err)
|
|
||||||
}
|
|
||||||
cmdOpts.Env[wshutil.WaveJwtTokenVarName] = jwtStr
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if bc.ControllerType == BlockController_Shell {
|
if bc.ControllerType == BlockController_Shell {
|
||||||
cmdOpts.Interactive = true
|
cmdOpts.Interactive = true
|
||||||
cmdOpts.Login = true
|
cmdOpts.Login = true
|
||||||
@ -315,16 +277,29 @@ func (bc *BlockController) DoRunShellCommand(rc *RunShellOpts, blockMeta waveobj
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
conn, err := remote.GetConn(credentialCtx, opts)
|
||||||
client, err := remote.GetClient(credentialCtx, opts)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
shellProc, err = shellexec.StartRemoteShellProc(rc.TermSize, cmdStr, cmdOpts, client)
|
if !blockMeta.GetBool(wstore.MetaKey_CmdNoWsh, false) {
|
||||||
|
jwtStr, err := wshutil.MakeClientJWTToken(wshrpc.RpcContext{TabId: bc.TabId, BlockId: bc.BlockId}, conn.SockName)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error making jwt token: %w", err)
|
||||||
|
}
|
||||||
|
cmdOpts.Env[wshutil.WaveJwtTokenVarName] = jwtStr
|
||||||
|
}
|
||||||
|
shellProc, err = shellexec.StartRemoteShellProc(rc.TermSize, cmdStr, cmdOpts, conn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if !blockMeta.GetBool(wstore.MetaKey_CmdNoWsh, false) {
|
||||||
|
jwtStr, err := wshutil.MakeClientJWTToken(wshrpc.RpcContext{TabId: bc.TabId, BlockId: bc.BlockId}, wavebase.GetDomainSocketName())
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error making jwt token: %w", err)
|
||||||
|
}
|
||||||
|
cmdOpts.Env[wshutil.WaveJwtTokenVarName] = jwtStr
|
||||||
|
}
|
||||||
shellProc, err = shellexec.StartShellProc(rc.TermSize, cmdStr, cmdOpts)
|
shellProc, err = shellexec.StartShellProc(rc.TermSize, cmdStr, cmdOpts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -428,11 +403,11 @@ func getBoolFromMeta(meta map[string]any, key string, def bool) bool {
|
|||||||
return def
|
return def
|
||||||
}
|
}
|
||||||
|
|
||||||
func getTermSize(bdata *wstore.Block) shellexec.TermSize {
|
func getTermSize(bdata *wstore.Block) wstore.TermSize {
|
||||||
if bdata.RuntimeOpts != nil {
|
if bdata.RuntimeOpts != nil {
|
||||||
return bdata.RuntimeOpts.TermSize
|
return bdata.RuntimeOpts.TermSize
|
||||||
} else {
|
} else {
|
||||||
return shellexec.TermSize{
|
return wstore.TermSize{
|
||||||
Rows: 25,
|
Rows: 25,
|
||||||
Cols: 80,
|
Cols: 80,
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"html/template"
|
"html/template"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
@ -16,37 +17,81 @@ import (
|
|||||||
|
|
||||||
"github.com/wavetermdev/thenextwave/pkg/userinput"
|
"github.com/wavetermdev/thenextwave/pkg/userinput"
|
||||||
"github.com/wavetermdev/thenextwave/pkg/util/shellutil"
|
"github.com/wavetermdev/thenextwave/pkg/util/shellutil"
|
||||||
|
"github.com/wavetermdev/thenextwave/pkg/util/utilfn"
|
||||||
"github.com/wavetermdev/thenextwave/pkg/wavebase"
|
"github.com/wavetermdev/thenextwave/pkg/wavebase"
|
||||||
|
"github.com/wavetermdev/thenextwave/pkg/wshutil"
|
||||||
"golang.org/x/crypto/ssh"
|
"golang.org/x/crypto/ssh"
|
||||||
)
|
)
|
||||||
|
|
||||||
var userHostRe = regexp.MustCompile(`^([a-zA-Z0-9][a-zA-Z0-9._@\\-]*@)?([a-z0-9][a-z0-9.-]*)(?::([0-9]+))?$`)
|
var userHostRe = regexp.MustCompile(`^([a-zA-Z0-9][a-zA-Z0-9._@\\-]*@)?([a-z0-9][a-z0-9.-]*)(?::([0-9]+))?$`)
|
||||||
var globalLock = &sync.Mutex{}
|
var globalLock = &sync.Mutex{}
|
||||||
var clientControllerMap = make(map[SSHOpts]*ssh.Client)
|
var clientControllerMap = make(map[SSHOpts]*SSHConn)
|
||||||
|
|
||||||
func GetClient(ctx context.Context, opts *SSHOpts) (*ssh.Client, error) {
|
type SSHConn struct {
|
||||||
|
Lock *sync.Mutex
|
||||||
|
Opts *SSHOpts
|
||||||
|
Client *ssh.Client
|
||||||
|
SockName string
|
||||||
|
DomainSockListener net.Listener
|
||||||
|
}
|
||||||
|
|
||||||
|
func (conn *SSHConn) Close() error {
|
||||||
|
if conn.DomainSockListener != nil {
|
||||||
|
conn.DomainSockListener.Close()
|
||||||
|
}
|
||||||
|
return conn.Client.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (conn *SSHConn) OpenDomainSocketListener() error {
|
||||||
|
if conn.DomainSockListener != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
randStr, err := utilfn.RandomHexString(16) // 64-bits of randomness
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error generating random string: %w", err)
|
||||||
|
}
|
||||||
|
sockName := fmt.Sprintf("/tmp/waveterm-%s.sock", randStr)
|
||||||
|
log.Printf("remote domain socket %s %q\n", conn.Opts.String(), sockName)
|
||||||
|
listener, err := conn.Client.ListenUnix(sockName)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to request connection domain socket: %v", err)
|
||||||
|
}
|
||||||
|
conn.SockName = sockName
|
||||||
|
conn.DomainSockListener = listener
|
||||||
|
go func() {
|
||||||
|
wshutil.RunWshRpcOverListener(listener)
|
||||||
|
}()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetConn(ctx context.Context, opts *SSHOpts) (*SSHConn, error) {
|
||||||
globalLock.Lock()
|
globalLock.Lock()
|
||||||
defer globalLock.Unlock()
|
defer globalLock.Unlock()
|
||||||
|
|
||||||
// attempt to retrieve if already opened
|
// attempt to retrieve if already opened
|
||||||
client, ok := clientControllerMap[*opts]
|
conn, ok := clientControllerMap[*opts]
|
||||||
if ok {
|
if ok {
|
||||||
return client, nil
|
return conn, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
client, err := ConnectToClient(ctx, opts) //todo specify or remove opts
|
client, err := ConnectToClient(ctx, opts) //todo specify or remove opts
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
conn = &SSHConn{Lock: &sync.Mutex{}, Opts: opts, Client: client}
|
||||||
|
err = conn.OpenDomainSocketListener()
|
||||||
|
if err != nil {
|
||||||
|
conn.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
// check that correct wsh extensions are installed
|
// check that correct wsh extensions are installed
|
||||||
expectedVersion := fmt.Sprintf("wsh v%s", wavebase.WaveVersion)
|
expectedVersion := fmt.Sprintf("wsh v%s", wavebase.WaveVersion)
|
||||||
clientVersion, err := getWshVersion(client)
|
clientVersion, err := getWshVersion(client)
|
||||||
if err == nil && clientVersion == expectedVersion {
|
if err == nil && clientVersion == expectedVersion {
|
||||||
// save successful connection to map
|
// save successful connection to map
|
||||||
clientControllerMap[*opts] = client
|
clientControllerMap[*opts] = conn
|
||||||
|
return conn, nil
|
||||||
return client, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var queryText string
|
var queryText string
|
||||||
@ -92,9 +137,9 @@ func GetClient(ctx context.Context, opts *SSHOpts) (*ssh.Client, error) {
|
|||||||
log.Printf("successful install")
|
log.Printf("successful install")
|
||||||
|
|
||||||
// save successful connection to map
|
// save successful connection to map
|
||||||
clientControllerMap[*opts] = client
|
clientControllerMap[*opts] = conn
|
||||||
|
|
||||||
return client, nil
|
return conn, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func DisconnectClient(opts *SSHOpts) error {
|
func DisconnectClient(opts *SSHOpts) error {
|
||||||
|
@ -707,3 +707,10 @@ type SSHOpts struct {
|
|||||||
SSHUser string `json:"sshuser"`
|
SSHUser string `json:"sshuser"`
|
||||||
SSHPort int `json:"sshport,omitempty"`
|
SSHPort int `json:"sshport,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (opts SSHOpts) String() string {
|
||||||
|
if opts.SSHPort == 0 {
|
||||||
|
return fmt.Sprintf("%s@%s", opts.SSHUser, opts.SSHHost)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s@%s:%d", opts.SSHUser, opts.SSHHost, opts.SSHPort)
|
||||||
|
}
|
||||||
|
@ -22,14 +22,10 @@ import (
|
|||||||
"github.com/wavetermdev/thenextwave/pkg/remote"
|
"github.com/wavetermdev/thenextwave/pkg/remote"
|
||||||
"github.com/wavetermdev/thenextwave/pkg/util/shellutil"
|
"github.com/wavetermdev/thenextwave/pkg/util/shellutil"
|
||||||
"github.com/wavetermdev/thenextwave/pkg/wavebase"
|
"github.com/wavetermdev/thenextwave/pkg/wavebase"
|
||||||
"golang.org/x/crypto/ssh"
|
"github.com/wavetermdev/thenextwave/pkg/wshutil"
|
||||||
|
"github.com/wavetermdev/thenextwave/pkg/wstore"
|
||||||
)
|
)
|
||||||
|
|
||||||
type TermSize struct {
|
|
||||||
Rows int `json:"rows"`
|
|
||||||
Cols int `json:"cols"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type CommandOptsType struct {
|
type CommandOptsType struct {
|
||||||
Interactive bool `json:"interactive,omitempty"`
|
Interactive bool `json:"interactive,omitempty"`
|
||||||
Login bool `json:"login,omitempty"`
|
Login bool `json:"login,omitempty"`
|
||||||
@ -153,7 +149,8 @@ func (pp *PipePty) WriteString(s string) (n int, err error) {
|
|||||||
return pp.Write([]byte(s))
|
return pp.Write([]byte(s))
|
||||||
}
|
}
|
||||||
|
|
||||||
func StartRemoteShellProc(termSize TermSize, cmdStr string, cmdOpts CommandOptsType, client *ssh.Client) (*ShellProc, error) {
|
func StartRemoteShellProc(termSize wstore.TermSize, cmdStr string, cmdOpts CommandOptsType, conn *remote.SSHConn) (*ShellProc, error) {
|
||||||
|
client := conn.Client
|
||||||
shellPath, err := remote.DetectShell(client)
|
shellPath, err := remote.DetectShell(client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -239,6 +236,12 @@ func StartRemoteShellProc(termSize TermSize, cmdStr string, cmdOpts CommandOptsT
|
|||||||
cmdCombined = fmt.Sprintf(`ZDOTDIR="%s/.waveterm/zsh-integration" %s`, homeDir, cmdCombined)
|
cmdCombined = fmt.Sprintf(`ZDOTDIR="%s/.waveterm/zsh-integration" %s`, homeDir, cmdCombined)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
jwtToken, ok := cmdOpts.Env[wshutil.WaveJwtTokenVarName]
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("no jwt token provided to connection")
|
||||||
|
}
|
||||||
|
cmdCombined = fmt.Sprintf(`%s=%s %s`, wshutil.WaveJwtTokenVarName, jwtToken, cmdCombined)
|
||||||
|
|
||||||
session.RequestPty("xterm-256color", termSize.Rows, termSize.Cols, nil)
|
session.RequestPty("xterm-256color", termSize.Rows, termSize.Cols, nil)
|
||||||
|
|
||||||
sessionWrap := SessionWrap{session, cmdCombined, pipePty, pipePty}
|
sessionWrap := SessionWrap{session, cmdCombined, pipePty, pipePty}
|
||||||
@ -262,7 +265,7 @@ func isBashShell(shellPath string) bool {
|
|||||||
return strings.Contains(shellBase, "bash")
|
return strings.Contains(shellBase, "bash")
|
||||||
}
|
}
|
||||||
|
|
||||||
func StartShellProc(termSize TermSize, cmdStr string, cmdOpts CommandOptsType) (*ShellProc, error) {
|
func StartShellProc(termSize wstore.TermSize, cmdStr string, cmdOpts CommandOptsType) (*ShellProc, error) {
|
||||||
shellutil.InitCustomShellStartupFiles()
|
shellutil.InitCustomShellStartupFiles()
|
||||||
var ecmd *exec.Cmd
|
var ecmd *exec.Cmd
|
||||||
var shellOpts []string
|
var shellOpts []string
|
||||||
@ -324,7 +327,7 @@ func StartShellProc(termSize TermSize, cmdStr string, cmdOpts CommandOptsType) (
|
|||||||
return &ShellProc{Cmd: CmdWrap{ecmd, cmdPty}, CloseOnce: &sync.Once{}, DoneCh: make(chan any)}, nil
|
return &ShellProc{Cmd: CmdWrap{ecmd, cmdPty}, CloseOnce: &sync.Once{}, DoneCh: make(chan any)}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunSimpleCmdInPty(ecmd *exec.Cmd, termSize TermSize) ([]byte, error) {
|
func RunSimpleCmdInPty(ecmd *exec.Cmd, termSize wstore.TermSize) ([]byte, error) {
|
||||||
ecmd.Env = os.Environ()
|
ecmd.Env = os.Environ()
|
||||||
shellutil.UpdateCmdEnv(ecmd, shellutil.WaveshellLocalEnvVars(shellutil.DefaultTermType))
|
shellutil.UpdateCmdEnv(ecmd, shellutil.WaveshellLocalEnvVars(shellutil.DefaultTermType))
|
||||||
if termSize.Rows == 0 || termSize.Cols == 0 {
|
if termSize.Rows == 0 || termSize.Cols == 0 {
|
||||||
|
@ -5,8 +5,10 @@ package utilfn
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"crypto/rand"
|
||||||
"crypto/sha1"
|
"crypto/sha1"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -885,3 +887,15 @@ func WriteTemplateToFile(fileName string, templateText string, vars map[string]s
|
|||||||
template.Must(template.New("").Parse(templateText)).Execute(outBuffer, vars)
|
template.Must(template.New("").Parse(templateText)).Execute(outBuffer, vars)
|
||||||
return os.WriteFile(fileName, outBuffer.Bytes(), 0644)
|
return os.WriteFile(fileName, outBuffer.Bytes(), 0644)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// every byte is 4-bits of randomness
|
||||||
|
func RandomHexString(numHexDigits int) (string, error) {
|
||||||
|
numBytes := (numHexDigits + 1) / 2 // Calculate the number of bytes needed
|
||||||
|
bytes := make([]byte, numBytes)
|
||||||
|
if _, err := rand.Read(bytes); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
hexStr := hex.EncodeToString(bytes)
|
||||||
|
return hexStr[:numHexDigits], nil // Return the exact number of hex digits
|
||||||
|
}
|
||||||
|
@ -7,10 +7,10 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"github.com/wavetermdev/thenextwave/pkg/shellexec"
|
|
||||||
"github.com/wavetermdev/thenextwave/pkg/tsgen/tsgenmeta"
|
"github.com/wavetermdev/thenextwave/pkg/tsgen/tsgenmeta"
|
||||||
"github.com/wavetermdev/thenextwave/pkg/util/utilfn"
|
"github.com/wavetermdev/thenextwave/pkg/util/utilfn"
|
||||||
"github.com/wavetermdev/thenextwave/pkg/wshutil"
|
"github.com/wavetermdev/thenextwave/pkg/wshutil"
|
||||||
|
"github.com/wavetermdev/thenextwave/pkg/wstore"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -45,9 +45,9 @@ func (cmd *WSRpcCommand) GetWSCommand() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type SetBlockTermSizeWSCommand struct {
|
type SetBlockTermSizeWSCommand struct {
|
||||||
WSCommand string `json:"wscommand" tstype:"\"setblocktermsize\""`
|
WSCommand string `json:"wscommand" tstype:"\"setblocktermsize\""`
|
||||||
BlockId string `json:"blockid"`
|
BlockId string `json:"blockid"`
|
||||||
TermSize shellexec.TermSize `json:"termsize"`
|
TermSize wstore.TermSize `json:"termsize"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cmd *SetBlockTermSizeWSCommand) GetWSCommand() string {
|
func (cmd *SetBlockTermSizeWSCommand) GetWSCommand() string {
|
||||||
|
@ -11,7 +11,6 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"github.com/wavetermdev/thenextwave/pkg/ijson"
|
"github.com/wavetermdev/thenextwave/pkg/ijson"
|
||||||
"github.com/wavetermdev/thenextwave/pkg/shellexec"
|
|
||||||
"github.com/wavetermdev/thenextwave/pkg/waveobj"
|
"github.com/wavetermdev/thenextwave/pkg/waveobj"
|
||||||
"github.com/wavetermdev/thenextwave/pkg/wstore"
|
"github.com/wavetermdev/thenextwave/pkg/wstore"
|
||||||
)
|
)
|
||||||
@ -180,10 +179,10 @@ type CommandBlockRestartData struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type CommandBlockInputData struct {
|
type CommandBlockInputData struct {
|
||||||
BlockId string `json:"blockid" wshcontext:"BlockId"`
|
BlockId string `json:"blockid" wshcontext:"BlockId"`
|
||||||
InputData64 string `json:"inputdata64,omitempty"`
|
InputData64 string `json:"inputdata64,omitempty"`
|
||||||
SigName string `json:"signame,omitempty"`
|
SigName string `json:"signame,omitempty"`
|
||||||
TermSize *shellexec.TermSize `json:"termsize,omitempty"`
|
TermSize *wstore.TermSize `json:"termsize,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type CommandFileData struct {
|
type CommandFileData struct {
|
||||||
|
@ -4,8 +4,6 @@
|
|||||||
package wshserver
|
package wshserver
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
|
||||||
"net"
|
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/wavetermdev/thenextwave/pkg/wshrpc"
|
"github.com/wavetermdev/thenextwave/pkg/wshrpc"
|
||||||
@ -17,44 +15,6 @@ const (
|
|||||||
DefaultInputChSize = 32
|
DefaultInputChSize = 32
|
||||||
)
|
)
|
||||||
|
|
||||||
func handleDomainSocketClient(conn net.Conn) {
|
|
||||||
proxy := wshutil.MakeRpcProxy()
|
|
||||||
go func() {
|
|
||||||
writeErr := wshutil.AdaptOutputChToStream(proxy.ToRemoteCh, conn)
|
|
||||||
if writeErr != nil {
|
|
||||||
log.Printf("error writing to domain socket: %v\n", writeErr)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
go func() {
|
|
||||||
// when input is closed, close the connection
|
|
||||||
defer conn.Close()
|
|
||||||
wshutil.AdaptStreamToMsgCh(conn, proxy.FromRemoteCh)
|
|
||||||
}()
|
|
||||||
rpcCtx, err := proxy.HandleAuthentication()
|
|
||||||
if err != nil {
|
|
||||||
conn.Close()
|
|
||||||
log.Printf("error handling authentication: %v\n", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// now that we're authenticated, set the ctx and attach to the router
|
|
||||||
log.Printf("domain socket connection authenticated: %#v\n", rpcCtx)
|
|
||||||
proxy.SetRpcContext(rpcCtx)
|
|
||||||
wshutil.DefaultRouter.RegisterRoute("controller:"+rpcCtx.BlockId, proxy)
|
|
||||||
}
|
|
||||||
|
|
||||||
func RunWshRpcOverListener(listener net.Listener) {
|
|
||||||
defer log.Printf("domain socket listener shutting down\n")
|
|
||||||
for {
|
|
||||||
conn, err := listener.Accept()
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("error accepting connection: %v\n", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
log.Print("got domain socket connection\n")
|
|
||||||
go handleDomainSocketClient(conn)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var waveSrvClient_Singleton *wshutil.WshRpc
|
var waveSrvClient_Singleton *wshutil.WshRpc
|
||||||
var waveSrvClient_Once = &sync.Once{}
|
var waveSrvClient_Once = &sync.Once{}
|
||||||
|
|
||||||
|
@ -302,6 +302,44 @@ func mapClaimsToRpcContext(claims jwt.MapClaims) *wshrpc.RpcContext {
|
|||||||
return rpcCtx
|
return rpcCtx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func RunWshRpcOverListener(listener net.Listener) {
|
||||||
|
defer log.Printf("domain socket listener shutting down\n")
|
||||||
|
for {
|
||||||
|
conn, err := listener.Accept()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("error accepting connection: %v\n", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
log.Print("got domain socket connection\n")
|
||||||
|
go handleDomainSocketClient(conn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleDomainSocketClient(conn net.Conn) {
|
||||||
|
proxy := MakeRpcProxy()
|
||||||
|
go func() {
|
||||||
|
writeErr := AdaptOutputChToStream(proxy.ToRemoteCh, conn)
|
||||||
|
if writeErr != nil {
|
||||||
|
log.Printf("error writing to domain socket: %v\n", writeErr)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
go func() {
|
||||||
|
// when input is closed, close the connection
|
||||||
|
defer conn.Close()
|
||||||
|
AdaptStreamToMsgCh(conn, proxy.FromRemoteCh)
|
||||||
|
}()
|
||||||
|
rpcCtx, err := proxy.HandleAuthentication()
|
||||||
|
if err != nil {
|
||||||
|
conn.Close()
|
||||||
|
log.Printf("error handling authentication: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// now that we're authenticated, set the ctx and attach to the router
|
||||||
|
log.Printf("domain socket connection authenticated: %#v\n", rpcCtx)
|
||||||
|
proxy.SetRpcContext(rpcCtx)
|
||||||
|
DefaultRouter.RegisterRoute("controller:"+rpcCtx.BlockId, proxy)
|
||||||
|
}
|
||||||
|
|
||||||
// only for use on client
|
// only for use on client
|
||||||
func ExtractUnverifiedRpcContext(tokenStr string) (*wshrpc.RpcContext, error) {
|
func ExtractUnverifiedRpcContext(tokenStr string) (*wshrpc.RpcContext, error) {
|
||||||
// this happens on the client who does not have access to the secret key
|
// this happens on the client who does not have access to the secret key
|
||||||
|
@ -8,7 +8,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"github.com/wavetermdev/thenextwave/pkg/shellexec"
|
|
||||||
"github.com/wavetermdev/thenextwave/pkg/waveobj"
|
"github.com/wavetermdev/thenextwave/pkg/waveobj"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -220,8 +219,8 @@ type StickerType struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type RuntimeOpts struct {
|
type RuntimeOpts struct {
|
||||||
TermSize shellexec.TermSize `json:"termsize,omitempty"`
|
TermSize TermSize `json:"termsize,omitempty"`
|
||||||
WinSize WinSize `json:"winsize,omitempty"`
|
WinSize WinSize `json:"winsize,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Point struct {
|
type Point struct {
|
||||||
@ -257,3 +256,8 @@ func AllWaveObjTypes() []reflect.Type {
|
|||||||
reflect.TypeOf(&LayoutState{}),
|
reflect.TypeOf(&LayoutState{}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TermSize struct {
|
||||||
|
Rows int `json:"rows"`
|
||||||
|
Cols int `json:"cols"`
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user