diff --git a/cmd/server/main-server.go b/cmd/server/main-server.go index 076fedd451..a3eef23112 100644 --- a/cmd/server/main-server.go +++ b/cmd/server/main-server.go @@ -259,6 +259,16 @@ func grabAndRemoveEnvVars() error { if err != nil { return err } + + // Remove WAVETERM env vars that leak from prod => dev + os.Unsetenv("WAVETERM_CLIENTID") + os.Unsetenv("WAVETERM_WORKSPACEID") + os.Unsetenv("WAVETERM_TABID") + os.Unsetenv("WAVETERM_BLOCKID") + os.Unsetenv("WAVETERM_CONN") + os.Unsetenv("WAVETERM_JWT") + os.Unsetenv("WAVETERM_VERSION") + return nil } diff --git a/docs/docs/customwidgets.mdx b/docs/docs/customwidgets.mdx index 29f6ac053f..d35d1d84c2 100644 --- a/docs/docs/customwidgets.mdx +++ b/docs/docs/customwidgets.mdx @@ -109,6 +109,7 @@ The `WidgetConfigType` takes the usual options common to all widgets. The `MetaT | "cmd:env" | (optional) A key-value object represting environment variables to be run with the command. Defaults to an empty object. | | "cmd:cwd" | (optional) A string representing the current working directory to be run with the command. Currently only works locally. Defaults to the home directory. | | "cmd:nowsh" | (optional) A boolean that will turn off wsh integration for the command. Defaults to false. | +| "cmd:jwt" | (optional) A boolean that forces adding JWT token to the environment. Required for running waveapps as widgets (both local and remote). Defaults to false. | | "term:localshellpath" | (optional) Sets the shell used for running your widget command. Only works locally. If left blank, wave will determine your system default instead. | | "term:localshellopts" | (optional) Sets the shell options meant to be used with `"term:localshellpath"`. This is useful if you are using a nonstandard shell and need to provide a specific option that we do not cover. Only works locally. Defaults to an empty string. | | "cmd:initscript" | (optional) for "shell" controller only. an init script to run before starting the shell (can be an inline script or an absolute local file path) | diff --git a/frontend/types/gotypes.d.ts b/frontend/types/gotypes.d.ts index b2c89fe3f7..e039c0391b 100644 --- a/frontend/types/gotypes.d.ts +++ b/frontend/types/gotypes.d.ts @@ -536,6 +536,7 @@ declare global { "cmd:args"?: string[]; "cmd:shell"?: boolean; "cmd:allowconnchange"?: boolean; + "cmd:jwt"?: boolean; "cmd:env"?: {[key: string]: string}; "cmd:cwd"?: string; "cmd:initscript"?: string; diff --git a/pkg/blockcontroller/blockcontroller.go b/pkg/blockcontroller/blockcontroller.go index d7363af451..23a3ffdbb6 100644 --- a/pkg/blockcontroller/blockcontroller.go +++ b/pkg/blockcontroller/blockcontroller.go @@ -369,6 +369,7 @@ func createCmdStrAndOpts(blockId string, blockMeta waveobj.MetaMapType, connName cmdStr = cmdStr + " " + utilfn.ShellQuote(arg, false, -1) } } + cmdOpts.ForceJwt = blockMeta.GetBool(waveobj.MetaKey_CmdJwt, false) return cmdStr, &cmdOpts, nil } diff --git a/pkg/shellexec/shellexec.go b/pkg/shellexec/shellexec.go index 564b6c5cf7..30a9871f0d 100644 --- a/pkg/shellexec/shellexec.go +++ b/pkg/shellexec/shellexec.go @@ -11,7 +11,6 @@ import ( "log" "os" "os/exec" - "path/filepath" "runtime" "strings" "sync" @@ -43,6 +42,7 @@ type CommandOptsType struct { ShellPath string `json:"shellPath,omitempty"` ShellOpts []string `json:"shellOpts,omitempty"` SwapToken *shellutil.TokenSwapEntry `json:"swapToken,omitempty"` + ForceJwt bool `json:"forcejwt,omitempty"` } type ShellProc struct { @@ -212,6 +212,7 @@ func StartWslShellProc(ctx context.Context, termSize waveobj.TermSize, cmdStr st shellOpts = append(shellOpts, cmdOpts.ShellOpts...) shellType := shellutil.GetShellTypeFromShellPath(shellPath) conn.Infof(ctx, "detected shell type: %s\n", shellType) + conn.Debugf(ctx, "cmdStr: %q\n", cmdStr) if cmdStr == "" { /* transform command in order to inject environment vars */ @@ -245,7 +246,6 @@ func StartWslShellProc(ctx context.Context, termSize waveobj.TermSize, cmdStr st cmdCombined = fmt.Sprintf("%s %s", shellPath, strings.Join(shellOpts, " ")) } else { // TODO check quoting of cmdStr - shellPath = cmdStr shellOpts = append(shellOpts, "-c", cmdStr) cmdCombined = fmt.Sprintf("%s %s", shellPath, strings.Join(shellOpts, " ")) } @@ -266,6 +266,7 @@ func StartWslShellProc(ctx context.Context, termSize waveobj.TermSize, cmdStr st } jwtToken := cmdOpts.SwapToken.Env[wavebase.WaveJwtTokenVarName] if jwtToken != "" { + conn.Debugf(ctx, "adding JWT token to environment\n") cmdCombined = fmt.Sprintf(`%s=%s %s`, wavebase.WaveJwtTokenVarName, jwtToken, cmdCombined) } log.Printf("full combined command: %s", cmdCombined) @@ -363,6 +364,7 @@ func StartRemoteShellProc(ctx context.Context, logCtx context.Context, termSize shellType := shellutil.GetShellTypeFromShellPath(shellPath) conn.Infof(logCtx, "detected shell type: %s\n", shellType) conn.Infof(logCtx, "swaptoken: %s\n", cmdOpts.SwapToken.Token) + conn.Debugf(logCtx, "cmdStr: %q\n", cmdStr) if cmdStr == "" { /* transform command in order to inject environment vars */ @@ -396,7 +398,6 @@ func StartRemoteShellProc(ctx context.Context, logCtx context.Context, termSize cmdCombined = fmt.Sprintf("%s %s", shellPath, strings.Join(shellOpts, " ")) } else { // TODO check quoting of cmdStr - shellPath = cmdStr shellOpts = append(shellOpts, "-c", cmdStr) cmdCombined = fmt.Sprintf("%s %s", shellPath, strings.Join(shellOpts, " ")) } @@ -442,6 +443,11 @@ func StartRemoteShellProc(ctx context.Context, logCtx context.Context, termSize conn.Debugf(logCtx, "packed swaptoken %s\n", packedToken) cmdCombined = fmt.Sprintf(`%s=%s %s`, wavebase.WaveSwapTokenVarName, packedToken, cmdCombined) } + jwtToken := cmdOpts.SwapToken.Env[wavebase.WaveJwtTokenVarName] + if jwtToken != "" && cmdOpts.ForceJwt { + conn.Debugf(logCtx, "adding JWT token to environment\n") + cmdCombined = fmt.Sprintf(`%s=%s %s`, wavebase.WaveJwtTokenVarName, jwtToken, cmdCombined) + } shellutil.AddTokenSwapEntry(cmdOpts.SwapToken) session.RequestPty("xterm-256color", termSize.Rows, termSize.Cols, nil) sessionWrap := MakeSessionWrap(session, cmdCombined, pipePty) @@ -453,24 +459,6 @@ func StartRemoteShellProc(ctx context.Context, logCtx context.Context, termSize return &ShellProc{Cmd: sessionWrap, ConnName: conn.GetName(), CloseOnce: &sync.Once{}, DoneCh: make(chan any)}, nil } -func isZshShell(shellPath string) bool { - // get the base path, and then check contains - shellBase := filepath.Base(shellPath) - return strings.Contains(shellBase, "zsh") -} - -func isBashShell(shellPath string) bool { - // get the base path, and then check contains - shellBase := filepath.Base(shellPath) - return strings.Contains(shellBase, "bash") -} - -func isFishShell(shellPath string) bool { - // get the base path, and then check contains - shellBase := filepath.Base(shellPath) - return strings.Contains(shellBase, "fish") -} - func StartLocalShellProc(logCtx context.Context, termSize waveobj.TermSize, cmdStr string, cmdOpts CommandOptsType) (*ShellProc, error) { shellutil.InitCustomShellStartupFiles() var ecmd *exec.Cmd @@ -522,6 +510,11 @@ func StartLocalShellProc(logCtx context.Context, termSize waveobj.TermSize, cmdS blocklogger.Debugf(logCtx, "packed swaptoken %s\n", packedToken) shellutil.UpdateCmdEnv(ecmd, map[string]string{wavebase.WaveSwapTokenVarName: packedToken}) } + jwtToken := cmdOpts.SwapToken.Env[wavebase.WaveJwtTokenVarName] + if jwtToken != "" && cmdOpts.ForceJwt { + blocklogger.Debugf(logCtx, "adding JWT token to environment\n") + shellutil.UpdateCmdEnv(ecmd, map[string]string{wavebase.WaveJwtTokenVarName: jwtToken}) + } /* For Snap installations, we need to correct the XDG environment variables as Snap diff --git a/pkg/waveobj/metaconsts.go b/pkg/waveobj/metaconsts.go index 7a45a5804a..0f3eb8fc09 100644 --- a/pkg/waveobj/metaconsts.go +++ b/pkg/waveobj/metaconsts.go @@ -51,6 +51,7 @@ const ( MetaKey_CmdArgs = "cmd:args" MetaKey_CmdShell = "cmd:shell" MetaKey_CmdAllowConnChange = "cmd:allowconnchange" + MetaKey_CmdJwt = "cmd:jwt" MetaKey_CmdEnv = "cmd:env" MetaKey_CmdCwd = "cmd:cwd" MetaKey_CmdInitScript = "cmd:initscript" diff --git a/pkg/waveobj/wtypemeta.go b/pkg/waveobj/wtypemeta.go index c0ebb92919..6fffeb9b7a 100644 --- a/pkg/waveobj/wtypemeta.go +++ b/pkg/waveobj/wtypemeta.go @@ -50,6 +50,7 @@ type MetaTSType struct { CmdArgs []string `json:"cmd:args,omitempty"` // args for cmd (only if cmd:shell is false) CmdShell bool `json:"cmd:shell,omitempty"` // shell expansion for cmd+args (defaults to true) CmdAllowConnChange bool `json:"cmd:allowconnchange,omitempty"` + CmdJwt bool `json:"cmd:jwt,omitempty"` // force adding JWT to environment // these can be nested under "[conn]" CmdEnv map[string]string `json:"cmd:env,omitempty"`