Skip to content

Commit

Permalink
Dynamically generate profile with .ssh/config
Browse files Browse the repository at this point in the history
This PR looks for the presense of OpenSSH config files and creates
profiles from the hosts present.

CLoses microsoft#9031
  • Loading branch information
jonthysell committed Sep 20, 2022
1 parent c51bb3a commit cfc66e9
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "PowershellCoreProfileGenerator.h"
#include "VisualStudioGenerator.h"
#include "WslDistroGenerator.h"
#include "SshHostGenerator.h"

// The following files are generated at build time into the "Generated Files" directory.
// defaults(-universal).h is a file containing the default json settings in a std::string_view.
Expand Down Expand Up @@ -148,6 +149,7 @@ void SettingsLoader::GenerateProfiles()
_executeGenerator(WslDistroGenerator{});
_executeGenerator(AzureCloudShellGenerator{});
_executeGenerator(VisualStudioGenerator{});
_executeGenerator(SshHostGenerator{});
}

// A new settings.json gets a special treatment:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@
<ClInclude Include="VsDevShellGenerator.h" />
<ClInclude Include="VsSetupConfiguration.h" />
<ClInclude Include="WslDistroGenerator.h" />
<ClInclude Include="SshHostGenerator.h" />
</ItemGroup>
<!-- ========================= Cpp Files ======================== -->
<ItemGroup>
Expand Down Expand Up @@ -165,6 +166,7 @@
<ClCompile Include="VsDevShellGenerator.cpp" />
<ClCompile Include="VsSetupConfiguration.cpp" />
<ClCompile Include="WslDistroGenerator.cpp" />
<ClCompile Include="SshHostGenerator.cpp" />
<!-- You _NEED_ to include this file and the jsoncpp IncludePath (below) if
you want to use jsoncpp -->
<ClCompile Include="$(OpenConsoleDir)\dep\jsoncpp\jsoncpp.cpp">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
<ClCompile Include="WslDistroGenerator.cpp">
<Filter>profileGeneration</Filter>
</ClCompile>
<ClCompile Include="SshHostGenerator.cpp">
<Filter>profileGeneration</Filter>
</ClCompile>
<ClCompile Include="CascadiaSettings.cpp" />
<ClCompile Include="CascadiaSettingsSerialization.cpp" />
<ClCompile Include="GlobalAppSettings.cpp" />
Expand Down Expand Up @@ -61,6 +64,9 @@
<ClInclude Include="WslDistroGenerator.h">
<Filter>profileGeneration</Filter>
</ClInclude>
<ClInclude Include="SshHostGenerator.h">
<Filter>profileGeneration</Filter>
</ClInclude>
<ClInclude Include="CascadiaSettings.h" />
<ClInclude Include="GlobalAppSettings.h" />
<ClInclude Include="TerminalSettingsSerializationHelpers.h" />
Expand Down
80 changes: 80 additions & 0 deletions src/cascadia/TerminalSettingsModel/SshHostGenerator.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

#include "pch.h"

#include "SshHostGenerator.h"
#include "../../inc/DefaultSettings.h"

#include "DynamicProfileUtils.h"

static constexpr std::wstring_view SshHostGeneratorNamespace{ L"Windows.Terminal.SSH" };

static constexpr std::wstring_view SSH_TITLE_FMT{ L"SSH - {}" };

static constexpr std::wstring_view SSH_COMMANDLINE_FMT{ L"ssh.exe {}" };
static constexpr const wchar_t* SSH_SYSTEMCONFIG_PATH = L"%ProgramData%\\ssh\\ssh_config";
static constexpr const wchar_t* SSH_USERCONFIG_PATH = L"%UserProfile%\\.ssh\\config";

static constexpr std::wstring_view SSH_HOST_PREFIX{ L"Host " };

using namespace ::Microsoft::Terminal::Settings::Model;
using namespace winrt::Microsoft::Terminal::Settings::Model;

std::wstring_view SshHostGenerator::GetNamespace() const noexcept
{
return SshHostGeneratorNamespace;
}

static winrt::com_ptr<implementation::Profile> _makeProfile(const std::wstring& hostName)
{
const auto title = std::format(SSH_TITLE_FMT, hostName);

const auto profile{ CreateDynamicProfile(title) };

std::wstring quotedCommandline = std::format(SSH_COMMANDLINE_FMT, hostName);
profile->Commandline(winrt::hstring{ quotedCommandline });

return profile;
}

static void _tryGetHostNamesFromConfigFile(const std::wstring configPath, std::vector<std::wstring>& hostNames)
{
std::filesystem::path resolvedConfigPath{ wil::ExpandEnvironmentStringsW<std::wstring>(configPath.c_str()) };
if (std::filesystem::exists(resolvedConfigPath) && std::filesystem::is_regular_file(resolvedConfigPath))
{
std::wifstream inputStream(resolvedConfigPath);

std::wstring line;
while (std::getline(inputStream, line))
{
if (line.starts_with(SSH_HOST_PREFIX))
{
hostNames.emplace_back(line.substr(SSH_HOST_PREFIX.length()));
}
}
}
}

// Method Description:
// - Generate a list of profiles for each detected OpenSSH host.
// Arguments:
// - <none>
// Return Value:
// - <A list of SSH host profiles.>
void SshHostGenerator::GenerateProfiles(std::vector<winrt::com_ptr<implementation::Profile>>& profiles) const
{
try
{
std::vector<std::wstring> hostNames;

_tryGetHostNamesFromConfigFile(SSH_SYSTEMCONFIG_PATH, hostNames);
_tryGetHostNamesFromConfigFile(SSH_USERCONFIG_PATH, hostNames);

for (const auto& hostName : hostNames)
{
profiles.emplace_back(_makeProfile(hostName));
}
}
CATCH_LOG();
}
29 changes: 29 additions & 0 deletions src/cascadia/TerminalSettingsModel/SshHostGenerator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*++
Copyright (c) Microsoft Corporation
Licensed under the MIT license.
Module Name:
- SshHostGenerator
Abstract:
- This is the dynamic profile generator for SSH connections. Enumerates all the
SSH hosts to create profiles for them.
Author(s):
- Jon Thysell - September 2022
--*/

#pragma once

#include "IDynamicProfileGenerator.h"

namespace winrt::Microsoft::Terminal::Settings::Model
{
class SshHostGenerator final : public IDynamicProfileGenerator
{
public:
std::wstring_view GetNamespace() const noexcept override;
void GenerateProfiles(std::vector<winrt::com_ptr<implementation::Profile>>& profiles) const override;
};
};

0 comments on commit cfc66e9

Please sign in to comment.