Compare commits

...

5 Commits

Author SHA1 Message Date
Red J Adaya a221655027 new wave modal (#781) 2024-09-20 14:06:51 -07:00
Evan Simkowitz b0025e4b1f Merge bump version workflow (#791) 2024-09-19 14:30:14 -07:00
dependabot[bot] ab200d624d Bump express from 4.19.2 to 4.21.0 (#785) 2024-09-19 00:26:07 -07:00
Sylvie Crowe abe4ae6fea Update AI Library (#784)
The AI library was outdated and seemed to prevent newer project-based
keys from working. This update should hopefully correct that.
2024-09-17 21:24:33 -07:00
Sylvie Crowe 8bb989fc6f Add ssh-agent support to ssh client (#673)
This will attempt to use the ssh agent before trying other ssh keys in
case other integrations are being used through it.

---------

Co-authored-by: Evan Simkowitz <esimkowitz@users.noreply.github.com>
2024-09-17 16:29:26 -07:00
18 changed files with 837 additions and 65 deletions
+83
View File
@@ -0,0 +1,83 @@
# Workflow to manage bumping the package version and pushing it to the target branch with a new tag.
# This workflow uses a GitHub App to bypass branch protection and uses the GitHub API directly to ensure commits and tags are signed.
# For more information, see this doc: https://github.com/Nautilus-Cyberneering/pygithub/blob/main/docs/how_to_sign_automatic_commits_in_github_actions.md
name: Bump Version
run-name: "branch: ${{ github.ref_name }}; semver-bump: ${{ inputs.bump }}; prerelease: ${{ inputs.is-prerelease }}"
on:
workflow_dispatch:
inputs:
bump:
description: SemVer Bump
required: true
type: choice
default: none
options:
- none
- patch
- minor
- major
is-prerelease:
description: Is Prerelease
required: true
type: boolean
default: true
env:
NODE_VERSION: "22.5.1"
jobs:
bump-version:
runs-on: ubuntu-latest
steps:
- name: Get App Token
uses: actions/create-github-app-token@v1
id: app-token
with:
app-id: ${{ vars.WAVE_BUILDER_APPID }}
private-key: ${{ secrets.WAVE_BUILDER_KEY }}
- uses: actions/checkout@v4
with:
token: ${{ steps.app-token.outputs.token }}
# General build dependencies
- uses: actions/setup-node@v4
with:
node-version: ${{env.NODE_VERSION}}
- name: Install Yarn
run: |
corepack enable
yarn install
- name: Install Task
uses: arduino/setup-task@v2
with:
version: 3.x
repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: "Bump Version: ${{ inputs.bump }}"
id: bump-version
run: echo "WAVETERM_VERSION=$( task version -- ${{ inputs.bump }} ${{inputs.is-prerelease}} )" >> "$GITHUB_OUTPUT"
shell: bash
- name: "Push version bump: ${{ steps.bump-version.outputs.WAVETERM_VERSION }}"
run: |
# Create a new commit for the package version bump in package.json
export VERSION=${{ steps.bump-version.outputs.WAVETERM_VERSION }}
export MESSAGE="chore: bump package version to $VERSION"
export FILE=package.json
export BRANCH=${{github.ref_name}}
export SHA=$( git rev-parse $BRANCH:$FILE )
export CONTENT=$( base64 -i $FILE )
gh api --method PUT /repos/:owner/:repo/contents/$FILE \
--field branch="$BRANCH" \
--field message="$MESSAGE" \
--field content="$CONTENT" \
--field sha="$SHA"
# Fetch the new commit and create a tag referencing it
git fetch
export TAG_SHA=$( git rev-parse origin/$BRANCH )
gh api --method POST /repos/:owner/:repo/git/refs \
--field ref="refs/tags/v$VERSION" \
--field sha="$TAG_SHA"
shell: bash
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
+2 -2
View File
@@ -76,7 +76,7 @@ function buildWaveShell {
}
function buildWaveSrv {
# adds -extldflags=-static, *only* on linux (macos does not support fully static binaries) to avoid a glibc dependency
(cd wavesrv; CGO_ENABLED=1 GOARCH=$1 go build -tags "osusergo,netgo,sqlite_omit_load_extension" -ldflags "-linkmode 'external' -extldflags=-static $GO_LDFLAGS -X main.WaveVersion=$WAVESRV_VERSION" -o ../bin/wavesrv.$1 ./cmd)
(cd wavesrv; CGO_ENABLED=1 GOARCH=$1 go build -tags "osusergo,netcgo,sqlite_omit_load_extension" -ldflags "-linkmode 'external' -extldflags=-static $GO_LDFLAGS -X main.WaveVersion=$WAVESRV_VERSION" -o ../bin/wavesrv.$1 ./cmd)
}
buildWaveShell darwin amd64
buildWaveShell darwin arm64
@@ -90,7 +90,7 @@ yarn run electron-builder -c electron-builder.config.js -l -p never
# @scripthaus command build-wavesrv
WAVESRV_VERSION=$(node -e 'console.log(require("./version.js"))')
cd wavesrv
CGO_ENABLED=1 go build -tags "osusergo,netgo,sqlite_omit_load_extension" -ldflags "-X main.BuildTime=$(date +'%Y%m%d%H%M') -X main.WaveVersion=$WAVESRV_VERSION" -o ../bin/wavesrv ./cmd
CGO_ENABLED=1 go build -tags "osusergo,netcgo,sqlite_omit_load_extension" -ldflags "-X main.BuildTime=$(date +'%Y%m%d%H%M') -X main.WaveVersion=$WAVESRV_VERSION" -o ../bin/wavesrv ./cmd
```
```bash
+1
View File
@@ -9,6 +9,7 @@ export const LINE_SETTINGS = "lineSettings";
export const CLIENT_SETTINGS = "clientSettings";
export const TAB_SWITCHER = "tabSwitcher";
export const USER_INPUT = "userInput";
export const NEW_WAVE = "newWave";
export const LineContainer_Main = "main";
export const LineContainer_History = "history";
File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 13 MiB

+1
View File
@@ -10,3 +10,4 @@ export { SessionSettingsModal } from "./sessionsettings";
export { ScreenSettingsModal } from "./screensettings";
export { LineSettingsModal } from "./linesettings";
export { UserInputModal } from "./userinput";
export { NewWaveModal } from "./newwave";
+95
View File
@@ -0,0 +1,95 @@
.newwave-modal {
width: 640px;
border-radius: 8px;
border: 0.5px solid rgba(255, 255, 255, 0.12);
background: #232323;
box-shadow: 0px 8px 32px 0px rgba(0, 0, 0, 0.25);
.wave-modal-content .wave-modal-body {
padding: 0;
gap: 8px;
.wave-modal-body-inner {
gap: 24px;
display: flex;
flex-direction: column;
header.newwave-header {
padding: 24px 32px 0;
position: relative;
flex-direction: column;
gap: 12px;
border-bottom: none;
.modal-title {
text-align: left;
font-size: 20px;
font-weight: normal;
}
.close {
position: absolute;
right: 32px;
top: 24px;
}
}
.content.newwave-content {
display: flex;
flex-direction: column;
align-items: flex-start;
width: 100%;
margin-bottom: 0;
gap: 10px;
.item {
width: 100%;
line-height: 19px;
font-weight: 400;
padding-left: 32px;
padding-right: 32px;
&.image-item {
padding: 0 0;
height: 360px;
}
img {
width: 100%;
margin-bottom: -45px;
}
span {
font-weight: 600;
}
}
}
footer {
padding: 0 32px 24px;
display: flex;
justify-content: flex-end;
.button-wrapper {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
button {
font-size: 15px;
margin-top: 16px;
&:last-child {
margin-left: 10px;
}
}
button.disabled-button {
cursor: default;
}
}
}
}
}
}
+78
View File
@@ -0,0 +1,78 @@
// Copyright 2023, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
import * as React from "react";
import * as mobxReact from "mobx-react";
import { boundMethod } from "autobind-decorator";
import { Modal, Button } from "@/elements";
import { getApi } from "@/models";
import newwave from "@/assets/new-wave-screenshot.svg";
import "./newwave.less";
@mobxReact.observer
class NewWaveModal extends React.Component<{ onClose: () => void }, {}> {
@boundMethod
handleDownloadOldWave(): void {
getApi().openExternalLink("https://www.waveterm.dev/download-legacy");
}
@boundMethod
handleDownloadNewWave(): void {
getApi().openExternalLink("https://www.waveterm.dev/download");
}
@boundMethod
handleClose(): void {
this.props.onClose();
}
render() {
return (
<Modal className="newwave-modal">
<div className="wave-modal-body">
<div className="wave-modal-body-inner">
<header className="newwave-header unselectable">
<div className="modal-title">A New Wave is Coming!</div>
<i className="fa-regular fa-xmark-large close" onClick={this.handleClose}></i>
</header>
<div className="content newwave-content unselectable">
<div className="item">
We are excited to share that after 3-months of work, and almost 1000 new commits, Wave
v0.8 is now available. It features a new layout engine for screen splitting, improved
remote file browsing and previewing, improved performance, and a new design. We've also
removed some of the more controversial features that took over the shell experience and
overrode things like completions, history, and prompts.
</div>
<div className="item">
The new build is a fresh start, and a clean break from the current version. As such,
your history, settings, and configuration will <i>not</i> be carried over. If you'd like
to continue to run the legacy version, you will need to download it separately.
</div>
<div className="item image-item">
<img src={newwave} height="400px" />
</div>
<div className="item">
You can download Wave v0.8 now or wait for an auto-update next week. The legacy version
will be available via separate download page.
</div>
</div>
<footer className="unselectable">
<div className="button-wrapper">
<Button className="secondary" onClick={this.handleDownloadOldWave}>
Legacy Download
</Button>
</div>
<div className="button-wrapper">
<Button onClick={this.handleDownloadNewWave}>Upgrade to Wave v0.8</Button>
</div>
</footer>
</div>
</div>
</Modal>
);
}
}
export { NewWaveModal };
+21 -1
View File
@@ -5,14 +5,34 @@ import * as React from "react";
import * as mobxReact from "mobx-react";
import { GlobalModel } from "@/models";
import { TosModal } from "./tos";
import { NewWaveModal } from "./newwave";
const SessionStorageKey = "newWaveRendered";
@mobxReact.observer
class ModalsProvider extends React.Component {
class ModalsProvider extends React.Component<{}, {}> {
constructor(props) {
super(props);
this.handleNewWaveOnClose = this.handleNewWaveOnClose.bind(this);
}
handleNewWaveOnClose() {
sessionStorage.setItem(SessionStorageKey, "1");
this.forceUpdate();
}
render() {
let store = GlobalModel.modalsModel.store.slice();
if (GlobalModel.needsTos()) {
return <TosModal />;
}
const newWaveRendered = sessionStorage.getItem(SessionStorageKey);
if (!newWaveRendered) {
return <NewWaveModal onClose={this.handleNewWaveOnClose} />;
}
let rtn: JSX.Element[] = [];
for (let i = 0; i < store.length; i++) {
let entry = store[i];
+2
View File
@@ -13,6 +13,7 @@ import {
ScreenSettingsModal,
LineSettingsModal,
UserInputModal,
NewWaveModal,
} from "@/modals";
import * as constants from "@/app/appconst";
@@ -27,6 +28,7 @@ const modalsRegistry: { [key: string]: React.ComponentType } = {
[constants.LINE_SETTINGS]: LineSettingsModal,
[constants.TAB_SWITCHER]: TabSwitcherModal,
[constants.USER_INPUT]: UserInputModal,
[constants.NEW_WAVE]: NewWaveModal,
};
export { modalsRegistry };
+24
View File
@@ -18,6 +18,7 @@ import (
"os/exec"
"regexp"
"sort"
"strconv"
"strings"
"syscall"
"unicode/utf8"
@@ -673,3 +674,26 @@ func GetFirstLine(s string) string {
}
return s[0:idx]
}
func TrimQuotes(s string) (string, bool) {
if len(s) > 2 && s[0] == '"' {
trimmed, err := strconv.Unquote(s)
if err != nil {
return s, false
}
return trimmed, true
}
return s, false
}
func TryTrimQuotes(s string) string {
trimmed, _ := TrimQuotes(s)
return trimmed
}
func ReplaceQuotes(s string, shouldReplace bool) string {
if shouldReplace {
return strconv.Quote(s)
}
return s
}
+1 -1
View File
@@ -17,7 +17,7 @@ require (
github.com/jmoiron/sqlx v1.3.5
github.com/kevinburke/ssh_config v1.2.0
github.com/mattn/go-sqlite3 v1.14.16
github.com/sashabaranov/go-openai v1.9.0
github.com/sashabaranov/go-openai v1.30.0
github.com/sawka/txwrap v0.1.2
github.com/wavetermdev/waveterm/waveshell v0.0.0
golang.org/x/crypto v0.24.0
+2
View File
@@ -51,6 +51,8 @@ github.com/rogpeppe/go-internal v1.10.1-0.20230524175051-ec119421bb97 h1:3RPlVWz
github.com/rogpeppe/go-internal v1.10.1-0.20230524175051-ec119421bb97/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
github.com/sashabaranov/go-openai v1.9.0 h1:NoiO++IISxxJ1pRc0n7uZvMGMake0G+FJ1XPwXtprsA=
github.com/sashabaranov/go-openai v1.9.0/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg=
github.com/sashabaranov/go-openai v1.30.0 h1:fHv9urGxABfm885xGWsXFSk5cksa+8dJ4jGli/UQQcI=
github.com/sashabaranov/go-openai v1.30.0/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg=
github.com/sawka/txwrap v0.1.2 h1:v8xS0Z1LE7/6vMZA81PYihI+0TSR6Zm1MalzzBIuXKc=
github.com/sawka/txwrap v0.1.2/go.mod h1:T3nlw2gVpuolo6/XEetvBbk1oMXnY978YmBFy1UyHvw=
github.com/skeema/knownhosts v1.3.0 h1:AM+y0rI04VksttfwjkSTNQorvGqmwATnvnAHpSgc0LY=
+8 -1
View File
@@ -167,7 +167,14 @@ func SendTelemetry(ctx context.Context, force bool) error {
log.Printf("[pcloud] sending telemetry data\n")
dayStr := telemetry.GetCurDayStr()
defaultShellType := shellapi.DetectLocalShellType()
input := TelemetryInputType{UserId: clientData.UserId, ClientId: clientData.ClientId, CurDay: dayStr, DefaultShell: defaultShellType, Activity: activity}
input := TelemetryInputType{
UserId: clientData.UserId,
ClientId: clientData.ClientId,
AppType: "wave",
CurDay: dayStr,
DefaultShell: defaultShellType,
Activity: activity,
}
req, err := makeAnonPostReq(ctx, TelemetryUrl, input)
if err != nil {
return err
+1
View File
@@ -22,6 +22,7 @@ type NoTelemetryInputType struct {
type TelemetryInputType struct {
UserId string `json:"userid"`
ClientId string `json:"clientid"`
AppType string `json:"apptype"`
CurDay string `json:"curday"`
DefaultShell string `json:"defaultshell"`
Activity []*telemetry.ActivityType `json:"activity"`
+2 -2
View File
@@ -190,7 +190,7 @@ func RunCompletionStream(ctx context.Context, opts *sstore.OpenAIOptsType, promp
pk := packet.MakeOpenAIPacket()
pk.Index = choice.Index
pk.Text = choice.Delta.Content
pk.FinishReason = choice.FinishReason
pk.FinishReason = string(choice.FinishReason)
rtn <- pk
}
}
@@ -209,7 +209,7 @@ func marshalResponse(resp openaiapi.ChatCompletionResponse) []*packet.OpenAIPack
choicePk := packet.MakeOpenAIPacket()
choicePk.Index = choice.Index
choicePk.Text = choice.Message.Content
choicePk.FinishReason = choice.FinishReason
choicePk.FinishReason = string(choice.FinishReason)
rtn = append(rtn, choicePk)
}
return rtn
+5 -3
View File
@@ -1314,14 +1314,15 @@ func (wsh *WaveshellProc) RunInstall(autoInstall bool) {
wsh.WriteToPtyBuffer("*error: cannot install on a local remote\n")
return
}
_, err = shellapi.MakeShellApi(packet.ShellType_bash)
sapi, err := shellapi.MakeShellApi(wsh.GetShellType())
if err != nil {
wsh.WriteToPtyBuffer("*error: %v\n", err)
return
}
if wsh.Client == nil {
remoteDisplayName := fmt.Sprintf("%s [%s]", remoteCopy.RemoteAlias, remoteCopy.RemoteCanonicalName)
client, err := ConnectToClient(makeClientCtx, remoteCopy.SSHOpts, remoteDisplayName)
sshAuthSock, _ := exec.CommandContext(makeClientCtx, sapi.GetLocalShellPath(), "-c", "echo \"${SSH_AUTH_SOCK}\"").CombinedOutput()
client, err := ConnectToClient(makeClientCtx, remoteCopy.SSHOpts, remoteDisplayName, strings.TrimSpace(string(sshAuthSock)))
if err != nil {
statusErr := fmt.Errorf("ssh cannot connect to client: %w", err)
wsh.setInstallErrorStatus(statusErr)
@@ -1614,7 +1615,8 @@ func (wsh *WaveshellProc) createWaveshellSession(clientCtx context.Context, remo
wsSession = shexec.CmdWrap{Cmd: ecmd}
} else if wsh.Client == nil {
remoteDisplayName := fmt.Sprintf("%s [%s]", remoteCopy.RemoteAlias, remoteCopy.RemoteCanonicalName)
client, err := ConnectToClient(clientCtx, remoteCopy.SSHOpts, remoteDisplayName)
sshAuthSock, _ := exec.CommandContext(clientCtx, sapi.GetLocalShellPath(), "-c", "echo \"${SSH_AUTH_SOCK}\"").CombinedOutput()
client, err := ConnectToClient(clientCtx, remoteCopy.SSHOpts, remoteDisplayName, strings.TrimSpace(string(sshAuthSock)))
if err != nil {
return nil, fmt.Errorf("ssh cannot connect to client: %w", err)
}
+90 -9
View File
@@ -24,10 +24,12 @@ import (
"github.com/kevinburke/ssh_config"
"github.com/skeema/knownhosts"
"github.com/wavetermdev/waveterm/waveshell/pkg/base"
"github.com/wavetermdev/waveterm/waveshell/pkg/utilfn"
"github.com/wavetermdev/waveterm/wavesrv/pkg/scbus"
"github.com/wavetermdev/waveterm/wavesrv/pkg/sstore"
"github.com/wavetermdev/waveterm/wavesrv/pkg/userinput"
"golang.org/x/crypto/ssh"
"golang.org/x/crypto/ssh/agent"
xknownhosts "golang.org/x/crypto/ssh/knownhosts"
)
@@ -68,7 +70,7 @@ func createDummySigner() ([]ssh.Signer, error) {
// they were successes. An error in this function prevents any other
// keys from being attempted. But if there's an error because of a dummy
// file, the library can still try again with a new key.
func createPublicKeyCallback(connCtx context.Context, sshKeywords *SshKeywords, passphrase string) func() ([]ssh.Signer, error) {
func createPublicKeyCallback(connCtx context.Context, sshKeywords *SshKeywords, passphrase string, authSockSignersExt []ssh.Signer, agentClient agent.ExtendedAgent) func() ([]ssh.Signer, error) {
var identityFiles []string
existingKeys := make(map[string][]byte)
@@ -86,7 +88,19 @@ func createPublicKeyCallback(connCtx context.Context, sshKeywords *SshKeywords,
// require pointer to modify list in closure
identityFilesPtr := &identityFiles
var authSockSigners []ssh.Signer
authSockSigners = append(authSockSigners, authSockSignersExt...)
authSockSignersPtr := &authSockSigners
return func() ([]ssh.Signer, error) {
// try auth sock
if len(*authSockSignersPtr) != 0 {
authSockSigner := (*authSockSignersPtr)[0]
*authSockSignersPtr = (*authSockSignersPtr)[1:]
return []ssh.Signer{authSockSigner}, nil
}
// try manual identity files
if len(*identityFilesPtr) == 0 {
return nil, fmt.Errorf("no identity files remaining")
}
@@ -98,6 +112,24 @@ func createPublicKeyCallback(connCtx context.Context, sshKeywords *SshKeywords,
// skip this key and try with the next
return createDummySigner()
}
unencryptedPrivateKey, err := ssh.ParseRawPrivateKey(privateKey)
if err == nil {
signer, err := ssh.NewSignerFromKey(unencryptedPrivateKey)
if err == nil {
if sshKeywords.AddKeysToAgent && agentClient != nil {
agentClient.Add(agent.AddedKey{
PrivateKey: unencryptedPrivateKey,
})
}
return []ssh.Signer{signer}, err
}
}
if _, ok := err.(*ssh.PassphraseMissingError); !ok {
// skip this key and try with the next
return createDummySigner()
}
signer, err := ssh.ParsePrivateKey(privateKey)
if err == nil {
return []ssh.Signer{signer}, err
@@ -107,9 +139,17 @@ func createPublicKeyCallback(connCtx context.Context, sshKeywords *SshKeywords,
return createDummySigner()
}
signer, err = ssh.ParsePrivateKeyWithPassphrase(privateKey, []byte(passphrase))
unencryptedPrivateKey, err = ssh.ParseRawPrivateKeyWithPassphrase(privateKey, []byte(passphrase))
if err == nil {
return []ssh.Signer{signer}, err
signer, err := ssh.NewSignerFromKey(unencryptedPrivateKey)
if err == nil {
if sshKeywords.AddKeysToAgent && agentClient != nil {
agentClient.Add(agent.AddedKey{
PrivateKey: unencryptedPrivateKey,
})
}
return []ssh.Signer{signer}, err
}
}
if err != x509.IncorrectPasswordError && err.Error() != "bcrypt_pbkdf: empty password" {
// skip this key and try with the next
@@ -135,11 +175,22 @@ func createPublicKeyCallback(connCtx context.Context, sshKeywords *SshKeywords,
// trying keys
return nil, UserInputCancelError{Err: err}
}
signer, err = ssh.ParsePrivateKeyWithPassphrase(privateKey, []byte(response.Text))
unencryptedPrivateKey, err = ssh.ParseRawPrivateKeyWithPassphrase(privateKey, []byte([]byte(response.Text)))
if err != nil {
// skip this key and try with the next
return createDummySigner()
}
signer, err = ssh.NewSignerFromKey(unencryptedPrivateKey)
if err != nil {
// skip this key and try with the next
return createDummySigner()
}
if sshKeywords.AddKeysToAgent && agentClient != nil {
agentClient.Add(agent.AddedKey{
PrivateKey: unencryptedPrivateKey,
})
}
return []ssh.Signer{signer}, err
}
}
@@ -538,8 +589,8 @@ func DialContext(ctx context.Context, network string, addr string, config *ssh.C
return ssh.NewClient(c, chans, reqs), nil
}
func ConnectToClient(connCtx context.Context, opts *sstore.SSHOpts, remoteDisplayName string) (*ssh.Client, error) {
sshConfigKeywords, err := findSshConfigKeywords(opts.SSHHost)
func ConnectToClient(connCtx context.Context, opts *sstore.SSHOpts, remoteDisplayName string, sshAuthSock string) (*ssh.Client, error) {
sshConfigKeywords, err := findSshConfigKeywords(opts.SSHHost, sshAuthSock)
if err != nil {
return nil, err
}
@@ -549,7 +600,17 @@ func ConnectToClient(connCtx context.Context, opts *sstore.SSHOpts, remoteDispla
return nil, err
}
publicKeyCallback := ssh.PublicKeysCallback(createPublicKeyCallback(connCtx, sshKeywords, opts.SSHPassword))
conn, err := net.Dial("unix", sshKeywords.IdentityAgent)
var authSockSigners []ssh.Signer
var agentClient agent.ExtendedAgent
if err != nil {
log.Printf("Failed to open Identity Agent Socket: %v", err)
} else {
agentClient = agent.NewClient(conn)
authSockSigners, _ = agentClient.Signers()
}
publicKeyCallback := ssh.PublicKeysCallback(createPublicKeyCallback(connCtx, sshKeywords, opts.SSHPassword, authSockSigners, agentClient))
keyboardInteractive := ssh.KeyboardInteractive(createCombinedKbdInteractiveChallenge(connCtx, opts.SSHPassword, remoteDisplayName))
passwordCallback := ssh.PasswordCallback(createCombinedPasswordCallbackPrompt(connCtx, opts.SSHPassword, remoteDisplayName))
@@ -564,7 +625,7 @@ func ConnectToClient(connCtx context.Context, opts *sstore.SSHOpts, remoteDispla
// exclude gssapi-with-mic and hostbased until implemented
authMethodMap := map[string]ssh.AuthMethod{
"publickey": ssh.RetryableAuthMethod(publicKeyCallback, len(sshKeywords.IdentityFile)),
"publickey": ssh.RetryableAuthMethod(publicKeyCallback, len(sshKeywords.IdentityFile)+len(authSockSigners)),
"keyboard-interactive": ssh.RetryableAuthMethod(keyboardInteractive, attemptsAllowed),
"password": ssh.RetryableAuthMethod(passwordCallback, attemptsAllowed),
}
@@ -613,6 +674,8 @@ type SshKeywords struct {
PasswordAuthentication bool
KbdInteractiveAuthentication bool
PreferredAuthentications []string
AddKeysToAgent bool
IdentityAgent string
}
func combineSshKeywords(opts *sstore.SSHOpts, configKeywords *SshKeywords) (*SshKeywords, error) {
@@ -662,6 +725,8 @@ func combineSshKeywords(opts *sstore.SSHOpts, configKeywords *SshKeywords) (*Ssh
sshKeywords.PasswordAuthentication = configKeywords.PasswordAuthentication
sshKeywords.KbdInteractiveAuthentication = configKeywords.KbdInteractiveAuthentication
sshKeywords.PreferredAuthentications = configKeywords.PreferredAuthentications
sshKeywords.AddKeysToAgent = configKeywords.AddKeysToAgent
sshKeywords.IdentityAgent = configKeywords.IdentityAgent
return sshKeywords, nil
}
@@ -669,7 +734,7 @@ func combineSshKeywords(opts *sstore.SSHOpts, configKeywords *SshKeywords) (*Ssh
// note that a `var == "yes"` will default to false
// but `var != "no"` will default to true
// when given unexpected strings
func findSshConfigKeywords(hostPattern string) (*SshKeywords, error) {
func findSshConfigKeywords(hostPattern string, sshAuthSock string) (*SshKeywords, error) {
ssh_config.ReloadConfigs()
sshKeywords := &SshKeywords{}
var err error
@@ -724,5 +789,21 @@ func findSshConfigKeywords(hostPattern string) (*SshKeywords, error) {
}
sshKeywords.PreferredAuthentications = strings.Split(preferredAuthenticationsRaw, ",")
addKeysToAgentRaw, err := ssh_config.GetStrict(hostPattern, "AddKeysToAgent")
if err != nil {
return nil, err
}
sshKeywords.AddKeysToAgent = (strings.ToLower(addKeysToAgentRaw) == "yes")
identityAgentRaw, err := ssh_config.GetStrict(hostPattern, "IdentityAgent")
if err != nil {
return nil, err
}
if identityAgentRaw == "" {
sshKeywords.IdentityAgent = base.ExpandHomeDir(utilfn.TryTrimQuotes(strings.TrimSpace(string(sshAuthSock))))
} else {
sshKeywords.IdentityAgent = base.ExpandHomeDir(utilfn.TryTrimQuotes(identityAgentRaw))
}
return sshKeywords, nil
}
+99 -46
View File
@@ -5168,9 +5168,9 @@ __metadata:
languageName: node
linkType: hard
"body-parser@npm:1.20.2":
version: 1.20.2
resolution: "body-parser@npm:1.20.2"
"body-parser@npm:1.20.3":
version: 1.20.3
resolution: "body-parser@npm:1.20.3"
dependencies:
bytes: "npm:3.1.2"
content-type: "npm:~1.0.5"
@@ -5180,11 +5180,11 @@ __metadata:
http-errors: "npm:2.0.0"
iconv-lite: "npm:0.4.24"
on-finished: "npm:2.4.1"
qs: "npm:6.11.0"
qs: "npm:6.13.0"
raw-body: "npm:2.5.2"
type-is: "npm:~1.6.18"
unpipe: "npm:1.0.0"
checksum: 10c0/06f1438fff388a2e2354c96aa3ea8147b79bfcb1262dfcc2aae68ec13723d01d5781680657b74e9f83c808266d5baf52804032fbde2b7382b89bd8cdb273ace9
checksum: 10c0/0a9a93b7518f222885498dcecaad528cf010dd109b071bf471c93def4bfe30958b83e03496eb9c1ad4896db543d999bb62be1a3087294162a88cfa1b42c16310
languageName: node
linkType: hard
@@ -5479,6 +5479,19 @@ __metadata:
languageName: node
linkType: hard
"call-bind@npm:^1.0.7":
version: 1.0.7
resolution: "call-bind@npm:1.0.7"
dependencies:
es-define-property: "npm:^1.0.0"
es-errors: "npm:^1.3.0"
function-bind: "npm:^1.1.2"
get-intrinsic: "npm:^1.2.4"
set-function-length: "npm:^1.2.1"
checksum: 10c0/a3ded2e423b8e2a265983dba81c27e125b48eefb2655e7dfab6be597088da3d47c47976c24bc51b8fd9af1061f8f87b4ab78a314f3c77784b2ae2ba535ad8b8d
languageName: node
linkType: hard
"callsites@npm:^3.0.0":
version: 3.1.0
resolution: "callsites@npm:3.1.0"
@@ -6281,7 +6294,7 @@ __metadata:
languageName: node
linkType: hard
"define-data-property@npm:^1.0.1":
"define-data-property@npm:^1.0.1, define-data-property@npm:^1.1.4":
version: 1.1.4
resolution: "define-data-property@npm:1.1.4"
dependencies:
@@ -6732,6 +6745,13 @@ __metadata:
languageName: node
linkType: hard
"encodeurl@npm:~2.0.0":
version: 2.0.0
resolution: "encodeurl@npm:2.0.0"
checksum: 10c0/5d317306acb13e6590e28e27924c754163946a2480de11865c991a3a7eed4315cd3fba378b543ca145829569eefe9b899f3d84bb09870f675ae60bc924b01ceb
languageName: node
linkType: hard
"encoding@npm:^0.1.13":
version: 0.1.13
resolution: "encoding@npm:0.1.13"
@@ -6968,41 +6988,41 @@ __metadata:
linkType: hard
"express@npm:^4.17.3":
version: 4.19.2
resolution: "express@npm:4.19.2"
version: 4.21.0
resolution: "express@npm:4.21.0"
dependencies:
accepts: "npm:~1.3.8"
array-flatten: "npm:1.1.1"
body-parser: "npm:1.20.2"
body-parser: "npm:1.20.3"
content-disposition: "npm:0.5.4"
content-type: "npm:~1.0.4"
cookie: "npm:0.6.0"
cookie-signature: "npm:1.0.6"
debug: "npm:2.6.9"
depd: "npm:2.0.0"
encodeurl: "npm:~1.0.2"
encodeurl: "npm:~2.0.0"
escape-html: "npm:~1.0.3"
etag: "npm:~1.8.1"
finalhandler: "npm:1.2.0"
finalhandler: "npm:1.3.1"
fresh: "npm:0.5.2"
http-errors: "npm:2.0.0"
merge-descriptors: "npm:1.0.1"
merge-descriptors: "npm:1.0.3"
methods: "npm:~1.1.2"
on-finished: "npm:2.4.1"
parseurl: "npm:~1.3.3"
path-to-regexp: "npm:0.1.7"
path-to-regexp: "npm:0.1.10"
proxy-addr: "npm:~2.0.7"
qs: "npm:6.11.0"
qs: "npm:6.13.0"
range-parser: "npm:~1.2.1"
safe-buffer: "npm:5.2.1"
send: "npm:0.18.0"
serve-static: "npm:1.15.0"
send: "npm:0.19.0"
serve-static: "npm:1.16.2"
setprototypeof: "npm:1.2.0"
statuses: "npm:2.0.1"
type-is: "npm:~1.6.18"
utils-merge: "npm:1.0.1"
vary: "npm:~1.1.2"
checksum: 10c0/e82e2662ea9971c1407aea9fc3c16d6b963e55e3830cd0ef5e00b533feda8b770af4e3be630488ef8a752d7c75c4fcefb15892868eeaafe7353cb9e3e269fdcb
checksum: 10c0/4cf7ca328f3fdeb720f30ccb2ea7708bfa7d345f9cc460b64a82bf1b2c91e5b5852ba15a9a11b2a165d6089acf83457fc477dc904d59cd71ed34c7a91762c6cc
languageName: node
linkType: hard
@@ -7145,18 +7165,18 @@ __metadata:
languageName: node
linkType: hard
"finalhandler@npm:1.2.0":
version: 1.2.0
resolution: "finalhandler@npm:1.2.0"
"finalhandler@npm:1.3.1":
version: 1.3.1
resolution: "finalhandler@npm:1.3.1"
dependencies:
debug: "npm:2.6.9"
encodeurl: "npm:~1.0.2"
encodeurl: "npm:~2.0.0"
escape-html: "npm:~1.0.3"
on-finished: "npm:2.4.1"
parseurl: "npm:~1.3.3"
statuses: "npm:2.0.1"
unpipe: "npm:~1.0.0"
checksum: 10c0/64b7e5ff2ad1fcb14931cd012651631b721ce657da24aedb5650ddde9378bf8e95daa451da43398123f5de161a81e79ff5affe4f9f2a6d2df4a813d6d3e254b7
checksum: 10c0/d38035831865a49b5610206a3a9a9aae4e8523cbbcd01175d0480ffbf1278c47f11d89be3ca7f617ae6d94f29cf797546a4619cd84dd109009ef33f12f69019f
languageName: node
linkType: hard
@@ -7669,7 +7689,7 @@ __metadata:
languageName: node
linkType: hard
"has-property-descriptors@npm:^1.0.0":
"has-property-descriptors@npm:^1.0.0, has-property-descriptors@npm:^1.0.2":
version: 1.0.2
resolution: "has-property-descriptors@npm:1.0.2"
dependencies:
@@ -9184,10 +9204,10 @@ __metadata:
languageName: node
linkType: hard
"merge-descriptors@npm:1.0.1":
version: 1.0.1
resolution: "merge-descriptors@npm:1.0.1"
checksum: 10c0/b67d07bd44cfc45cebdec349bb6e1f7b077ee2fd5beb15d1f7af073849208cb6f144fe403e29a36571baf3f4e86469ac39acf13c318381e958e186b2766f54ec
"merge-descriptors@npm:1.0.3":
version: 1.0.3
resolution: "merge-descriptors@npm:1.0.3"
checksum: 10c0/866b7094afd9293b5ea5dcd82d71f80e51514bed33b4c4e9f516795dc366612a4cbb4dc94356e943a8a6914889a914530badff27f397191b9b75cda20b6bae93
languageName: node
linkType: hard
@@ -10124,6 +10144,13 @@ __metadata:
languageName: node
linkType: hard
"object-inspect@npm:^1.13.1":
version: 1.13.2
resolution: "object-inspect@npm:1.13.2"
checksum: 10c0/b97835b4c91ec37b5fd71add84f21c3f1047d1d155d00c0fcd6699516c256d4fcc6ff17a1aced873197fe447f91a3964178fd2a67a1ee2120cdaf60e81a050b4
languageName: node
linkType: hard
"object-inspect@npm:^1.9.0":
version: 1.13.1
resolution: "object-inspect@npm:1.13.1"
@@ -10452,10 +10479,10 @@ __metadata:
languageName: node
linkType: hard
"path-to-regexp@npm:0.1.7":
version: 0.1.7
resolution: "path-to-regexp@npm:0.1.7"
checksum: 10c0/50a1ddb1af41a9e68bd67ca8e331a705899d16fb720a1ea3a41e310480948387daf603abb14d7b0826c58f10146d49050a1291ba6a82b78a382d1c02c0b8f905
"path-to-regexp@npm:0.1.10":
version: 0.1.10
resolution: "path-to-regexp@npm:0.1.10"
checksum: 10c0/34196775b9113ca6df88e94c8d83ba82c0e1a2063dd33bfe2803a980da8d49b91db8104f49d5191b44ea780d46b8670ce2b7f4a5e349b0c48c6779b653f1afe4
languageName: node
linkType: hard
@@ -10740,12 +10767,12 @@ __metadata:
languageName: node
linkType: hard
"qs@npm:6.11.0":
version: 6.11.0
resolution: "qs@npm:6.11.0"
"qs@npm:6.13.0":
version: 6.13.0
resolution: "qs@npm:6.13.0"
dependencies:
side-channel: "npm:^1.0.4"
checksum: 10c0/4e4875e4d7c7c31c233d07a448e7e4650f456178b9dd3766b7cfa13158fdb24ecb8c4f059fa91e820dc6ab9f2d243721d071c9c0378892dcdad86e9e9a27c68f
side-channel: "npm:^1.0.6"
checksum: 10c0/62372cdeec24dc83a9fb240b7533c0fdcf0c5f7e0b83343edd7310f0ab4c8205a5e7c56406531f2e47e1b4878a3821d652be4192c841de5b032ca83619d8f860
languageName: node
linkType: hard
@@ -11450,9 +11477,9 @@ __metadata:
languageName: node
linkType: hard
"send@npm:0.18.0":
version: 0.18.0
resolution: "send@npm:0.18.0"
"send@npm:0.19.0":
version: 0.19.0
resolution: "send@npm:0.19.0"
dependencies:
debug: "npm:2.6.9"
depd: "npm:2.0.0"
@@ -11467,7 +11494,7 @@ __metadata:
on-finished: "npm:2.4.1"
range-parser: "npm:~1.2.1"
statuses: "npm:2.0.1"
checksum: 10c0/0eb134d6a51fc13bbcb976a1f4214ea1e33f242fae046efc311e80aff66c7a43603e26a79d9d06670283a13000e51be6e0a2cb80ff0942eaf9f1cd30b7ae736a
checksum: 10c0/ea3f8a67a8f0be3d6bf9080f0baed6d2c51d11d4f7b4470de96a5029c598a7011c497511ccc28968b70ef05508675cebff27da9151dd2ceadd60be4e6cf845e3
languageName: node
linkType: hard
@@ -11504,15 +11531,15 @@ __metadata:
languageName: node
linkType: hard
"serve-static@npm:1.15.0":
version: 1.15.0
resolution: "serve-static@npm:1.15.0"
"serve-static@npm:1.16.2":
version: 1.16.2
resolution: "serve-static@npm:1.16.2"
dependencies:
encodeurl: "npm:~1.0.2"
encodeurl: "npm:~2.0.0"
escape-html: "npm:~1.0.3"
parseurl: "npm:~1.3.3"
send: "npm:0.18.0"
checksum: 10c0/fa9f0e21a540a28f301258dfe1e57bb4f81cd460d28f0e973860477dd4acef946a1f41748b5bd41c73b621bea2029569c935faa38578fd34cd42a9b4947088ba
send: "npm:0.19.0"
checksum: 10c0/528fff6f5e12d0c5a391229ad893910709bc51b5705962b09404a1d813857578149b8815f35d3ee5752f44cd378d0f31669d4b1d7e2d11f41e08283d5134bd1f
languageName: node
linkType: hard
@@ -11535,6 +11562,20 @@ __metadata:
languageName: node
linkType: hard
"set-function-length@npm:^1.2.1":
version: 1.2.2
resolution: "set-function-length@npm:1.2.2"
dependencies:
define-data-property: "npm:^1.1.4"
es-errors: "npm:^1.3.0"
function-bind: "npm:^1.1.2"
get-intrinsic: "npm:^1.2.4"
gopd: "npm:^1.0.1"
has-property-descriptors: "npm:^1.0.2"
checksum: 10c0/82850e62f412a258b71e123d4ed3873fa9377c216809551192bb6769329340176f109c2eeae8c22a8d386c76739855f78e8716515c818bcaef384b51110f0f3c
languageName: node
linkType: hard
"setprototypeof@npm:1.1.0":
version: 1.1.0
resolution: "setprototypeof@npm:1.1.0"
@@ -11592,6 +11633,18 @@ __metadata:
languageName: node
linkType: hard
"side-channel@npm:^1.0.6":
version: 1.0.6
resolution: "side-channel@npm:1.0.6"
dependencies:
call-bind: "npm:^1.0.7"
es-errors: "npm:^1.3.0"
get-intrinsic: "npm:^1.2.4"
object-inspect: "npm:^1.13.1"
checksum: 10c0/d2afd163dc733cc0a39aa6f7e39bf0c436293510dbccbff446733daeaf295857dbccf94297092ec8c53e2503acac30f0b78830876f0485991d62a90e9cad305f
languageName: node
linkType: hard
"signal-exit@npm:^3.0.2, signal-exit@npm:^3.0.3, signal-exit@npm:^3.0.7":
version: 3.0.7
resolution: "signal-exit@npm:3.0.7"