Просмотр исходного кода

bump russh for keyboard-interactive fixes and lock race fix

Eugene 11 месяцев назад
Родитель
Сommit
92c729dada
3 измененных файлов с 50 добавлено и 20 удалено
  1. 1 1
      app/package.json
  2. 4 4
      app/yarn.lock
  3. 45 15
      tabby-ssh/src/session/ssh.ts

+ 1 - 1
app/package.json

@@ -30,7 +30,7 @@
     "native-process-working-directory": "^1.0.2",
     "npm": "6",
     "rxjs": "^7.5.7",
-    "russh": "0.1.11",
+    "russh": "0.1.13",
     "source-map-support": "^0.5.20",
     "v8-compile-cache": "^2.3.0",
     "yargs": "^17.7.2"

+ 4 - 4
app/yarn.lock

@@ -3628,10 +3628,10 @@ run-queue@^1.0.0, run-queue@^1.0.3:
   dependencies:
     aproba "^1.1.1"
 
[email protected]1:
-  version "0.1.11"
-  resolved "https://registry.yarnpkg.com/russh/-/russh-0.1.11.tgz#22e74f93ec1cb045930c85f8ba1daf2e5efcae4b"
-  integrity sha512-3CuI+rMoGpnnFDJxsEmcHYRSHInf3bz3fbgeyPnX8n1wgsX6wdbyI1DKL188oQlsrFWEjO3/7ebbYliCi0Qz7w==
[email protected]3:
+  version "0.1.13"
+  resolved "https://registry.yarnpkg.com/russh/-/russh-0.1.13.tgz#e5e1d1b3b7fcd62992df8efce5300b3f57262df5"
+  integrity sha512-5yLxrsC0rYtfynkCLIdeS2XHQKwMEFeww3XoEezaNSHks9grbHbLxgfWBnZ7ZJgrCrJCRgSOvu6Ct5GKpYgb7w==
   dependencies:
     "@napi-rs/cli" "^2.18.3"
 

+ 45 - 15
tabby-ssh/src/session/ssh.ts

@@ -50,6 +50,18 @@ type AuthMethod = {
     kind: 'pageant',
 }
 
+function sshAuthTypeForMethod (m: AuthMethod): string {
+    switch (m.type) {
+        case 'none': return 'none'
+        case 'hostbased': return 'hostbased'
+        case 'prompt-password': return 'password'
+        case 'saved-password': return 'password'
+        case 'keyboard-interactive': return 'keyboard-interactive'
+        case 'publickey': return 'publickey'
+        case 'agent': return 'agent'
+    }
+}
+
 export class KeyboardInteractivePrompt {
     readonly responses: string[] = []
 
@@ -181,6 +193,13 @@ export class SSHSession {
                 })
             }
         }
+        if (!this.profile.options.auth || this.profile.options.auth === 'keyboardInteractive') {
+            const savedPassword = this.profile.options.password ?? await this.passwordStorage.loadPassword(this.profile)
+            if (savedPassword) {
+                this.remainingAuthMethods.push({ type: 'keyboard-interactive', savedPassword })
+            }
+            this.remainingAuthMethods.push({ type: 'keyboard-interactive' })
+        }
         if (!this.profile.options.auth || this.profile.options.auth === 'password') {
             if (this.profile.options.password) {
                 this.remainingAuthMethods.push({ type: 'saved-password', password: this.profile.options.password })
@@ -191,13 +210,6 @@ export class SSHSession {
             }
             this.remainingAuthMethods.push({ type: 'prompt-password' })
         }
-        if (!this.profile.options.auth || this.profile.options.auth === 'keyboardInteractive') {
-            const savedPassword = this.profile.options.password ?? await this.passwordStorage.loadPassword(this.profile)
-            if (savedPassword) {
-                this.remainingAuthMethods.push({ type: 'keyboard-interactive', savedPassword })
-            }
-            this.remainingAuthMethods.push({ type: 'keyboard-interactive' })
-        }
         this.remainingAuthMethods.push({ type: 'hostbased' })
     }
 
@@ -495,7 +507,7 @@ export class SSHSession {
         this.keyboardInteractivePrompt.next(prompt)
     }
 
-    async handleAuth (methodsLeft?: string[] | null): Promise<russh.AuthenticatedSSHClient|null> {
+    async handleAuth (): Promise<russh.AuthenticatedSSHClient|null> {
         this.activePrivateKey = null
 
         if (!(this.ssh instanceof russh.SSHClient)) {
@@ -506,22 +518,36 @@ export class SSHSession {
             throw new Error('No username')
         }
 
+        const noneResult = await this.ssh.authenticateNone(this.authUsername)
+        if (noneResult instanceof russh.AuthenticatedSSHClient) {
+            return noneResult
+        }
+
+        let methodsLeft = noneResult.remainingMethods
+
+        function maybeSetRemainingMethods (r: russh.AuthFailure) {
+            if (r.remainingMethods.length) {
+                methodsLeft = r.remainingMethods
+            }
+        }
+
         while (true) {
-            const method = this.remainingAuthMethods.shift()
+            const m = methodsLeft
+            const method = this.remainingAuthMethods.find(x => !m || m.includes(sshAuthTypeForMethod(x)))
+
             if (!method) {
                 return null
             }
-            if (methodsLeft && !methodsLeft.includes(method.type) && method.type !== 'agent') {
-                // Agent can still be used even if not in methodsLeft
-                this.logger.info('Server does not support auth method', method.type)
-                continue
-            }
+
+            this.remainingAuthMethods = this.remainingAuthMethods.filter(x => x !== method)
+
             if (method.type === 'saved-password') {
                 this.emitServiceMessage(this.translate.instant('Using saved password'))
                 const result = await this.ssh.authenticateWithPassword(this.authUsername, method.password)
                 if (result instanceof russh.AuthenticatedSSHClient) {
                     return result
                 }
+                maybeSetRemainingMethods(result)
             }
             if (method.type === 'prompt-password') {
                 const modal = this.ngbModal.open(PromptModalComponent)
@@ -539,6 +565,7 @@ export class SSHSession {
                         if (result instanceof russh.AuthenticatedSSHClient) {
                             return result
                         }
+                        maybeSetRemainingMethods(result)
                     } else {
                         continue
                     }
@@ -556,6 +583,7 @@ export class SSHSession {
                         if (result instanceof russh.AuthenticatedSSHClient) {
                             return result
                         }
+                        maybeSetRemainingMethods(result)
                     }
                 } catch (e) {
                     this.emitServiceMessage(colors.bgYellow.yellow.black(' ! ') + ` Failed to load private key ${method.name}: ${e}`)
@@ -567,6 +595,7 @@ export class SSHSession {
 
                 while (true) {
                     if (state.state === 'failure') {
+                        maybeSetRemainingMethods(state)
                         break
                     }
 
@@ -602,7 +631,7 @@ export class SSHSession {
                         }
                     }
 
-                    state = await this.ssh .continueKeyboardInteractiveAuthentication(responses)
+                    state = await this.ssh.continueKeyboardInteractiveAuthentication(responses)
 
                     if (state instanceof russh.AuthenticatedSSHClient) {
                         return state
@@ -615,6 +644,7 @@ export class SSHSession {
                     if (result instanceof russh.AuthenticatedSSHClient) {
                         return result
                     }
+                    maybeSetRemainingMethods(result)
                 } catch (e) {
                     this.emitServiceMessage(colors.bgYellow.yellow.black(' ! ') + ` Failed to authenticate using agent: ${e}`)
                     continue