Browse Source

Bug 1896: Importing sessions from OpenSSH config file (ProxyJump directive + grammar)

Source commit: b6dd5e0a4670570f6ae50c4b79fada6d6df653bd
Martin Prikryl 4 năm trước cách đây
mục cha
commit
148ed7f71d

+ 23 - 0
source/core/SessionData.cpp

@@ -1714,6 +1714,29 @@ void TSessionData::ImportFromOpenssh(TStrings * Lines)
         {
           UserName = Value;
         }
+        else if (SameText(Directive, L"ProxyJump"))
+        {
+          UnicodeString Jump = Value;
+          // multiple jumps are not supported
+          if (Jump.Pos(L",") == 0)
+          {
+            std::unique_ptr<TSessionData> JumpData(new TSessionData(EmptyStr));
+            bool DefaultsOnly;
+            if ((JumpData->ParseUrl(Jump, NULL, NULL, DefaultsOnly, NULL, NULL, NULL, 0)) &&
+                !JumpData->HostName.IsEmpty())
+            {
+              JumpData->Name = JumpData->HostName;
+              JumpData->ImportFromOpenssh(Lines);
+
+              Tunnel = true;
+              TunnelHostName = JumpData->HostName;
+              TunnelPortNumber = JumpData->PortNumber;
+              TunnelUserName = JumpData->UserName;
+              TunnelPassword = JumpData->Password;
+              TunnelPublicKeyFile = JumpData->PublicKeyFile;
+            }
+          }
+        }
         UsedDirectives->Add(Directive);
       }
     }

+ 81 - 56
source/forms/ImportSessions.cpp

@@ -246,6 +246,68 @@ void __fastcall TImportSessionsDialog::HelpButtonClick(TObject * /*Sender*/)
   FormHelp(this);
 }
 //---------------------------------------------------------------------------
+bool TImportSessionsDialog::ConvertKeyFile(
+  UnicodeString & KeyFile, TStrings * ConvertedKeyFiles, TStrings * NotConvertedKeyFiles)
+{
+  bool ConvertedSession = false;
+  if (!KeyFile.IsEmpty() &&
+      FileExists(ApiPath(KeyFile)))
+  {
+    UnicodeString CanonicalPath = GetCanonicalPath(KeyFile);
+    // Reuses the already converted keys saved under a custom name
+    // (when saved under the default name they would be captured by the later condition based on GetConvertedKeyFileName)
+    int CanonicalIndex = ConvertedKeyFiles->IndexOfName(CanonicalPath);
+    if (CanonicalIndex >= 0)
+    {
+      KeyFile = ConvertedKeyFiles->ValueFromIndex[CanonicalIndex];
+      ConvertedSession = true;
+    }
+    // Prevents asking about converting the same key again, when the user refuses the conversion.
+    else if (NotConvertedKeyFiles->IndexOf(CanonicalPath) >= 0)
+    {
+      // noop
+    }
+    else
+    {
+      UnicodeString ConvertedFilename = GetConvertedKeyFileName(KeyFile);
+      UnicodeString FileName;
+      if (FileExists(ApiPath(ConvertedFilename)))
+      {
+        FileName = ConvertedFilename;
+        ConvertedSession = true;
+      }
+      else
+      {
+        FileName = KeyFile;
+        TDateTime TimestampBefore, TimestampAfter;
+        FileAge(FileName, TimestampBefore);
+        try
+        {
+          VerifyAndConvertKey(FileName, true);
+          FileAge(FileName, TimestampAfter);
+          if ((KeyFile != FileName) ||
+              // should never happen as cancelling the saving throws EAbort
+              DebugAlwaysTrue(TimestampBefore != TimestampAfter))
+          {
+            ConvertedSession = true;
+          }
+        }
+        catch (EAbort &)
+        {
+          NotConvertedKeyFiles->Add(CanonicalPath);
+        }
+      }
+
+      if (ConvertedSession)
+      {
+        KeyFile = FileName;
+        ConvertedKeyFiles->Values[CanonicalPath] = FileName;
+      }
+    }
+  }
+  return ConvertedSession;
+}
+//---------------------------------------------------------------------------
 bool __fastcall TImportSessionsDialog::Execute()
 {
   bool Result = (ShowModal() == DefaultResult(this));
@@ -266,66 +328,29 @@ bool __fastcall TImportSessionsDialog::Execute()
         if (Item->Checked)
         {
           TSessionData * Data = GetSessionData(Item);
-          if (!Data->PublicKeyFile.IsEmpty() &&
-              FileExists(ApiPath(Data->PublicKeyFile)))
+          UnicodeString SessionKeys;
+
+          UnicodeString PublicKeyFile = Data->PublicKeyFile;
+          if (ConvertKeyFile(PublicKeyFile, ConvertedKeyFiles.get(), NotConvertedKeyFiles.get()))
           {
-            UnicodeString CanonicalPath = GetCanonicalPath(Data->PublicKeyFile);
-            // Reuses the already converted keys saved under a custom name
-            // (when saved under the default name they would be captured by the later condition based on GetConvertedKeyFileName)
-            int CanonicalIndex = ConvertedKeyFiles->IndexOfName(CanonicalPath);
-            bool ConvertedSession = false;
-            if (CanonicalIndex >= 0)
-            {
-              Data->PublicKeyFile = ConvertedKeyFiles->ValueFromIndex[CanonicalIndex];
-              ConvertedSession = true;
-            }
-            // Prevents asking about converting the same key again, when the user refuses the conversion.
-            else if (NotConvertedKeyFiles->IndexOf(CanonicalPath) >= 0)
-            {
-              // noop
-            }
-            else
-            {
-              UnicodeString ConvertedFilename = GetConvertedKeyFileName(Data->PublicKeyFile);
-              UnicodeString FileName;
-              if (FileExists(ApiPath(ConvertedFilename)))
-              {
-                FileName = ConvertedFilename;
-                ConvertedSession = true;
-              }
-              else
-              {
-                FileName = Data->PublicKeyFile;
-                TDateTime TimestampBefore, TimestampAfter;
-                FileAge(FileName, TimestampBefore);
-                try
-                {
-                  VerifyAndConvertKey(FileName, true);
-                  FileAge(FileName, TimestampAfter);
-                  if ((Data->PublicKeyFile != FileName) ||
-                      // should never happen as cancelling the saving throws EAbort
-                      DebugAlwaysTrue(TimestampBefore != TimestampAfter))
-                  {
-                    ConvertedSession = true;
-                  }
-                }
-                catch (EAbort &)
-                {
-                  NotConvertedKeyFiles->Add(CanonicalPath);
-                }
-              }
-
-              if (ConvertedSession)
-              {
-                Data->PublicKeyFile = FileName;
-                ConvertedKeyFiles->Values[CanonicalPath] = FileName;
-              }
-            }
-            if (ConvertedSession)
+            Data->PublicKeyFile = PublicKeyFile;
+            SessionKeys = PublicKeyFile;
+          }
+
+          UnicodeString TunnelPublicKeyFile = Data->TunnelPublicKeyFile;
+          if (ConvertKeyFile(TunnelPublicKeyFile, ConvertedKeyFiles.get(), NotConvertedKeyFiles.get()))
+          {
+            Data->TunnelPublicKeyFile = TunnelPublicKeyFile;
+            if (SessionKeys != TunnelPublicKeyFile)
             {
-              ConvertedSessions->Add(FORMAT(L"%s (%s)", (Data->Name, Data->PublicKeyFile)));
+              AddToList(SessionKeys, TunnelPublicKeyFile, L", ");
             }
           }
+
+          if (!SessionKeys.IsEmpty())
+          {
+            ConvertedSessions->Add(FORMAT(L"%s (%s)", (Data->Name, SessionKeys)));
+          }
         }
       }
 

+ 1 - 0
source/forms/ImportSessions.h

@@ -47,6 +47,7 @@ private:
   void __fastcall SaveSelection();
   TStoredSessionList * __fastcall GetSessionList(int Index);
   TSessionData * GetSessionData(TListItem * Item);
+  bool ConvertKeyFile(UnicodeString & KeyFile, TStrings * ConvertedKeyFiles, TStrings * NotConvertedKeyFiles);
   virtual void __fastcall CreateHandle();
   virtual void __fastcall DestroyHandle();
   virtual void __fastcall Dispatch(void * Message);

+ 1 - 1
source/resource/TextsWin1.rc

@@ -656,7 +656,7 @@ BEGIN
         NEW_LOCAL_TAB_HINT, "Click to open new local tab.\nHold down Ctrl key to open new remote tab."
         NEW_REMOTE_TAB_HINT, "Click to open new session in new remote tab.\nHold down Shift Key to open new session in new window."
         NEW_REMOTE_TAB_CTRL_HINT, "%s\nHold down Ctrl key to open new local tab."
-        IMPORT_CONVERTED_KEYS, "%d key files in %d imported sessions were converted or replaced with existing keys in supported format."
+        IMPORT_CONVERTED_KEYS, "%d key file(s) in %d imported session(s) were converted or replaced with existing key(s) in supported format."
 
         WIN_VARIABLE_STRINGS, "WIN_VARIABLE"
         WINSCP_COPYRIGHT, "Copyright © 2000–2021 Martin Prikryl"