Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 13 additions & 10 deletions OpenSSH_GUI.SshConfig/Extensions/SshConfigurationExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ public static class SshConfigurationExtensions
/// <paramref name="builder" />.
/// </param>
/// <returns>The <see cref="IConfigurationBuilder" />.</returns>
public IConfigurationBuilder AddSshConfig(string path)
public IConfigurationBuilder AddSshConfig(string path, Action<string, Exception>? loggingAction = null)
{
return builder.AddSshConfig(null, path, false, false);
return builder.AddSshConfig(null, path, false, false, loggingAction);
}

/// <summary>
Expand All @@ -34,9 +34,9 @@ public IConfigurationBuilder AddSshConfig(string path)
/// </param>
/// <param name="optional">Whether the file is optional.</param>
/// <returns>The <see cref="IConfigurationBuilder" />.</returns>
public IConfigurationBuilder AddSshConfig(string path, bool optional)
public IConfigurationBuilder AddSshConfig(string path, bool optional, Action<string, Exception>? loggingAction = null)
{
return builder.AddSshConfig(null, path, optional, false);
return builder.AddSshConfig(null, path, optional, false, loggingAction);
}

/// <summary>
Expand All @@ -50,9 +50,9 @@ public IConfigurationBuilder AddSshConfig(string path, bool optional)
/// <param name="reloadOnChange">Whether the configuration should be reloaded if the file changes.</param>
/// <returns>The <see cref="IConfigurationBuilder" />.</returns>
public IConfigurationBuilder AddSshConfig(string path, bool optional,
bool reloadOnChange)
bool reloadOnChange, Action<string, Exception>? loggingAction = null)
{
return builder.AddSshConfig(null, path, optional, reloadOnChange);
return builder.AddSshConfig(null, path, optional, reloadOnChange, loggingAction);
}

/// <summary>
Expand All @@ -67,7 +67,7 @@ public IConfigurationBuilder AddSshConfig(string path, bool optional,
/// <param name="reloadOnChange">Whether the configuration should be reloaded if the file changes.</param>
/// <returns>The <see cref="IConfigurationBuilder" />.</returns>
public IConfigurationBuilder AddSshConfig(IFileProvider? fileProvider,
string path, bool optional, bool reloadOnChange)
string path, bool optional, bool reloadOnChange, Action<string, Exception>? loggingAction = null)
{
ArgumentNullException.ThrowIfNull(builder);
ArgumentException.ThrowIfNullOrEmpty(path);
Expand All @@ -79,17 +79,20 @@ public IConfigurationBuilder AddSshConfig(IFileProvider? fileProvider,
s.Optional = optional;
s.ReloadOnChange = reloadOnChange;
s.ResolveFileProvider();
});
}, loggingAction);
}

/// <summary>
/// Adds an SSH configuration source to the <paramref name="builder" />.
/// </summary>
/// <param name="configureSource">Configures the source.</param>
/// <returns>The <see cref="IConfigurationBuilder" />.</returns>
public IConfigurationBuilder AddSshConfig(Action<SshConfigurationSource>? configureSource)
public IConfigurationBuilder AddSshConfig(Action<SshConfigurationSource>? configureSource, Action<string, Exception>? loggingAction)
{
var source = new SshConfigurationSource();
var source = new SshConfigurationSource
{
OnSkippedIncludeFile = loggingAction
};
configureSource?.Invoke(source);
return builder.Add(source);
}
Expand Down
1 change: 0 additions & 1 deletion OpenSSH_GUI.SshConfig/OpenSSH_GUI.SshConfig.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
<!-- Target framework and other specs in Directory.Build.props -->
<AllowUnsafeBlocks>false</AllowUnsafeBlocks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<Optimize>true</Optimize>
<PackageId>OpenSSH_GUI.SshConfig</PackageId>
</PropertyGroup>
Expand Down
8 changes: 8 additions & 0 deletions OpenSSH_GUI.SshConfig/Options/SshConfigParserOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,14 @@ public sealed record SshConfigParserOptions
/// Defaults to <see langword="false" />.
/// </summary>
public bool ThrowOnUnknownKey { get; init; }

/// <summary>
/// Optional callback invoked when an included file cannot be read due to
/// insufficient permissions or an I/O error. Receives the file path and the
/// causing exception. When <see langword="null"/>, inaccessible files are
/// silently skipped.
/// </summary>
public Action<string, Exception>? OnSkippedIncludeFile { get; init; }

/// <summary>Gets the default options instance.</summary>
public static SshConfigParserOptions Default { get; } = new();
Expand Down
17 changes: 16 additions & 1 deletion OpenSSH_GUI.SshConfig/Parsers/SshConfigParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -411,7 +411,22 @@ private static SshConfigDocument ResolveInclude(

foreach (var file in Directory.GetFiles(dir, filePattern).Order(StringComparer.Ordinal))
{
var fileContent = File.ReadAllText(file);
string fileContent;
try
{
fileContent = File.ReadAllText(file);
}
catch (UnauthorizedAccessException ex)
{
options.OnSkippedIncludeFile?.Invoke(file, ex);
continue;
}
catch (IOException ex)
{
options.OnSkippedIncludeFile?.Invoke(file, ex);
continue;
}

var included = ParseDocument(fileContent, file, options, depth + 1);
globalItems.AddRange(included.GlobalItems);
blocks.AddRange(included.Blocks);
Expand Down
2 changes: 1 addition & 1 deletion OpenSSH_GUI.SshConfig/Services/SshConfigurationProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public override void Load(Stream stream)
// We use the file path from the source if available for better error messages.
var filePath = Source.Path;
var document = SshConfigParser.Parse(content,
new SshConfigParserOptions { IncludeBasePath = filePath is null ? null : Path.GetDirectoryName(filePath) });
new SshConfigParserOptions { IncludeBasePath = filePath is null ? null : Path.GetDirectoryName(filePath), OnSkippedIncludeFile = Source is SshConfigurationSource source ? source.OnSkippedIncludeFile : null });

var data = new Dictionary<string, string?>(StringComparer.OrdinalIgnoreCase);

Expand Down
8 changes: 8 additions & 0 deletions OpenSSH_GUI.SshConfig/Services/SshConfigurationSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@ namespace OpenSSH_GUI.SshConfig.Services;
/// </summary>
public sealed class SshConfigurationSource : FileConfigurationSource
{
/// <summary>
/// Optional callback invoked when an included file cannot be read due to
/// insufficient permissions or an I/O error. Receives the file path and the
/// causing exception. When <see langword="null"/>, inaccessible files are
/// silently skipped.
/// </summary>
public Action<string, Exception>? OnSkippedIncludeFile { get; init; }

/// <summary>
/// Builds the <see cref="SshConfigurationProvider" /> for this source.
/// </summary>
Expand Down
9 changes: 7 additions & 2 deletions OpenSSH_GUI/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,15 @@ public static async Task Main(string[] args)
private static void ConfigureAppConfiguration(HostBuilderContext builderContext,
IConfigurationBuilder configurationBuilder)
{
configurationBuilder.AddSshConfig(ConfigFile.GetPathOfFile(), true, true);
configurationBuilder.AddSshConfig(SshdConfig.GetPathOfFile(), true, true);
configurationBuilder.AddSshConfig(ConfigFile.GetPathOfFile(), true, true, LoggingAction);
configurationBuilder.AddSshConfig(SshdConfig.GetPathOfFile(), true, true, LoggingAction);
configurationBuilder.AddInMemoryCollection([
new KeyValuePair<string, string?>(VersionEnvVar, GetHostVersion())
]);
}

private static void LoggingAction(string arg1, Exception arg2)
{
Log.Logger.Error(arg2, "Failed to load SSH config file: {Path}", arg1);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
</screenshot>
</screenshots>

<icon type="stock">opensshgui</icon>
<icon type="stock">openssh-gui</icon>
<releases>
<release version="0.0.0" date="1970-01-01"/>
</releases>
Expand Down
Loading