Skip to content

Commit

Permalink
BBS Integration tests (#696)
Browse files Browse the repository at this point in the history
<!--
For the checkboxes below you must check each one to indicate that you
either did the relevant task, or considered it and decided there was
nothing that needed doing
-->

Stood up a BBS server in our shared Azure Subscription
(e2e-bbs-8-5-0-linux-2204.eastus.cloudapp.azure.com). It's running the
latest version of BBS (8.5.0) and Ubuntu 22.04.

Manually created 2 projects and 2 repos in BBS (in the future we may
automate this like we have for ADO/GH), and added a new integration test
to migrate BBS->GH.

Included asserts to check if the GH repo exists and is initialized.

The default SSH cert that Azure generates didn't seem to work when using
Ubuntu 22.04 (didn't work with our SSH.Net nuget library, but did work
when directly using SSH in a terminal). I found a [workaround in an
issue](sshnet/SSH.NET#825 (comment))
from the SSH.Net repo that I applied in this PR. I don't fully
understand exactly what it's doing, but it looks like it's updating the
signature on the key in-memory before using it. Whatever it's doing, it
makes keys that previously didn't work now work. So it seems like a good
thing to me.

Closes #553 

Future work:
- automate the creation of BBS test data (like we do for ADO/GH)
- Include downloading the migration logs (and asserting that they exist)
- Add BBS windows server (once we support SMB)
- Add AWS
- Add another BBS server with the oldest version we support (5.14 I
think)

Checklist
- [x] Did you write/update appropriate tests
- [x] Release notes updated (if appropriate)
- [x] Appropriate logging output
- [x] Issue linked
- [x] Docs updated (or issue created)

<!--
For docs we should review the docs at:

https://docs.github.com/en/early-access/github/migrating-with-github-enterprise-importer
and the README.md in this repo

If a doc update is required based on the changes in this PR, it is
sufficient to create an issue and link to it here. The doc update can be
made later/separately.

The process to update the docs can be found here:
https://github.com/github/docs-early-access#opening-prs

The markdown files are here: 

https://github.com/github/docs-early-access/tree/main/content/github/migrating-with-github-enterprise-importer
-->
  • Loading branch information
dylan-smith authored Nov 1, 2022
1 parent f6c1950 commit b4a33bb
Show file tree
Hide file tree
Showing 7 changed files with 256 additions and 12 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,9 @@ jobs:
ADO_PAT: ${{ secrets.ADO_PAT }}
GHEC_PAT: ${{ secrets.GHEC_PAT }}
GHES_PAT: ${{ secrets.GHES_PAT }}
BBS_USERNAME: ${{ secrets.BBS_USERNAME }}
BBS_PASSWORD: ${{ secrets.BBS_PASSWORD }}
SSH_KEY: ${{ secrets.SSH_KEY }}
AZURE_STORAGE_CONNECTION_STRING_LINUX: ${{ secrets.AZURE_STORAGE_CONNECTION_STRING_LINUX }}
AZURE_STORAGE_CONNECTION_STRING_MACOS: ${{ secrets.AZURE_STORAGE_CONNECTION_STRING_MACOS }}
AZURE_STORAGE_CONNECTION_STRING_WINDOWS: ${{ secrets.AZURE_STORAGE_CONNECTION_STRING_WINDOWS }}
Expand Down
103 changes: 103 additions & 0 deletions src/OctoshiftCLI.IntegrationTests/BbsToGithub.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;
using Azure.Storage.Blobs;
using Xunit;
using Xunit.Abstractions;

namespace OctoshiftCLI.IntegrationTests;

[Collection("Integration Tests")]
public sealed class BbsToGithub : IDisposable
{
private const string BBS_URL = "http://e2e-bbs-8-5-0-linux-2204.eastus.cloudapp.azure.com:7990";
private const string SSH_KEY_FILE = "ssh_key.pem";

private readonly ITestOutputHelper _output;
private readonly TestHelper _targetHelper;
private readonly TestHelper _sourceHelper;
private readonly HttpClient _versionClient;
private readonly HttpClient _targetGithubHttpClient;
private readonly GithubClient _targetGithubClient;
private readonly GithubApi _targetGithubApi;
private readonly HttpClient _sourceBbsHttpClient;
private readonly BbsClient _sourceBbsClient;
private readonly BbsApi _sourceBbsApi;
private readonly BlobServiceClient _blobServiceClient;
private readonly Dictionary<string, string> _tokens;
private readonly DateTime _startTime;

public BbsToGithub(ITestOutputHelper output)
{
_startTime = DateTime.Now;
_output = output;

var logger = new OctoLogger(_ => { }, x => _output.WriteLine(x), _ => { }, _ => { });

var sourceBbsUsername = Environment.GetEnvironmentVariable("BBS_USERNAME");
var sourceBbsPassword = Environment.GetEnvironmentVariable("BBS_PASSWORD");
var targetGithubToken = Environment.GetEnvironmentVariable("GHEC_PAT");
var azureStorageConnectionString = Environment.GetEnvironmentVariable($"AZURE_STORAGE_CONNECTION_STRING_{TestHelper.GetOsName().ToUpper()}");
var sshKey = Environment.GetEnvironmentVariable("SSH_KEY");
_tokens = new Dictionary<string, string>
{
["BBS_USERNAME"] = sourceBbsUsername,
["BBS_PASSWORD"] = sourceBbsPassword,
["GH_PAT"] = targetGithubToken,
["AZURE_STORAGE_CONNECTION_STRING"] = azureStorageConnectionString
};

File.WriteAllText(Path.Join(TestHelper.GetOsDistPath(), SSH_KEY_FILE), sshKey);

_versionClient = new HttpClient();

_sourceBbsHttpClient = new HttpClient();
_sourceBbsClient = new BbsClient(logger, _sourceBbsHttpClient, new VersionChecker(_versionClient, logger), new RetryPolicy(logger), sourceBbsUsername, sourceBbsPassword);
_sourceBbsApi = new BbsApi(_sourceBbsClient, BBS_URL, logger);

_targetGithubHttpClient = new HttpClient();
_targetGithubClient = new GithubClient(logger, _targetGithubHttpClient, new VersionChecker(_versionClient, logger), new RetryPolicy(logger), new DateTimeProvider(), targetGithubToken);
_targetGithubApi = new GithubApi(_targetGithubClient, "https://api.github.com", new RetryPolicy(logger));

_blobServiceClient = new BlobServiceClient(azureStorageConnectionString);

_sourceHelper = new TestHelper(_output, _sourceBbsApi, _sourceBbsClient, BBS_URL);
_targetHelper = new TestHelper(_output, _targetGithubApi, _targetGithubClient, _blobServiceClient);
}

[Fact]
public async Task Basic()
{
var githubTargetOrg = $"e2e-testing-{TestHelper.GetOsName()}";
const string repo1 = "EEL-repo-1";
const string repo2 = "EEL-repo-2";

await _targetHelper.ResetBlobContainers();

// TODO: Reset BBS test environment
await _targetHelper.ResetGithubTestEnvironment(githubTargetOrg);

// TODO: Generate BBS test data

await _targetHelper.RunBbsCliMigration(
$"generate-script --github-org {githubTargetOrg} --bbs-server-url {BBS_URL} --ssh-user octoshift --ssh-private-key {SSH_KEY_FILE}", _tokens);

_targetHelper.AssertNoErrorInLogs(_startTime);

await _targetHelper.AssertGithubRepoExists(githubTargetOrg, repo1);
await _targetHelper.AssertGithubRepoExists(githubTargetOrg, repo2);
await _targetHelper.AssertGithubRepoInitialized(githubTargetOrg, repo1);
await _targetHelper.AssertGithubRepoInitialized(githubTargetOrg, repo2);

// TODO: Assert migration logs are downloaded
}

public void Dispose()
{
_sourceBbsHttpClient?.Dispose();
_targetGithubHttpClient?.Dispose();
_versionClient?.Dispose();
}
}
15 changes: 15 additions & 0 deletions src/OctoshiftCLI.IntegrationTests/TestHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ public class TestHelper
private readonly AdoClient _adoClient;
private readonly GithubClient _githubClient;
private readonly BlobServiceClient _blobServiceClient;
private readonly BbsApi _bbsApi;
private readonly BbsClient _bbsClient;
private readonly string _bbsUrl;

public TestHelper(ITestOutputHelper output, AdoApi adoApi, GithubApi githubApi, AdoClient adoClient, GithubClient githubClient)
{
Expand All @@ -53,6 +56,14 @@ public TestHelper(ITestOutputHelper output, GithubApi githubTargetApi, GithubCli
_blobServiceClient = blobServiceClient;
}

public TestHelper(ITestOutputHelper output, BbsApi bbsApi, BbsClient bbsClient, string bbsUrl)
{
_output = output;
_bbsApi = bbsApi;
_bbsClient = bbsClient;
_bbsUrl = bbsUrl;
}

public string GithubApiBaseUrl { get; init; } = "https://api.github.com";

public async Task ResetAdoTestEnvironment(string adoOrg)
Expand Down Expand Up @@ -499,6 +510,7 @@ public async Task RunCliCommand(string command, string cliName, IDictionary<stri
}

_output.WriteLine($"Running command: {startInfo.FileName} {startInfo.Arguments}");

var p = Process.Start(startInfo);
await p.WaitForExitAsync();

Expand All @@ -511,6 +523,9 @@ public async Task RunAdoToGithubCliMigration(string generateScriptCommand, IDict
public async Task RunGeiCliMigration(string generateScriptCommand, IDictionary<string, string> tokens) =>
await RunCliMigration($"gei {generateScriptCommand}", "gh", tokens);

public async Task RunBbsCliMigration(string generateScriptCommand, IDictionary<string, string> tokens) =>
await RunCliMigration($"bbs2gh {generateScriptCommand}", "gh", tokens);

public static string GetOsDistPath()
{
return RuntimeInformation.IsOSPlatform(OSPlatform.Linux)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public class GenerateScriptCommandHandlerTests
private const string BBS_PASSWORD = "BBS-PASSWORD";
private const string SSH_USER = "SSH-USER";
private const string SSH_PRIVATE_KEY = "path-to-ssh-private-key";
private const string SSH_PORT = "1234";
private const int SSH_PORT = 2211;
private const string OUTPUT = "unit-test-output";
private const string BBS_FOO_PROJECT_KEY = "FP";
private const string BBS_FOO_PROJECT_NAME = "BBS-FOO-PROJECT-NAME";
Expand Down Expand Up @@ -122,10 +122,10 @@ public async Task Two_Projects_Two_Repos_Each_All_Options()
(Id: 4, Slug: BBS_BAR_REPO_2_SLUG, Name: BBS_BAR_REPO_2_NAME)
});

const string migrateRepoCommand1 = $"Exec {{ gh bbs2gh migrate-repo --bbs-server-url \"{BBS_SERVER_URL}\" --bbs-username \"{BBS_USERNAME}\" --bbs-shared-home \"{BBS_SHARED_HOME}\" --bbs-project \"{BBS_FOO_PROJECT_KEY}\" --bbs-repo \"{BBS_FOO_REPO_1_SLUG}\" --ssh-user \"{SSH_USER}\" --ssh-private-key \"{SSH_PRIVATE_KEY}\" --ssh-port {SSH_PORT} --github-org \"{GITHUB_ORG}\" --github-repo \"{BBS_FOO_PROJECT_KEY}-{BBS_FOO_REPO_1_SLUG}\" --verbose --wait }}";
const string migrateRepoCommand2 = $"Exec {{ gh bbs2gh migrate-repo --bbs-server-url \"{BBS_SERVER_URL}\" --bbs-username \"{BBS_USERNAME}\" --bbs-shared-home \"{BBS_SHARED_HOME}\" --bbs-project \"{BBS_FOO_PROJECT_KEY}\" --bbs-repo \"{BBS_FOO_REPO_2_SLUG}\" --ssh-user \"{SSH_USER}\" --ssh-private-key \"{SSH_PRIVATE_KEY}\" --ssh-port {SSH_PORT} --github-org \"{GITHUB_ORG}\" --github-repo \"{BBS_FOO_PROJECT_KEY}-{BBS_FOO_REPO_2_SLUG}\" --verbose --wait }}";
const string migrateRepoCommand3 = $"Exec {{ gh bbs2gh migrate-repo --bbs-server-url \"{BBS_SERVER_URL}\" --bbs-username \"{BBS_USERNAME}\" --bbs-shared-home \"{BBS_SHARED_HOME}\" --bbs-project \"{BBS_BAR_PROJECT_KEY}\" --bbs-repo \"{BBS_BAR_REPO_1_SLUG}\" --ssh-user \"{SSH_USER}\" --ssh-private-key \"{SSH_PRIVATE_KEY}\" --ssh-port {SSH_PORT} --github-org \"{GITHUB_ORG}\" --github-repo \"{BBS_BAR_PROJECT_KEY}-{BBS_BAR_REPO_1_SLUG}\" --verbose --wait }}";
const string migrateRepoCommand4 = $"Exec {{ gh bbs2gh migrate-repo --bbs-server-url \"{BBS_SERVER_URL}\" --bbs-username \"{BBS_USERNAME}\" --bbs-shared-home \"{BBS_SHARED_HOME}\" --bbs-project \"{BBS_BAR_PROJECT_KEY}\" --bbs-repo \"{BBS_BAR_REPO_2_SLUG}\" --ssh-user \"{SSH_USER}\" --ssh-private-key \"{SSH_PRIVATE_KEY}\" --ssh-port {SSH_PORT} --github-org \"{GITHUB_ORG}\" --github-repo \"{BBS_BAR_PROJECT_KEY}-{BBS_BAR_REPO_2_SLUG}\" --verbose --wait }}";
var migrateRepoCommand1 = $"Exec {{ gh bbs2gh migrate-repo --bbs-server-url \"{BBS_SERVER_URL}\" --bbs-username \"{BBS_USERNAME}\" --bbs-shared-home \"{BBS_SHARED_HOME}\" --bbs-project \"{BBS_FOO_PROJECT_KEY}\" --bbs-repo \"{BBS_FOO_REPO_1_SLUG}\" --ssh-user \"{SSH_USER}\" --ssh-private-key \"{SSH_PRIVATE_KEY}\" --ssh-port {SSH_PORT} --github-org \"{GITHUB_ORG}\" --github-repo \"{BBS_FOO_PROJECT_KEY}-{BBS_FOO_REPO_1_SLUG}\" --verbose --wait }}";
var migrateRepoCommand2 = $"Exec {{ gh bbs2gh migrate-repo --bbs-server-url \"{BBS_SERVER_URL}\" --bbs-username \"{BBS_USERNAME}\" --bbs-shared-home \"{BBS_SHARED_HOME}\" --bbs-project \"{BBS_FOO_PROJECT_KEY}\" --bbs-repo \"{BBS_FOO_REPO_2_SLUG}\" --ssh-user \"{SSH_USER}\" --ssh-private-key \"{SSH_PRIVATE_KEY}\" --ssh-port {SSH_PORT} --github-org \"{GITHUB_ORG}\" --github-repo \"{BBS_FOO_PROJECT_KEY}-{BBS_FOO_REPO_2_SLUG}\" --verbose --wait }}";
var migrateRepoCommand3 = $"Exec {{ gh bbs2gh migrate-repo --bbs-server-url \"{BBS_SERVER_URL}\" --bbs-username \"{BBS_USERNAME}\" --bbs-shared-home \"{BBS_SHARED_HOME}\" --bbs-project \"{BBS_BAR_PROJECT_KEY}\" --bbs-repo \"{BBS_BAR_REPO_1_SLUG}\" --ssh-user \"{SSH_USER}\" --ssh-private-key \"{SSH_PRIVATE_KEY}\" --ssh-port {SSH_PORT} --github-org \"{GITHUB_ORG}\" --github-repo \"{BBS_BAR_PROJECT_KEY}-{BBS_BAR_REPO_1_SLUG}\" --verbose --wait }}";
var migrateRepoCommand4 = $"Exec {{ gh bbs2gh migrate-repo --bbs-server-url \"{BBS_SERVER_URL}\" --bbs-username \"{BBS_USERNAME}\" --bbs-shared-home \"{BBS_SHARED_HOME}\" --bbs-project \"{BBS_BAR_PROJECT_KEY}\" --bbs-repo \"{BBS_BAR_REPO_2_SLUG}\" --ssh-user \"{SSH_USER}\" --ssh-private-key \"{SSH_PRIVATE_KEY}\" --ssh-port {SSH_PORT} --github-org \"{GITHUB_ORG}\" --github-repo \"{BBS_BAR_PROJECT_KEY}-{BBS_BAR_REPO_2_SLUG}\" --verbose --wait }}";

// Act
var args = new GenerateScriptCommandArgs
Expand Down Expand Up @@ -166,7 +166,7 @@ public async Task One_Repo_With_Kerberos()
(Id: 1, Slug: BBS_FOO_REPO_1_SLUG, Name: BBS_FOO_REPO_1_NAME),
});

const string migrateRepoCommand = $"Exec {{ gh bbs2gh migrate-repo --bbs-server-url \"{BBS_SERVER_URL}\" --bbs-username \"{BBS_USERNAME}\" --bbs-shared-home \"{BBS_SHARED_HOME}\" --bbs-project \"{BBS_FOO_PROJECT_KEY}\" --bbs-repo \"{BBS_FOO_REPO_1_SLUG}\" --ssh-user \"{SSH_USER}\" --ssh-private-key \"{SSH_PRIVATE_KEY}\" --ssh-port {SSH_PORT} --github-org \"{GITHUB_ORG}\" --github-repo \"{BBS_FOO_PROJECT_KEY}-{BBS_FOO_REPO_1_SLUG}\" --verbose --wait --kerberos }}";
var migrateRepoCommand = $"Exec {{ gh bbs2gh migrate-repo --bbs-server-url \"{BBS_SERVER_URL}\" --bbs-username \"{BBS_USERNAME}\" --bbs-shared-home \"{BBS_SHARED_HOME}\" --bbs-project \"{BBS_FOO_PROJECT_KEY}\" --bbs-repo \"{BBS_FOO_REPO_1_SLUG}\" --ssh-user \"{SSH_USER}\" --ssh-private-key \"{SSH_PRIVATE_KEY}\" --ssh-port {SSH_PORT} --github-org \"{GITHUB_ORG}\" --github-repo \"{BBS_FOO_PROJECT_KEY}-{BBS_FOO_REPO_1_SLUG}\" --verbose --wait --kerberos }}";

// Act
var args = new GenerateScriptCommandArgs
Expand Down Expand Up @@ -274,7 +274,7 @@ public async Task One_Repo_With_Aws_Bucket_Name()
(Id: 1, Slug: BBS_FOO_REPO_1_SLUG, Name: BBS_FOO_REPO_1_NAME),
});

const string migrateRepoCommand = $"Exec {{ gh bbs2gh migrate-repo --bbs-server-url \"{BBS_SERVER_URL}\" --bbs-username \"{BBS_USERNAME}\" --bbs-shared-home \"{BBS_SHARED_HOME}\" --bbs-project \"{BBS_FOO_PROJECT_KEY}\" --bbs-repo \"{BBS_FOO_REPO_1_SLUG}\" --ssh-user \"{SSH_USER}\" --ssh-private-key \"{SSH_PRIVATE_KEY}\" --ssh-port {SSH_PORT} --github-org \"{GITHUB_ORG}\" --github-repo \"{BBS_FOO_PROJECT_KEY}-{BBS_FOO_REPO_1_SLUG}\" --verbose --wait --aws-bucket-name \"{AWS_BUCKET_NAME}\" }}";
var migrateRepoCommand = $"Exec {{ gh bbs2gh migrate-repo --bbs-server-url \"{BBS_SERVER_URL}\" --bbs-username \"{BBS_USERNAME}\" --bbs-shared-home \"{BBS_SHARED_HOME}\" --bbs-project \"{BBS_FOO_PROJECT_KEY}\" --bbs-repo \"{BBS_FOO_REPO_1_SLUG}\" --ssh-user \"{SSH_USER}\" --ssh-private-key \"{SSH_PRIVATE_KEY}\" --ssh-port {SSH_PORT} --github-org \"{GITHUB_ORG}\" --github-repo \"{BBS_FOO_PROJECT_KEY}-{BBS_FOO_REPO_1_SLUG}\" --verbose --wait --aws-bucket-name \"{AWS_BUCKET_NAME}\" }}";

// Act
var args = new GenerateScriptCommandArgs
Expand Down
2 changes: 1 addition & 1 deletion src/bbs2gh/Commands/GenerateScriptCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ public class GenerateScriptCommandArgs
public string BbsSharedHome { get; set; }
public string SshUser { get; set; }
public string SshPrivateKey { get; set; }
public string SshPort { get; set; }
public int SshPort { get; set; }
public FileInfo Output { get; set; }
public bool Kerberos { get; set; }
public bool Verbose { get; set; }
Expand Down
76 changes: 76 additions & 0 deletions src/bbs2gh/RsaWithSha256SignatureKey.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
using System;
using System.Security.Cryptography;
using Renci.SshNet.Common;
using Renci.SshNet.Security;
using Renci.SshNet.Security.Cryptography;
using Renci.SshNet.Security.Cryptography.Ciphers;

namespace OctoshiftCLI.BbsToGithub;

// workaround for RSA keys on Ubuntu 22.04
// https://github.com/sshnet/SSH.NET/issues/825#issuecomment-1139440419

public class RsaWithSha256SignatureKey : RsaKey
{
public RsaWithSha256SignatureKey(BigInteger modulus, BigInteger exponent, BigInteger d, BigInteger p, BigInteger q,
BigInteger inverseQ) : base(modulus, exponent, d, p, q, inverseQ)
{
}

private RsaSha256DigitalSignature _digitalSignature;

protected override DigitalSignature DigitalSignature
{
get
{
_digitalSignature ??= new RsaSha256DigitalSignature(this);

return _digitalSignature;
}
}

public override string ToString() => "rsa-sha2-256";
}

public class RsaSha256DigitalSignature : CipherDigitalSignature, IDisposable
{
private HashAlgorithm _hash;

public RsaSha256DigitalSignature(RsaWithSha256SignatureKey rsaKey)
// custom OID
: base(new ObjectIdentifier(2, 16, 840, 1, 101, 3, 4, 2, 1), new RsaCipher(rsaKey))
{
// custom
_hash = SHA256.Create();
}

protected override byte[] Hash(byte[] input) => _hash.ComputeHash(input);

private bool _isDisposed;

public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}

protected virtual void Dispose(bool disposing)
{
if (_isDisposed)
{
return;
}

if (disposing)
{
var hash = _hash;
if (hash != null)
{
hash.Dispose();
_hash = null;
}

_isDisposed = true;
}
}
}
55 changes: 51 additions & 4 deletions src/bbs2gh/Services/BbsSshArchiveDownloader.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
using System;
using System.IO;
using System.Reflection;
using System.Threading.Tasks;
using Renci.SshNet;
using Renci.SshNet.Security;

namespace OctoshiftCLI.BbsToGithub.Services;

Expand All @@ -10,17 +12,56 @@ public sealed class BbsSshArchiveDownloader : IBbsArchiveDownloader, IDisposable
private const int DOWNLOAD_PROGRESS_REPORT_INTERVAL_IN_SECONDS = 10;

private readonly ISftpClient _sftpClient;
private readonly RsaKey _rsaKey;
private readonly PrivateKeyFile _privateKey;
private readonly PrivateKeyAuthenticationMethod _authenticationMethodRsa;
private readonly OctoLogger _log;
private readonly FileSystemProvider _fileSystemProvider;
private readonly object _mutex = new();
private DateTime _nextProgressReport;

#pragma warning disable CA2000 // Incorrectly flagged as a not-disposing error
public BbsSshArchiveDownloader(OctoLogger log, FileSystemProvider fileSystemProvider, string host, string sshUser, string privateKeyFileFullPath, int sshPort = 22)
: this(log, fileSystemProvider, new SftpClient(host, sshPort, sshUser, new PrivateKeyFile(privateKeyFileFullPath)))
{
_log = log;
_fileSystemProvider = fileSystemProvider;

_privateKey = new PrivateKeyFile(privateKeyFileFullPath);

if (IsRsaKey(_privateKey))
{
_rsaKey = UpdatePrivateKeyFileToRsaSha256(_privateKey);
_authenticationMethodRsa = new PrivateKeyAuthenticationMethod(sshUser, _privateKey);
var connection = new ConnectionInfo(host, sshPort, sshUser, _authenticationMethodRsa);
connection.HostKeyAlgorithms["rsa-sha2-256"] = data => new KeyHostAlgorithm("rsa-sha2-256", _rsaKey, data);
_sftpClient = new SftpClient(connection);
}
else
{
_sftpClient = new SftpClient(host, sshPort, sshUser, _privateKey);
}
}

private bool IsRsaKey(PrivateKeyFile privateKeyFile) => privateKeyFile.HostKey is KeyHostAlgorithm keyHostAlgorithm && keyHostAlgorithm.Key is RsaKey;

private RsaWithSha256SignatureKey UpdatePrivateKeyFileToRsaSha256(PrivateKeyFile privateKeyFile)
{
if ((privateKeyFile.HostKey as KeyHostAlgorithm).Key is not RsaKey oldRsaKey)
{
throw new ArgumentException("The private key file is not an RSA key.", nameof(privateKeyFile));
}

var rsaKey = new RsaWithSha256SignatureKey(oldRsaKey.Modulus, oldRsaKey.Exponent, oldRsaKey.D, oldRsaKey.P, oldRsaKey.Q, oldRsaKey.InverseQ);

var keyHostAlgorithm = new KeyHostAlgorithm(rsaKey.ToString(), rsaKey);

var hostKeyProperty = typeof(PrivateKeyFile).GetProperty(nameof(PrivateKeyFile.HostKey));
hostKeyProperty.SetValue(privateKeyFile, keyHostAlgorithm);

var keyField = typeof(PrivateKeyFile).GetField("_key", BindingFlags.NonPublic | BindingFlags.Instance);
keyField.SetValue(privateKeyFile, rsaKey);

return rsaKey;
}
#pragma warning restore CA2000

internal BbsSshArchiveDownloader(OctoLogger log, FileSystemProvider fileSystemProvider, ISftpClient sftpClient)
{
Expand Down Expand Up @@ -112,5 +153,11 @@ private string GetLogFriendlySize(ulong size)
};
}

public void Dispose() => (_sftpClient as IDisposable)?.Dispose();
public void Dispose()
{
(_sftpClient as IDisposable)?.Dispose();
(_rsaKey as IDisposable)?.Dispose();
(_authenticationMethodRsa as IDisposable)?.Dispose();
(_privateKey as IDisposable)?.Dispose();
}
}

0 comments on commit b4a33bb

Please sign in to comment.