Files
server/test/Setup.Test/ProgramTests.cs
2026-04-10 13:21:27 -04:00

125 lines
5.3 KiB
C#

using System.Net;
using System.Net.Http.Json;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using Bit.Setup;
using NSubstitute;
using RichardSzalay.MockHttp;
namespace Setup.Test;
public class ProgramTests
{
[Fact(Explicit = true)]
public async Task Install_Works()
{
var tempDir = Directory.CreateTempSubdirectory();
try
{
var installationId = $"{Guid.NewGuid()}";
var testApp = Substitute.For<Application>();
testApp.RootDirectory.Returns(tempDir.FullName);
testApp
.ReadInput(Arg.Any<string>())
.Returns(c =>
{
var prompt = c.Arg<string>();
return prompt switch
{
"Enter your installation id (get at https://bitwarden.com/host)" => installationId,
"Enter your installation key" => "test-key",
"Enter your region (US/EU) [US]" => "",
_ => throw new NotImplementedException($"Prompt not configured: {prompt}"),
};
});
testApp
.ReadQuestion(Arg.Any<string>())
.Returns(c =>
{
var prompt = c.Arg<string>();
return prompt switch
{
"Do you have a SSL certificate to use?" => false,
"Do you want to generate a self-signed SSL certificate?" => true,
_ => throw new NotImplementedException(prompt),
};
});
var mockHandler = new MockHttpMessageHandler();
mockHandler
.Expect(HttpMethod.Get, $"https://api.bitwarden.com/installations/{installationId}")
.Respond(HttpStatusCode.OK, JsonContent.Create(new { enabled = true, }));
testApp
.GetHttpClient()
.Returns(mockHandler.ToHttpClient());
Program.MainCore([
"-install", "1",
"-domain", "example.com",
"-letsencrypt", "n",
"-os", "lin",
"-corev", "test-version-does-not-exist",
"-webv", "test-version-does-not-exist",
"-dbname", "test-db",
"-keyconnectorv", "test-version-does-not-exist",
], testApp);
// Assert SSL certificate details
var baseDir = Path.Join(tempDir.FullName, "ssl", "self", "example.com");
var certFile = new FileInfo(Path.Join(baseDir, "certificate.crt"));
Assert.True(certFile.Exists);
var cert = new X509Certificate2(certFile.FullName);
var hundredYearsFromNow = DateTime.UtcNow.AddDays(36500);
Assert.InRange(cert.NotAfter, hundredYearsFromNow.AddMinutes(-1), hundredYearsFromNow.AddMinutes(1));
Assert.Equal("sha256RSA", cert.SignatureAlgorithm.FriendlyName);
var names = cert.SubjectName.EnumerateRelativeDistinguishedNames().ToList();
Assert.Equal(6, names.Count);
Assert.Contains(names, n => n.GetSingleElementType().FriendlyName == "C" && n.GetSingleElementValue() == "US");
Assert.Contains(names, n => n.GetSingleElementType().FriendlyName == "S" && n.GetSingleElementValue() == "California");
Assert.Contains(names, n => n.GetSingleElementType().FriendlyName == "L" && n.GetSingleElementValue() == "Santa Barbara");
Assert.Contains(names, n => n.GetSingleElementType().FriendlyName == "O" && n.GetSingleElementValue() == "Bitwarden Inc.");
Assert.Contains(names, n => n.GetSingleElementType().FriendlyName == "OU" && n.GetSingleElementValue() == "Bitwarden");
Assert.Contains(names, n => n.GetSingleElementType().FriendlyName == "CN" && n.GetSingleElementValue() == "example.com");
Assert.Equal(3, cert.Extensions.Count);
var san = Assert.Single(cert.Extensions.OfType<X509SubjectAlternativeNameExtension>());
var dns = Assert.Single(san.EnumerateDnsNames());
Assert.Equal("example.com", dns);
Assert.Empty(san.EnumerateIPAddresses());
Assert.False(san.Critical);
var basicConstraints = Assert.Single(cert.Extensions.OfType<X509BasicConstraintsExtension>());
Assert.True(basicConstraints.CertificateAuthority);
Assert.False(basicConstraints.HasPathLengthConstraint);
Assert.Equal(0, basicConstraints.PathLengthConstraint);
Assert.False(basicConstraints.Critical);
var subjectKeyIdentifier = Assert.Single(cert.Extensions.OfType<X509SubjectKeyIdentifierExtension>());
Assert.False(subjectKeyIdentifier.Critical);
// Validate that the private key can be imported in PEM format
using var rsa = RSA.Create();
rsa.ImportFromPem(
await File.ReadAllTextAsync(Path.Combine(baseDir, "private.key"), TestContext.Current.CancellationToken)
);
Assert.Equal(4096, rsa.KeySize);
Assert.Equal("RSA", rsa.KeyExchangeAlgorithm);
// Assert other things
}
finally
{
tempDir.Delete(true);
}
}
}