1
0
mirror of https://github.com/bitwarden/server.git synced 2025-06-30 23:52:50 -05:00

Turn on file scoped namespaces (#2225)

This commit is contained in:
Justin Baur
2022-08-29 14:53:16 -04:00
committed by GitHub
parent 7c4521e0b4
commit 34fb4cca2a
1206 changed files with 73816 additions and 75022 deletions

View File

@ -2,36 +2,35 @@
using Bit.Core.Utilities;
using Xunit;
namespace Bit.Core.Test.Utilities
namespace Bit.Core.Test.Utilities;
public class ClaimsExtensionsTests
{
public class ClaimsExtensionsTests
[Fact]
public void HasSSOIdP_Returns_True_When_The_Claims_Has_One_Of_Type_IdP_And_Value_Sso()
{
[Fact]
public void HasSSOIdP_Returns_True_When_The_Claims_Has_One_Of_Type_IdP_And_Value_Sso()
{
var claims = new List<Claim> { new Claim("idp", "sso") };
Assert.True(claims.HasSsoIdP());
}
var claims = new List<Claim> { new Claim("idp", "sso") };
Assert.True(claims.HasSsoIdP());
}
[Fact]
public void HasSSOIdP_Returns_False_When_The_Claims_Has_One_Of_Type_IdP_And_Value_Is_Not_Sso()
{
var claims = new List<Claim> { new Claim("idp", "asdfasfd") };
Assert.False(claims.HasSsoIdP());
}
[Fact]
public void HasSSOIdP_Returns_False_When_The_Claims_Has_One_Of_Type_IdP_And_Value_Is_Not_Sso()
{
var claims = new List<Claim> { new Claim("idp", "asdfasfd") };
Assert.False(claims.HasSsoIdP());
}
[Fact]
public void HasSSOIdP_Returns_False_When_The_Claims_Has_No_One_Of_Type_IdP()
{
var claims = new List<Claim> { new Claim("qweqweq", "sso") };
Assert.False(claims.HasSsoIdP());
}
[Fact]
public void HasSSOIdP_Returns_False_When_The_Claims_Has_No_One_Of_Type_IdP()
{
var claims = new List<Claim> { new Claim("qweqweq", "sso") };
Assert.False(claims.HasSsoIdP());
}
[Fact]
public void HasSSOIdP_Returns_False_When_The_Claims_Are_Empty()
{
var claims = new List<Claim>();
Assert.False(claims.HasSsoIdP());
}
[Fact]
public void HasSSOIdP_Returns_False_When_The_Claims_Are_Empty()
{
var claims = new List<Claim>();
Assert.False(claims.HasSsoIdP());
}
}

View File

@ -12,434 +12,433 @@ using IdentityModel;
using Microsoft.AspNetCore.DataProtection;
using Xunit;
namespace Bit.Core.Test.Utilities
namespace Bit.Core.Test.Utilities;
public class CoreHelpersTests
{
public class CoreHelpersTests
public static IEnumerable<object[]> _epochTestCases = new[]
{
public static IEnumerable<object[]> _epochTestCases = new[]
{
new object[] {new DateTime(2020, 12, 30, 11, 49, 12, DateTimeKind.Utc), 1609328952000L},
};
new object[] {new DateTime(2020, 12, 30, 11, 49, 12, DateTimeKind.Utc), 1609328952000L},
};
[Fact]
public void GenerateComb_Success()
{
// Arrange & Act
var comb = CoreHelpers.GenerateComb();
[Fact]
public void GenerateComb_Success()
{
// Arrange & Act
var comb = CoreHelpers.GenerateComb();
// Assert
Assert.NotEqual(Guid.Empty, comb);
// TODO: Add more asserts to make sure important aspects of
// the comb are working properly
// Assert
Assert.NotEqual(Guid.Empty, comb);
// TODO: Add more asserts to make sure important aspects of
// the comb are working properly
}
public static IEnumerable<object[]> GenerateCombCases = new[]
{
new object[]
{
Guid.Parse("a58db474-43d8-42f1-b4ee-0c17647cd0c0"), // Input Guid
new DateTime(2022, 3, 12, 12, 12, 0, DateTimeKind.Utc), // Input Time
Guid.Parse("a58db474-43d8-42f1-b4ee-ae5600c90cc1"), // Expected Comb
},
new object[]
{
Guid.Parse("f776e6ee-511f-4352-bb28-88513002bdeb"),
new DateTime(2021, 5, 10, 10, 52, 0, DateTimeKind.Utc),
Guid.Parse("f776e6ee-511f-4352-bb28-ad2400b313c1"),
},
new object[]
{
Guid.Parse("51a25fc7-3cad-497d-8e2f-8d77011648a1"),
new DateTime(1999, 2, 26, 16, 53, 13, DateTimeKind.Utc),
Guid.Parse("51a25fc7-3cad-497d-8e2f-8d77011649cd"),
},
new object[]
{
Guid.Parse("bfb8f353-3b32-4a9e-bef6-24fe0b54bfb0"),
new DateTime(2024, 10, 20, 1, 32, 16, DateTimeKind.Utc),
Guid.Parse("bfb8f353-3b32-4a9e-bef6-b20f00195780"),
}
};
[Theory]
[MemberData(nameof(GenerateCombCases))]
public void GenerateComb_WithInputs_Success(Guid inputGuid, DateTime inputTime, Guid expectedComb)
{
var comb = CoreHelpers.GenerateComb(inputGuid, inputTime);
Assert.Equal(expectedComb, comb);
}
[Theory]
[InlineData(2, 5, new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 })]
[InlineData(2, 3, new[] { 1, 2, 3, 4, 5 })]
[InlineData(2, 1, new[] { 1, 2 })]
[InlineData(1, 1, new[] { 1 })]
[InlineData(2, 2, new[] { 1, 2, 3 })]
public void Batch_Success(int batchSize, int totalBatches, int[] collection)
{
// Arrange
var remainder = collection.Length % batchSize;
// Act
var batches = collection.Batch(batchSize);
// Assert
Assert.Equal(totalBatches, batches.Count());
foreach (var batch in batches.Take(totalBatches - 1))
{
Assert.Equal(batchSize, batch.Count());
}
public static IEnumerable<object[]> GenerateCombCases = new[]
{
new object[]
Assert.Equal(batches.Last().Count(), remainder == 0 ? batchSize : remainder);
}
/*
[Fact]
public void ToGuidIdArrayTVP_Success()
{
// Arrange
var item0 = Guid.NewGuid();
var item1 = Guid.NewGuid();
var ids = new[] { item0, item1 };
// Act
var dt = ids.ToGuidIdArrayTVP();
// Assert
Assert.Single(dt.Columns);
Assert.Equal("GuidId", dt.Columns[0].ColumnName);
Assert.Equal(2, dt.Rows.Count);
Assert.Equal(item0, dt.Rows[0][0]);
Assert.Equal(item1, dt.Rows[1][0]);
}
*/
// TODO: Test the other ToArrayTVP Methods
[Theory]
[InlineData("12345&6789", "123456789")]
[InlineData("abcdef", "ABCDEF")]
[InlineData("1!@#$%&*()_+", "1")]
[InlineData("\u00C6123abc\u00C7", "123ABC")]
[InlineData("123\u00C6ABC", "123ABC")]
[InlineData("\r\nHello", "E")]
[InlineData("\tdef", "DEF")]
[InlineData("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUV1234567890", "ABCDEFABCDEF1234567890")]
public void CleanCertificateThumbprint_Success(string input, string output)
{
// Arrange & Act
var sanitizedInput = CoreHelpers.CleanCertificateThumbprint(input);
// Assert
Assert.Equal(output, sanitizedInput);
}
// TODO: Add more tests
[Theory]
[MemberData(nameof(_epochTestCases))]
public void ToEpocMilliseconds_Success(DateTime date, long milliseconds)
{
// Act & Assert
Assert.Equal(milliseconds, CoreHelpers.ToEpocMilliseconds(date));
}
[Theory]
[MemberData(nameof(_epochTestCases))]
public void FromEpocMilliseconds(DateTime date, long milliseconds)
{
// Act & Assert
Assert.Equal(date, CoreHelpers.FromEpocMilliseconds(milliseconds));
}
[Fact]
public void SecureRandomString_Success()
{
// Arrange & Act
var @string = CoreHelpers.SecureRandomString(8);
// Assert
// TODO: Should probably add more Asserts down the line
Assert.Equal(8, @string.Length);
}
[Theory]
[InlineData(1, "1 Bytes")]
[InlineData(-5L, "-5 Bytes")]
[InlineData(1023L, "1023 Bytes")]
[InlineData(1024L, "1 KB")]
[InlineData(1025L, "1 KB")]
[InlineData(-1023L, "-1023 Bytes")]
[InlineData(-1024L, "-1 KB")]
[InlineData(-1025L, "-1 KB")]
[InlineData(1048575L, "1024 KB")]
[InlineData(1048576L, "1 MB")]
[InlineData(1048577L, "1 MB")]
[InlineData(-1048575L, "-1024 KB")]
[InlineData(-1048576L, "-1 MB")]
[InlineData(-1048577L, "-1 MB")]
[InlineData(1073741823L, "1024 MB")]
[InlineData(1073741824L, "1 GB")]
[InlineData(1073741825L, "1 GB")]
[InlineData(-1073741823L, "-1024 MB")]
[InlineData(-1073741824L, "-1 GB")]
[InlineData(-1073741825L, "-1 GB")]
[InlineData(long.MaxValue, "8589934592 GB")]
public void ReadableBytesSize_Success(long size, string readable)
{
// Act & Assert
Assert.Equal(readable, CoreHelpers.ReadableBytesSize(size));
}
[Fact]
public void CloneObject_Success()
{
var original = new { Message = "Message" };
var copy = CoreHelpers.CloneObject(original);
Assert.Equal(original.Message, copy.Message);
}
[Fact]
public void ExtendQuery_AddNewParameter_Success()
{
// Arrange
var uri = new Uri("https://bitwarden.com/?param1=value1");
// Act
var newUri = CoreHelpers.ExtendQuery(uri,
new Dictionary<string, string> { { "param2", "value2" } });
// Assert
Assert.Equal("https://bitwarden.com/?param1=value1&param2=value2", newUri.ToString());
}
[Fact]
public void ExtendQuery_AddTwoNewParameters_Success()
{
// Arrange
var uri = new Uri("https://bitwarden.com/?param1=value1");
// Act
var newUri = CoreHelpers.ExtendQuery(uri,
new Dictionary<string, string>
{
Guid.Parse("a58db474-43d8-42f1-b4ee-0c17647cd0c0"), // Input Guid
new DateTime(2022, 3, 12, 12, 12, 0, DateTimeKind.Utc), // Input Time
Guid.Parse("a58db474-43d8-42f1-b4ee-ae5600c90cc1"), // Expected Comb
},
new object[]
{
Guid.Parse("f776e6ee-511f-4352-bb28-88513002bdeb"),
new DateTime(2021, 5, 10, 10, 52, 0, DateTimeKind.Utc),
Guid.Parse("f776e6ee-511f-4352-bb28-ad2400b313c1"),
},
new object[]
{
Guid.Parse("51a25fc7-3cad-497d-8e2f-8d77011648a1"),
new DateTime(1999, 2, 26, 16, 53, 13, DateTimeKind.Utc),
Guid.Parse("51a25fc7-3cad-497d-8e2f-8d77011649cd"),
},
new object[]
{
Guid.Parse("bfb8f353-3b32-4a9e-bef6-24fe0b54bfb0"),
new DateTime(2024, 10, 20, 1, 32, 16, DateTimeKind.Utc),
Guid.Parse("bfb8f353-3b32-4a9e-bef6-b20f00195780"),
}
};
{ "param2", "value2" },
{ "param3", "value3" }
});
[Theory]
[MemberData(nameof(GenerateCombCases))]
public void GenerateComb_WithInputs_Success(Guid inputGuid, DateTime inputTime, Guid expectedComb)
// Assert
Assert.Equal("https://bitwarden.com/?param1=value1&param2=value2&param3=value3", newUri.ToString());
}
[Fact]
public void ExtendQuery_AddExistingParameter_Success()
{
// Arrange
var uri = new Uri("https://bitwarden.com/?param1=value1&param2=value2");
// Act
var newUri = CoreHelpers.ExtendQuery(uri,
new Dictionary<string, string> { { "param1", "test_value" } });
// Assert
Assert.Equal("https://bitwarden.com/?param1=test_value&param2=value2", newUri.ToString());
}
[Fact]
public void ExtendQuery_AddNoParameters_Success()
{
// Arrange
const string startingUri = "https://bitwarden.com/?param1=value1";
var uri = new Uri(startingUri);
// Act
var newUri = CoreHelpers.ExtendQuery(uri, new Dictionary<string, string>());
// Assert
Assert.Equal(startingUri, newUri.ToString());
}
[Theory]
[InlineData("bücher.com", "xn--bcher-kva.com")]
[InlineData("bücher.cömé", "xn--bcher-kva.xn--cm-cja4c")]
[InlineData("hello@bücher.com", "hello@xn--bcher-kva.com")]
[InlineData("hello@world.cömé", "hello@world.xn--cm-cja4c")]
[InlineData("hello@bücher.cömé", "hello@xn--bcher-kva.xn--cm-cja4c")]
[InlineData("ascii.com", "ascii.com")]
[InlineData("", "")]
[InlineData(null, null)]
public void PunyEncode_Success(string text, string expected)
{
var actual = CoreHelpers.PunyEncode(text);
Assert.Equal(expected, actual);
}
[Fact]
public void GetEmbeddedResourceContentsAsync_Success()
{
var fileContents = CoreHelpers.GetEmbeddedResourceContentsAsync("data.embeddedResource.txt");
Assert.Equal("Contents of embeddedResource.txt\n", fileContents.Replace("\r\n", "\n"));
}
[Theory, CustomAutoData(typeof(UserFixture))]
public void BuildIdentityClaims_BaseClaims_Success(User user, bool isPremium)
{
var expected = new Dictionary<string, string>
{
var comb = CoreHelpers.GenerateComb(inputGuid, inputTime);
{ "premium", isPremium ? "true" : "false" },
{ JwtClaimTypes.Email, user.Email },
{ JwtClaimTypes.EmailVerified, user.EmailVerified ? "true" : "false" },
{ JwtClaimTypes.Name, user.Name },
{ "sstamp", user.SecurityStamp },
}.ToList();
Assert.Equal(expectedComb, comb);
var actual = CoreHelpers.BuildIdentityClaims(user, Array.Empty<CurrentContentOrganization>(),
Array.Empty<CurrentContentProvider>(), isPremium);
foreach (var claim in expected)
{
Assert.Contains(claim, actual);
}
Assert.Equal(expected.Count, actual.Count);
}
[Theory]
[InlineData(2, 5, new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 })]
[InlineData(2, 3, new[] { 1, 2, 3, 4, 5 })]
[InlineData(2, 1, new[] { 1, 2 })]
[InlineData(1, 1, new[] { 1 })]
[InlineData(2, 2, new[] { 1, 2, 3 })]
public void Batch_Success(int batchSize, int totalBatches, int[] collection)
[Theory, CustomAutoData(typeof(UserFixture))]
public void BuildIdentityClaims_NonCustomOrganizationUserType_Success(User user)
{
var fixture = new Fixture().WithAutoNSubstitutions();
foreach (var organizationUserType in Enum.GetValues<OrganizationUserType>().Except(new[] { OrganizationUserType.Custom }))
{
// Arrange
var remainder = collection.Length % batchSize;
// Act
var batches = collection.Batch(batchSize);
// Assert
Assert.Equal(totalBatches, batches.Count());
foreach (var batch in batches.Take(totalBatches - 1))
{
Assert.Equal(batchSize, batch.Count());
}
Assert.Equal(batches.Last().Count(), remainder == 0 ? batchSize : remainder);
}
/*
[Fact]
public void ToGuidIdArrayTVP_Success()
{
// Arrange
var item0 = Guid.NewGuid();
var item1 = Guid.NewGuid();
var ids = new[] { item0, item1 };
// Act
var dt = ids.ToGuidIdArrayTVP();
// Assert
Assert.Single(dt.Columns);
Assert.Equal("GuidId", dt.Columns[0].ColumnName);
Assert.Equal(2, dt.Rows.Count);
Assert.Equal(item0, dt.Rows[0][0]);
Assert.Equal(item1, dt.Rows[1][0]);
}
*/
// TODO: Test the other ToArrayTVP Methods
[Theory]
[InlineData("12345&6789", "123456789")]
[InlineData("abcdef", "ABCDEF")]
[InlineData("1!@#$%&*()_+", "1")]
[InlineData("\u00C6123abc\u00C7", "123ABC")]
[InlineData("123\u00C6ABC", "123ABC")]
[InlineData("\r\nHello", "E")]
[InlineData("\tdef", "DEF")]
[InlineData("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUV1234567890", "ABCDEFABCDEF1234567890")]
public void CleanCertificateThumbprint_Success(string input, string output)
{
// Arrange & Act
var sanitizedInput = CoreHelpers.CleanCertificateThumbprint(input);
// Assert
Assert.Equal(output, sanitizedInput);
}
// TODO: Add more tests
[Theory]
[MemberData(nameof(_epochTestCases))]
public void ToEpocMilliseconds_Success(DateTime date, long milliseconds)
{
// Act & Assert
Assert.Equal(milliseconds, CoreHelpers.ToEpocMilliseconds(date));
}
[Theory]
[MemberData(nameof(_epochTestCases))]
public void FromEpocMilliseconds(DateTime date, long milliseconds)
{
// Act & Assert
Assert.Equal(date, CoreHelpers.FromEpocMilliseconds(milliseconds));
}
[Fact]
public void SecureRandomString_Success()
{
// Arrange & Act
var @string = CoreHelpers.SecureRandomString(8);
// Assert
// TODO: Should probably add more Asserts down the line
Assert.Equal(8, @string.Length);
}
[Theory]
[InlineData(1, "1 Bytes")]
[InlineData(-5L, "-5 Bytes")]
[InlineData(1023L, "1023 Bytes")]
[InlineData(1024L, "1 KB")]
[InlineData(1025L, "1 KB")]
[InlineData(-1023L, "-1023 Bytes")]
[InlineData(-1024L, "-1 KB")]
[InlineData(-1025L, "-1 KB")]
[InlineData(1048575L, "1024 KB")]
[InlineData(1048576L, "1 MB")]
[InlineData(1048577L, "1 MB")]
[InlineData(-1048575L, "-1024 KB")]
[InlineData(-1048576L, "-1 MB")]
[InlineData(-1048577L, "-1 MB")]
[InlineData(1073741823L, "1024 MB")]
[InlineData(1073741824L, "1 GB")]
[InlineData(1073741825L, "1 GB")]
[InlineData(-1073741823L, "-1024 MB")]
[InlineData(-1073741824L, "-1 GB")]
[InlineData(-1073741825L, "-1 GB")]
[InlineData(long.MaxValue, "8589934592 GB")]
public void ReadableBytesSize_Success(long size, string readable)
{
// Act & Assert
Assert.Equal(readable, CoreHelpers.ReadableBytesSize(size));
}
[Fact]
public void CloneObject_Success()
{
var original = new { Message = "Message" };
var copy = CoreHelpers.CloneObject(original);
Assert.Equal(original.Message, copy.Message);
}
[Fact]
public void ExtendQuery_AddNewParameter_Success()
{
// Arrange
var uri = new Uri("https://bitwarden.com/?param1=value1");
// Act
var newUri = CoreHelpers.ExtendQuery(uri,
new Dictionary<string, string> { { "param2", "value2" } });
// Assert
Assert.Equal("https://bitwarden.com/?param1=value1&param2=value2", newUri.ToString());
}
[Fact]
public void ExtendQuery_AddTwoNewParameters_Success()
{
// Arrange
var uri = new Uri("https://bitwarden.com/?param1=value1");
// Act
var newUri = CoreHelpers.ExtendQuery(uri,
new Dictionary<string, string>
{
{ "param2", "value2" },
{ "param3", "value3" }
});
// Assert
Assert.Equal("https://bitwarden.com/?param1=value1&param2=value2&param3=value3", newUri.ToString());
}
[Fact]
public void ExtendQuery_AddExistingParameter_Success()
{
// Arrange
var uri = new Uri("https://bitwarden.com/?param1=value1&param2=value2");
// Act
var newUri = CoreHelpers.ExtendQuery(uri,
new Dictionary<string, string> { { "param1", "test_value" } });
// Assert
Assert.Equal("https://bitwarden.com/?param1=test_value&param2=value2", newUri.ToString());
}
[Fact]
public void ExtendQuery_AddNoParameters_Success()
{
// Arrange
const string startingUri = "https://bitwarden.com/?param1=value1";
var uri = new Uri(startingUri);
// Act
var newUri = CoreHelpers.ExtendQuery(uri, new Dictionary<string, string>());
// Assert
Assert.Equal(startingUri, newUri.ToString());
}
[Theory]
[InlineData("bücher.com", "xn--bcher-kva.com")]
[InlineData("bücher.cömé", "xn--bcher-kva.xn--cm-cja4c")]
[InlineData("hello@bücher.com", "hello@xn--bcher-kva.com")]
[InlineData("hello@world.cömé", "hello@world.xn--cm-cja4c")]
[InlineData("hello@bücher.cömé", "hello@xn--bcher-kva.xn--cm-cja4c")]
[InlineData("ascii.com", "ascii.com")]
[InlineData("", "")]
[InlineData(null, null)]
public void PunyEncode_Success(string text, string expected)
{
var actual = CoreHelpers.PunyEncode(text);
Assert.Equal(expected, actual);
}
[Fact]
public void GetEmbeddedResourceContentsAsync_Success()
{
var fileContents = CoreHelpers.GetEmbeddedResourceContentsAsync("data.embeddedResource.txt");
Assert.Equal("Contents of embeddedResource.txt\n", fileContents.Replace("\r\n", "\n"));
}
[Theory, CustomAutoData(typeof(UserFixture))]
public void BuildIdentityClaims_BaseClaims_Success(User user, bool isPremium)
{
var expected = new Dictionary<string, string>
{
{ "premium", isPremium ? "true" : "false" },
{ JwtClaimTypes.Email, user.Email },
{ JwtClaimTypes.EmailVerified, user.EmailVerified ? "true" : "false" },
{ JwtClaimTypes.Name, user.Name },
{ "sstamp", user.SecurityStamp },
}.ToList();
var actual = CoreHelpers.BuildIdentityClaims(user, Array.Empty<CurrentContentOrganization>(),
Array.Empty<CurrentContentProvider>(), isPremium);
foreach (var claim in expected)
{
Assert.Contains(claim, actual);
}
Assert.Equal(expected.Count, actual.Count);
}
[Theory, CustomAutoData(typeof(UserFixture))]
public void BuildIdentityClaims_NonCustomOrganizationUserType_Success(User user)
{
var fixture = new Fixture().WithAutoNSubstitutions();
foreach (var organizationUserType in Enum.GetValues<OrganizationUserType>().Except(new[] { OrganizationUserType.Custom }))
{
var org = fixture.Create<CurrentContentOrganization>();
org.Type = organizationUserType;
var expected = new KeyValuePair<string, string>($"org{organizationUserType.ToString().ToLower()}", org.Id.ToString());
var actual = CoreHelpers.BuildIdentityClaims(user, new[] { org }, Array.Empty<CurrentContentProvider>(), false);
Assert.Contains(expected, actual);
}
}
[Theory, CustomAutoData(typeof(UserFixture))]
public void BuildIdentityClaims_CustomOrganizationUserClaims_Success(User user, CurrentContentOrganization org)
{
var fixture = new Fixture().WithAutoNSubstitutions();
org.Type = OrganizationUserType.Custom;
var org = fixture.Create<CurrentContentOrganization>();
org.Type = organizationUserType;
var expected = new KeyValuePair<string, string>($"org{organizationUserType.ToString().ToLower()}", org.Id.ToString());
var actual = CoreHelpers.BuildIdentityClaims(user, new[] { org }, Array.Empty<CurrentContentProvider>(), false);
foreach (var (permitted, claimName) in org.Permissions.ClaimsMap)
{
var claim = new KeyValuePair<string, string>(claimName, org.Id.ToString());
if (permitted)
{
Assert.Contains(claim, actual);
}
else
{
Assert.DoesNotContain(claim, actual);
}
}
}
[Theory, CustomAutoData(typeof(UserFixture))]
public void BuildIdentityClaims_ProviderClaims_Success(User user)
{
var fixture = new Fixture().WithAutoNSubstitutions();
var providers = new List<CurrentContentProvider>();
foreach (var providerUserType in Enum.GetValues<ProviderUserType>())
{
var provider = fixture.Create<CurrentContentProvider>();
provider.Type = providerUserType;
providers.Add(provider);
}
var claims = new List<KeyValuePair<string, string>>();
if (providers.Any())
{
foreach (var group in providers.GroupBy(o => o.Type))
{
switch (group.Key)
{
case ProviderUserType.ProviderAdmin:
foreach (var provider in group)
{
claims.Add(new KeyValuePair<string, string>("providerprovideradmin", provider.Id.ToString()));
}
break;
case ProviderUserType.ServiceUser:
foreach (var provider in group)
{
claims.Add(new KeyValuePair<string, string>("providerserviceuser", provider.Id.ToString()));
}
break;
}
}
}
var actual = CoreHelpers.BuildIdentityClaims(user, Array.Empty<CurrentContentOrganization>(), providers, false);
foreach (var claim in claims)
{
Assert.Contains(claim, actual);
}
}
public static IEnumerable<object[]> TokenIsValidData()
{
return new[]
{
new object[]
{
"first_part 476669d4-9642-4af8-9b29-9366efad4ed3 test@email.com {0}", // unprotectedTokenTemplate
"first_part", // firstPart
"test@email.com", // email
Guid.Parse("476669d4-9642-4af8-9b29-9366efad4ed3"), // id
DateTime.UtcNow.AddHours(-1), // creationTime
12, // expirationInHours
true, // isValid
}
};
}
[Theory]
[MemberData(nameof(TokenIsValidData))]
public void TokenIsValid_Success(string unprotectedTokenTemplate, string firstPart, string userEmail, Guid id, DateTime creationTime, double expirationInHours, bool isValid)
{
var protector = new TestDataProtector(string.Format(unprotectedTokenTemplate, CoreHelpers.ToEpocMilliseconds(creationTime)));
Assert.Equal(isValid, CoreHelpers.TokenIsValid(firstPart, protector, "protected_token", userEmail, id, expirationInHours));
}
private class TestDataProtector : IDataProtector
{
private readonly string _token;
public TestDataProtector(string token)
{
_token = token;
}
public IDataProtector CreateProtector(string purpose) => throw new NotImplementedException();
public byte[] Protect(byte[] plaintext) => throw new NotImplementedException();
public byte[] Unprotect(byte[] protectedData)
{
return Encoding.UTF8.GetBytes(_token);
}
}
[Theory]
[InlineData("hi@email.com", "hi@email.com")] // Short email with no room to obfuscate
[InlineData("name@email.com", "na**@email.com")] // Can obfuscate
[InlineData("reallylongnamethatnooneshouldhave@email", "re*******************************@email")] // Really long email and no .com, .net, etc
[InlineData("name@", "name@")] // @ symbol but no domain
[InlineData("", "")] // Empty string
[InlineData(null, null)] // null
public void ObfuscateEmail_Success(string input, string expected)
{
Assert.Equal(expected, CoreHelpers.ObfuscateEmail(input));
Assert.Contains(expected, actual);
}
}
[Theory, CustomAutoData(typeof(UserFixture))]
public void BuildIdentityClaims_CustomOrganizationUserClaims_Success(User user, CurrentContentOrganization org)
{
var fixture = new Fixture().WithAutoNSubstitutions();
org.Type = OrganizationUserType.Custom;
var actual = CoreHelpers.BuildIdentityClaims(user, new[] { org }, Array.Empty<CurrentContentProvider>(), false);
foreach (var (permitted, claimName) in org.Permissions.ClaimsMap)
{
var claim = new KeyValuePair<string, string>(claimName, org.Id.ToString());
if (permitted)
{
Assert.Contains(claim, actual);
}
else
{
Assert.DoesNotContain(claim, actual);
}
}
}
[Theory, CustomAutoData(typeof(UserFixture))]
public void BuildIdentityClaims_ProviderClaims_Success(User user)
{
var fixture = new Fixture().WithAutoNSubstitutions();
var providers = new List<CurrentContentProvider>();
foreach (var providerUserType in Enum.GetValues<ProviderUserType>())
{
var provider = fixture.Create<CurrentContentProvider>();
provider.Type = providerUserType;
providers.Add(provider);
}
var claims = new List<KeyValuePair<string, string>>();
if (providers.Any())
{
foreach (var group in providers.GroupBy(o => o.Type))
{
switch (group.Key)
{
case ProviderUserType.ProviderAdmin:
foreach (var provider in group)
{
claims.Add(new KeyValuePair<string, string>("providerprovideradmin", provider.Id.ToString()));
}
break;
case ProviderUserType.ServiceUser:
foreach (var provider in group)
{
claims.Add(new KeyValuePair<string, string>("providerserviceuser", provider.Id.ToString()));
}
break;
}
}
}
var actual = CoreHelpers.BuildIdentityClaims(user, Array.Empty<CurrentContentOrganization>(), providers, false);
foreach (var claim in claims)
{
Assert.Contains(claim, actual);
}
}
public static IEnumerable<object[]> TokenIsValidData()
{
return new[]
{
new object[]
{
"first_part 476669d4-9642-4af8-9b29-9366efad4ed3 test@email.com {0}", // unprotectedTokenTemplate
"first_part", // firstPart
"test@email.com", // email
Guid.Parse("476669d4-9642-4af8-9b29-9366efad4ed3"), // id
DateTime.UtcNow.AddHours(-1), // creationTime
12, // expirationInHours
true, // isValid
}
};
}
[Theory]
[MemberData(nameof(TokenIsValidData))]
public void TokenIsValid_Success(string unprotectedTokenTemplate, string firstPart, string userEmail, Guid id, DateTime creationTime, double expirationInHours, bool isValid)
{
var protector = new TestDataProtector(string.Format(unprotectedTokenTemplate, CoreHelpers.ToEpocMilliseconds(creationTime)));
Assert.Equal(isValid, CoreHelpers.TokenIsValid(firstPart, protector, "protected_token", userEmail, id, expirationInHours));
}
private class TestDataProtector : IDataProtector
{
private readonly string _token;
public TestDataProtector(string token)
{
_token = token;
}
public IDataProtector CreateProtector(string purpose) => throw new NotImplementedException();
public byte[] Protect(byte[] plaintext) => throw new NotImplementedException();
public byte[] Unprotect(byte[] protectedData)
{
return Encoding.UTF8.GetBytes(_token);
}
}
[Theory]
[InlineData("hi@email.com", "hi@email.com")] // Short email with no room to obfuscate
[InlineData("name@email.com", "na**@email.com")] // Can obfuscate
[InlineData("reallylongnamethatnooneshouldhave@email", "re*******************************@email")] // Really long email and no .com, .net, etc
[InlineData("name@", "name@")] // @ symbol but no domain
[InlineData("", "")] // Empty string
[InlineData(null, null)] // null
public void ObfuscateEmail_Success(string input, string expected)
{
Assert.Equal(expected, CoreHelpers.ObfuscateEmail(input));
}
}

View File

@ -1,43 +1,42 @@
using Bit.Core.Utilities;
using Xunit;
namespace Bit.Core.Test.Utilities
namespace Bit.Core.Test.Utilities;
public class EncryptedStringAttributeTests
{
public class EncryptedStringAttributeTests
[Theory]
[InlineData(null)]
[InlineData("aXY=|Y3Q=")] // Valid AesCbc256_B64
[InlineData("aXY=|Y3Q=|cnNhQ3Q=")] // Valid AesCbc128_HmacSha256_B64
[InlineData("Rsa2048_OaepSha256_B64.cnNhQ3Q=")]
public void IsValid_ReturnsTrue_WhenValid(string input)
{
[Theory]
[InlineData(null)]
[InlineData("aXY=|Y3Q=")] // Valid AesCbc256_B64
[InlineData("aXY=|Y3Q=|cnNhQ3Q=")] // Valid AesCbc128_HmacSha256_B64
[InlineData("Rsa2048_OaepSha256_B64.cnNhQ3Q=")]
public void IsValid_ReturnsTrue_WhenValid(string input)
{
var sut = new EncryptedStringAttribute();
var sut = new EncryptedStringAttribute();
var actual = sut.IsValid(input);
var actual = sut.IsValid(input);
Assert.True(actual);
}
Assert.True(actual);
}
[Theory]
[InlineData("")]
[InlineData(".")]
[InlineData("|")]
[InlineData("!|!")] // Invalid base 64
[InlineData("Rsa2048_OaepSha1_HmacSha256_B64.1")] // Invalid length
[InlineData("Rsa2048_OaepSha1_HmacSha256_B64.|")] // Empty iv & ct
[InlineData("AesCbc128_HmacSha256_B64.1")] // Invalid length
[InlineData("AesCbc128_HmacSha256_B64.aXY=|Y3Q=|")] // Empty mac
[InlineData("Rsa2048_OaepSha1_HmacSha256_B64.aXY=|Y3Q=|")] // Empty mac
[InlineData("Rsa2048_OaepSha256_B64.1|2")] // Invalid length
[InlineData("Rsa2048_OaepSha1_HmacSha256_B64.aXY=|")] // Empty mac
public void IsValid_ReturnsFalse_WhenInvalid(string input)
{
var sut = new EncryptedStringAttribute();
[Theory]
[InlineData("")]
[InlineData(".")]
[InlineData("|")]
[InlineData("!|!")] // Invalid base 64
[InlineData("Rsa2048_OaepSha1_HmacSha256_B64.1")] // Invalid length
[InlineData("Rsa2048_OaepSha1_HmacSha256_B64.|")] // Empty iv & ct
[InlineData("AesCbc128_HmacSha256_B64.1")] // Invalid length
[InlineData("AesCbc128_HmacSha256_B64.aXY=|Y3Q=|")] // Empty mac
[InlineData("Rsa2048_OaepSha1_HmacSha256_B64.aXY=|Y3Q=|")] // Empty mac
[InlineData("Rsa2048_OaepSha256_B64.1|2")] // Invalid length
[InlineData("Rsa2048_OaepSha1_HmacSha256_B64.aXY=|")] // Empty mac
public void IsValid_ReturnsFalse_WhenInvalid(string input)
{
var sut = new EncryptedStringAttribute();
var actual = sut.IsValid(input);
var actual = sut.IsValid(input);
Assert.False(actual);
}
Assert.False(actual);
}
}

View File

@ -2,65 +2,64 @@
using Bit.Core.Utilities;
using Xunit;
namespace Bit.Core.Test.Helpers
namespace Bit.Core.Test.Helpers;
public class JsonHelpersTests
{
public class JsonHelpersTests
private static void CompareJson<T>(T value, JsonSerializerOptions options, Newtonsoft.Json.JsonSerializerSettings settings)
{
private static void CompareJson<T>(T value, JsonSerializerOptions options, Newtonsoft.Json.JsonSerializerSettings settings)
{
var stgJson = JsonSerializer.Serialize(value, options);
var nsJson = Newtonsoft.Json.JsonConvert.SerializeObject(value, settings);
var stgJson = JsonSerializer.Serialize(value, options);
var nsJson = Newtonsoft.Json.JsonConvert.SerializeObject(value, settings);
Assert.Equal(stgJson, nsJson);
}
[Fact]
public void DefaultJsonOptions()
{
var testObject = new SimpleTestObject
{
Id = 0,
Name = "Test",
};
CompareJson(testObject, JsonHelpers.Default, new Newtonsoft.Json.JsonSerializerSettings());
}
[Fact]
public void IndentedJsonOptions()
{
var testObject = new SimpleTestObject
{
Id = 10,
Name = "Test Name"
};
CompareJson(testObject, JsonHelpers.Indented, new Newtonsoft.Json.JsonSerializerSettings
{
Formatting = Newtonsoft.Json.Formatting.Indented,
});
}
[Fact]
public void NullValueHandlingJsonOptions()
{
var testObject = new SimpleTestObject
{
Id = 14,
Name = null,
};
CompareJson(testObject, JsonHelpers.IgnoreWritingNull, new Newtonsoft.Json.JsonSerializerSettings
{
NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore,
});
}
Assert.Equal(stgJson, nsJson);
}
public class SimpleTestObject
[Fact]
public void DefaultJsonOptions()
{
public int Id { get; set; }
public string Name { get; set; }
var testObject = new SimpleTestObject
{
Id = 0,
Name = "Test",
};
CompareJson(testObject, JsonHelpers.Default, new Newtonsoft.Json.JsonSerializerSettings());
}
[Fact]
public void IndentedJsonOptions()
{
var testObject = new SimpleTestObject
{
Id = 10,
Name = "Test Name"
};
CompareJson(testObject, JsonHelpers.Indented, new Newtonsoft.Json.JsonSerializerSettings
{
Formatting = Newtonsoft.Json.Formatting.Indented,
});
}
[Fact]
public void NullValueHandlingJsonOptions()
{
var testObject = new SimpleTestObject
{
Id = 14,
Name = null,
};
CompareJson(testObject, JsonHelpers.IgnoreWritingNull, new Newtonsoft.Json.JsonSerializerSettings
{
NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore,
});
}
}
public class SimpleTestObject
{
public int Id { get; set; }
public string Name { get; set; }
}

View File

@ -5,165 +5,164 @@ using Bit.Core.Utilities;
using Bit.Test.Common.Helpers;
using Xunit;
namespace Bit.Core.Test.Utilities
namespace Bit.Core.Test.Utilities;
public class PermissiveStringConverterTests
{
public class PermissiveStringConverterTests
private const string numberJson = "{ \"StringProp\": 1, \"EnumerableStringProp\": [ 2, 3 ]}";
private const string stringJson = "{ \"StringProp\": \"1\", \"EnumerableStringProp\": [ \"2\", \"3\" ]}";
private const string nullAndEmptyJson = "{ \"StringProp\": null, \"EnumerableStringProp\": [] }";
private const string singleValueJson = "{ \"StringProp\": 1, \"EnumerableStringProp\": \"Hello!\" }";
private const string nullJson = "{ \"StringProp\": null, \"EnumerableStringProp\": null }";
private const string boolJson = "{ \"StringProp\": true, \"EnumerableStringProp\": [ false, 1.2]}";
private const string objectJsonOne = "{ \"StringProp\": { \"Message\": \"Hi\"}, \"EnumerableStringProp\": []}";
private const string objectJsonTwo = "{ \"StringProp\": \"Hi\", \"EnumerableStringProp\": {}}";
private readonly string bigNumbersJson =
"{ \"StringProp\":" + decimal.MinValue + ", \"EnumerableStringProp\": [" + ulong.MaxValue + ", " + long.MinValue + "]}";
[Theory]
[InlineData(numberJson)]
[InlineData(stringJson)]
public void Read_Success(string json)
{
private const string numberJson = "{ \"StringProp\": 1, \"EnumerableStringProp\": [ 2, 3 ]}";
private const string stringJson = "{ \"StringProp\": \"1\", \"EnumerableStringProp\": [ \"2\", \"3\" ]}";
private const string nullAndEmptyJson = "{ \"StringProp\": null, \"EnumerableStringProp\": [] }";
private const string singleValueJson = "{ \"StringProp\": 1, \"EnumerableStringProp\": \"Hello!\" }";
private const string nullJson = "{ \"StringProp\": null, \"EnumerableStringProp\": null }";
private const string boolJson = "{ \"StringProp\": true, \"EnumerableStringProp\": [ false, 1.2]}";
private const string objectJsonOne = "{ \"StringProp\": { \"Message\": \"Hi\"}, \"EnumerableStringProp\": []}";
private const string objectJsonTwo = "{ \"StringProp\": \"Hi\", \"EnumerableStringProp\": {}}";
private readonly string bigNumbersJson =
"{ \"StringProp\":" + decimal.MinValue + ", \"EnumerableStringProp\": [" + ulong.MaxValue + ", " + long.MinValue + "]}";
[Theory]
[InlineData(numberJson)]
[InlineData(stringJson)]
public void Read_Success(string json)
{
var obj = JsonSerializer.Deserialize<TestObject>(json);
Assert.Equal("1", obj.StringProp);
Assert.Equal(2, obj.EnumerableStringProp.Count());
Assert.Equal("2", obj.EnumerableStringProp.ElementAt(0));
Assert.Equal("3", obj.EnumerableStringProp.ElementAt(1));
}
[Fact]
public void Read_Boolean_Success()
{
var obj = JsonSerializer.Deserialize<TestObject>(boolJson);
Assert.Equal("True", obj.StringProp);
Assert.Equal(2, obj.EnumerableStringProp.Count());
Assert.Equal("False", obj.EnumerableStringProp.ElementAt(0));
Assert.Equal("1.2", obj.EnumerableStringProp.ElementAt(1));
}
[Fact]
public void Read_Float_Success_Culture()
{
var ci = new CultureInfo("sv-SE");
Thread.CurrentThread.CurrentCulture = ci;
Thread.CurrentThread.CurrentUICulture = ci;
var obj = JsonSerializer.Deserialize<TestObject>(boolJson);
Assert.Equal("1.2", obj.EnumerableStringProp.ElementAt(1));
}
[Fact]
public void Read_BigNumbers_Success()
{
var obj = JsonSerializer.Deserialize<TestObject>(bigNumbersJson);
Assert.Equal(decimal.MinValue.ToString(), obj.StringProp);
Assert.Equal(2, obj.EnumerableStringProp.Count());
Assert.Equal(ulong.MaxValue.ToString(), obj.EnumerableStringProp.ElementAt(0));
Assert.Equal(long.MinValue.ToString(), obj.EnumerableStringProp.ElementAt(1));
}
[Fact]
public void Read_SingleValue_Success()
{
var obj = JsonSerializer.Deserialize<TestObject>(singleValueJson);
Assert.Equal("1", obj.StringProp);
Assert.Single(obj.EnumerableStringProp);
Assert.Equal("Hello!", obj.EnumerableStringProp.ElementAt(0));
}
[Fact]
public void Read_NullAndEmptyJson_Success()
{
var obj = JsonSerializer.Deserialize<TestObject>(nullAndEmptyJson);
Assert.Null(obj.StringProp);
Assert.Empty(obj.EnumerableStringProp);
}
[Fact]
public void Read_Null_Success()
{
var obj = JsonSerializer.Deserialize<TestObject>(nullJson);
Assert.Null(obj.StringProp);
Assert.Null(obj.EnumerableStringProp);
}
[Theory]
[InlineData(objectJsonOne)]
[InlineData(objectJsonTwo)]
public void Read_Object_Throws(string json)
{
var exception = Assert.Throws<JsonException>(() => JsonSerializer.Deserialize<TestObject>(json));
}
[Fact]
public void Write_Success()
{
var json = JsonSerializer.Serialize(new TestObject
{
StringProp = "1",
EnumerableStringProp = new List<string>
{
"2",
"3",
},
});
var jsonElement = JsonDocument.Parse(json).RootElement;
var stringProp = AssertHelper.AssertJsonProperty(jsonElement, "StringProp", JsonValueKind.String);
Assert.Equal("1", stringProp.GetString());
var list = AssertHelper.AssertJsonProperty(jsonElement, "EnumerableStringProp", JsonValueKind.Array);
Assert.Equal(2, list.GetArrayLength());
var firstElement = list[0];
Assert.Equal(JsonValueKind.String, firstElement.ValueKind);
Assert.Equal("2", firstElement.GetString());
var secondElement = list[1];
Assert.Equal(JsonValueKind.String, secondElement.ValueKind);
Assert.Equal("3", secondElement.GetString());
}
[Fact]
public void Write_Null()
{
// When the values are null the converters aren't actually ran and it automatically serializes null
var json = JsonSerializer.Serialize(new TestObject
{
StringProp = null,
EnumerableStringProp = null,
});
var jsonElement = JsonDocument.Parse(json).RootElement;
AssertHelper.AssertJsonProperty(jsonElement, "StringProp", JsonValueKind.Null);
AssertHelper.AssertJsonProperty(jsonElement, "EnumerableStringProp", JsonValueKind.Null);
}
[Fact]
public void Write_Empty()
{
// When the values are null the converters aren't actually ran and it automatically serializes null
var json = JsonSerializer.Serialize(new TestObject
{
StringProp = "",
EnumerableStringProp = Enumerable.Empty<string>(),
});
var jsonElement = JsonDocument.Parse(json).RootElement;
var stringVal = AssertHelper.AssertJsonProperty(jsonElement, "StringProp", JsonValueKind.String).GetString();
Assert.Equal("", stringVal);
var array = AssertHelper.AssertJsonProperty(jsonElement, "EnumerableStringProp", JsonValueKind.Array);
Assert.Equal(0, array.GetArrayLength());
}
var obj = JsonSerializer.Deserialize<TestObject>(json);
Assert.Equal("1", obj.StringProp);
Assert.Equal(2, obj.EnumerableStringProp.Count());
Assert.Equal("2", obj.EnumerableStringProp.ElementAt(0));
Assert.Equal("3", obj.EnumerableStringProp.ElementAt(1));
}
public class TestObject
[Fact]
public void Read_Boolean_Success()
{
[JsonConverter(typeof(PermissiveStringConverter))]
public string StringProp { get; set; }
var obj = JsonSerializer.Deserialize<TestObject>(boolJson);
Assert.Equal("True", obj.StringProp);
Assert.Equal(2, obj.EnumerableStringProp.Count());
Assert.Equal("False", obj.EnumerableStringProp.ElementAt(0));
Assert.Equal("1.2", obj.EnumerableStringProp.ElementAt(1));
}
[JsonConverter(typeof(PermissiveStringEnumerableConverter))]
public IEnumerable<string> EnumerableStringProp { get; set; }
[Fact]
public void Read_Float_Success_Culture()
{
var ci = new CultureInfo("sv-SE");
Thread.CurrentThread.CurrentCulture = ci;
Thread.CurrentThread.CurrentUICulture = ci;
var obj = JsonSerializer.Deserialize<TestObject>(boolJson);
Assert.Equal("1.2", obj.EnumerableStringProp.ElementAt(1));
}
[Fact]
public void Read_BigNumbers_Success()
{
var obj = JsonSerializer.Deserialize<TestObject>(bigNumbersJson);
Assert.Equal(decimal.MinValue.ToString(), obj.StringProp);
Assert.Equal(2, obj.EnumerableStringProp.Count());
Assert.Equal(ulong.MaxValue.ToString(), obj.EnumerableStringProp.ElementAt(0));
Assert.Equal(long.MinValue.ToString(), obj.EnumerableStringProp.ElementAt(1));
}
[Fact]
public void Read_SingleValue_Success()
{
var obj = JsonSerializer.Deserialize<TestObject>(singleValueJson);
Assert.Equal("1", obj.StringProp);
Assert.Single(obj.EnumerableStringProp);
Assert.Equal("Hello!", obj.EnumerableStringProp.ElementAt(0));
}
[Fact]
public void Read_NullAndEmptyJson_Success()
{
var obj = JsonSerializer.Deserialize<TestObject>(nullAndEmptyJson);
Assert.Null(obj.StringProp);
Assert.Empty(obj.EnumerableStringProp);
}
[Fact]
public void Read_Null_Success()
{
var obj = JsonSerializer.Deserialize<TestObject>(nullJson);
Assert.Null(obj.StringProp);
Assert.Null(obj.EnumerableStringProp);
}
[Theory]
[InlineData(objectJsonOne)]
[InlineData(objectJsonTwo)]
public void Read_Object_Throws(string json)
{
var exception = Assert.Throws<JsonException>(() => JsonSerializer.Deserialize<TestObject>(json));
}
[Fact]
public void Write_Success()
{
var json = JsonSerializer.Serialize(new TestObject
{
StringProp = "1",
EnumerableStringProp = new List<string>
{
"2",
"3",
},
});
var jsonElement = JsonDocument.Parse(json).RootElement;
var stringProp = AssertHelper.AssertJsonProperty(jsonElement, "StringProp", JsonValueKind.String);
Assert.Equal("1", stringProp.GetString());
var list = AssertHelper.AssertJsonProperty(jsonElement, "EnumerableStringProp", JsonValueKind.Array);
Assert.Equal(2, list.GetArrayLength());
var firstElement = list[0];
Assert.Equal(JsonValueKind.String, firstElement.ValueKind);
Assert.Equal("2", firstElement.GetString());
var secondElement = list[1];
Assert.Equal(JsonValueKind.String, secondElement.ValueKind);
Assert.Equal("3", secondElement.GetString());
}
[Fact]
public void Write_Null()
{
// When the values are null the converters aren't actually ran and it automatically serializes null
var json = JsonSerializer.Serialize(new TestObject
{
StringProp = null,
EnumerableStringProp = null,
});
var jsonElement = JsonDocument.Parse(json).RootElement;
AssertHelper.AssertJsonProperty(jsonElement, "StringProp", JsonValueKind.Null);
AssertHelper.AssertJsonProperty(jsonElement, "EnumerableStringProp", JsonValueKind.Null);
}
[Fact]
public void Write_Empty()
{
// When the values are null the converters aren't actually ran and it automatically serializes null
var json = JsonSerializer.Serialize(new TestObject
{
StringProp = "",
EnumerableStringProp = Enumerable.Empty<string>(),
});
var jsonElement = JsonDocument.Parse(json).RootElement;
var stringVal = AssertHelper.AssertJsonProperty(jsonElement, "StringProp", JsonValueKind.String).GetString();
Assert.Equal("", stringVal);
var array = AssertHelper.AssertJsonProperty(jsonElement, "EnumerableStringProp", JsonValueKind.Array);
Assert.Equal(0, array.GetArrayLength());
}
}
public class TestObject
{
[JsonConverter(typeof(PermissiveStringConverter))]
public string StringProp { get; set; }
[JsonConverter(typeof(PermissiveStringEnumerableConverter))]
public IEnumerable<string> EnumerableStringProp { get; set; }
}

View File

@ -10,83 +10,82 @@ using Microsoft.Extensions.DependencyInjection;
using NSubstitute;
using Xunit;
namespace Bit.Core.Test.Utilities
namespace Bit.Core.Test.Utilities;
public class SelfHostedAttributeTests
{
public class SelfHostedAttributeTests
[Fact]
public void NotSelfHosted_Throws_When_SelfHosted()
{
[Fact]
public void NotSelfHosted_Throws_When_SelfHosted()
// Arrange
var sha = new SelfHostedAttribute { NotSelfHostedOnly = true };
// Act & Assert
Assert.Throws<BadRequestException>(() => sha.OnActionExecuting(GetContext(selfHosted: true)));
}
[Fact]
public void NotSelfHosted_Success_When_NotSelfHosted()
{
// Arrange
var sha = new SelfHostedAttribute { NotSelfHostedOnly = true };
// Act
sha.OnActionExecuting(GetContext(selfHosted: false));
// Assert
// The Assert here is just NOT throwing an exception
}
[Fact]
public void SelfHosted_Success_When_SelfHosted()
{
// Arrange
var sha = new SelfHostedAttribute { SelfHostedOnly = true };
// Act
sha.OnActionExecuting(GetContext(selfHosted: true));
// Assert
// The Assert here is just NOT throwing an exception
}
[Fact]
public void SelfHosted_Throws_When_NotSelfHosted()
{
// Arrange
var sha = new SelfHostedAttribute { SelfHostedOnly = true };
// Act & Assert
Assert.Throws<BadRequestException>(() => sha.OnActionExecuting(GetContext(selfHosted: false)));
}
// This generates a ActionExecutingContext with the needed injected
// service with the given value.
private ActionExecutingContext GetContext(bool selfHosted)
{
IServiceCollection services = new ServiceCollection();
var globalSettings = new GlobalSettings
{
// Arrange
var sha = new SelfHostedAttribute { NotSelfHostedOnly = true };
SelfHosted = selfHosted
};
// Act & Assert
Assert.Throws<BadRequestException>(() => sha.OnActionExecuting(GetContext(selfHosted: true)));
}
services.AddSingleton(globalSettings);
[Fact]
public void NotSelfHosted_Success_When_NotSelfHosted()
{
// Arrange
var sha = new SelfHostedAttribute { NotSelfHostedOnly = true };
var httpContext = new DefaultHttpContext();
httpContext.RequestServices = services.BuildServiceProvider();
// Act
sha.OnActionExecuting(GetContext(selfHosted: false));
var context = Substitute.For<ActionExecutingContext>(
Substitute.For<ActionContext>(httpContext,
new RouteData(),
Substitute.For<ActionDescriptor>()),
new List<IFilterMetadata>(),
new Dictionary<string, object>(),
Substitute.For<Controller>());
// Assert
// The Assert here is just NOT throwing an exception
}
[Fact]
public void SelfHosted_Success_When_SelfHosted()
{
// Arrange
var sha = new SelfHostedAttribute { SelfHostedOnly = true };
// Act
sha.OnActionExecuting(GetContext(selfHosted: true));
// Assert
// The Assert here is just NOT throwing an exception
}
[Fact]
public void SelfHosted_Throws_When_NotSelfHosted()
{
// Arrange
var sha = new SelfHostedAttribute { SelfHostedOnly = true };
// Act & Assert
Assert.Throws<BadRequestException>(() => sha.OnActionExecuting(GetContext(selfHosted: false)));
}
// This generates a ActionExecutingContext with the needed injected
// service with the given value.
private ActionExecutingContext GetContext(bool selfHosted)
{
IServiceCollection services = new ServiceCollection();
var globalSettings = new GlobalSettings
{
SelfHosted = selfHosted
};
services.AddSingleton(globalSettings);
var httpContext = new DefaultHttpContext();
httpContext.RequestServices = services.BuildServiceProvider();
var context = Substitute.For<ActionExecutingContext>(
Substitute.For<ActionContext>(httpContext,
new RouteData(),
Substitute.For<ActionDescriptor>()),
new List<IFilterMetadata>(),
new Dictionary<string, object>(),
Substitute.For<Controller>());
return context;
}
return context;
}
}

View File

@ -1,59 +1,58 @@
using Bit.Core.Utilities;
using Xunit;
namespace Bit.Core.Test.Utilities
namespace Bit.Core.Test.Utilities;
public class StrictEmailAttributeTests
{
public class StrictEmailAttributeTests
[Theory]
[InlineData("hello@world.com")] // regular email address
[InlineData("hello@world.planet.com")] // subdomain
[InlineData("hello+1@world.com")] // alias
[InlineData("hello.there@world.com")] // period in local-part
[InlineData("hello@wörldé.com")] // unicode domain
[InlineData("hello@world.cömé")] // unicode top-level domain
public void IsValid_ReturnsTrueWhenValid(string email)
{
[Theory]
[InlineData("hello@world.com")] // regular email address
[InlineData("hello@world.planet.com")] // subdomain
[InlineData("hello+1@world.com")] // alias
[InlineData("hello.there@world.com")] // period in local-part
[InlineData("hello@wörldé.com")] // unicode domain
[InlineData("hello@world.cömé")] // unicode top-level domain
public void IsValid_ReturnsTrueWhenValid(string email)
{
var sut = new StrictEmailAddressAttribute();
var sut = new StrictEmailAddressAttribute();
var actual = sut.IsValid(email);
var actual = sut.IsValid(email);
Assert.True(actual);
}
Assert.True(actual);
}
[Theory]
[InlineData(null)] // null
[InlineData("hello@world.com\t")] // trailing tab char
[InlineData("\thello@world.com")] // leading tab char
[InlineData("hel\tlo@world.com")] // local-part tab char
[InlineData("hello@world.com\b")] // trailing backspace char
[InlineData("\" \"hello@world.com")] // leading spaces in quotes
[InlineData("hello@world.com\" \"")] // trailing spaces in quotes
[InlineData("hel\" \"lo@world.com")] // local-part spaces in quotes
[InlineData("hello there@world.com")] // unescaped unquoted spaces
[InlineData("Hello <hello@world.com>")] // friendly from
[InlineData("<hello@world.com>")] // wrapped angle brackets
[InlineData("hello(com)there@world.com")] // comment
[InlineData("hello@world.com.")] // trailing period
[InlineData(".hello@world.com")] // leading period
[InlineData("hello@world.com;")] // trailing semicolon
[InlineData(";hello@world.com")] // leading semicolon
[InlineData("hello@world.com; hello@world.com")] // semicolon separated list
[InlineData("hello@world.com, hello@world.com")] // comma separated list
[InlineData("hellothere@worldcom")] // dotless domain
[InlineData("hello.there@worldcom")] // dotless domain
[InlineData("hellothere@.worldcom")] // domain beginning with dot
[InlineData("hellothere@worldcom.")] // domain ending in dot
[InlineData("hellothere@world.com-")] // domain ending in hyphen
[InlineData("hellö@world.com")] // unicode at end of local-part
[InlineData("héllo@world.com")] // unicode in middle of local-part
public void IsValid_ReturnsFalseWhenInvalid(string email)
{
var sut = new StrictEmailAddressAttribute();
[Theory]
[InlineData(null)] // null
[InlineData("hello@world.com\t")] // trailing tab char
[InlineData("\thello@world.com")] // leading tab char
[InlineData("hel\tlo@world.com")] // local-part tab char
[InlineData("hello@world.com\b")] // trailing backspace char
[InlineData("\" \"hello@world.com")] // leading spaces in quotes
[InlineData("hello@world.com\" \"")] // trailing spaces in quotes
[InlineData("hel\" \"lo@world.com")] // local-part spaces in quotes
[InlineData("hello there@world.com")] // unescaped unquoted spaces
[InlineData("Hello <hello@world.com>")] // friendly from
[InlineData("<hello@world.com>")] // wrapped angle brackets
[InlineData("hello(com)there@world.com")] // comment
[InlineData("hello@world.com.")] // trailing period
[InlineData(".hello@world.com")] // leading period
[InlineData("hello@world.com;")] // trailing semicolon
[InlineData(";hello@world.com")] // leading semicolon
[InlineData("hello@world.com; hello@world.com")] // semicolon separated list
[InlineData("hello@world.com, hello@world.com")] // comma separated list
[InlineData("hellothere@worldcom")] // dotless domain
[InlineData("hello.there@worldcom")] // dotless domain
[InlineData("hellothere@.worldcom")] // domain beginning with dot
[InlineData("hellothere@worldcom.")] // domain ending in dot
[InlineData("hellothere@world.com-")] // domain ending in hyphen
[InlineData("hellö@world.com")] // unicode at end of local-part
[InlineData("héllo@world.com")] // unicode in middle of local-part
public void IsValid_ReturnsFalseWhenInvalid(string email)
{
var sut = new StrictEmailAddressAttribute();
var actual = sut.IsValid(email);
var actual = sut.IsValid(email);
Assert.False(actual);
}
Assert.False(actual);
}
}

View File

@ -1,54 +1,53 @@
using Bit.Core.Utilities;
using Xunit;
namespace Bit.Core.Test.Utilities
namespace Bit.Core.Test.Utilities;
public class StrictEmailAddressListAttributeTests
{
public class StrictEmailAddressListAttributeTests
public static List<object[]> EmailList => new()
{
public static List<object[]> EmailList => new()
{
new object[] { new List<string> { "test@domain.com", "test@sub.domain.com", "hello@world.planet.com" }, true },
new object[] { new List<string> { "/hello@world.com", "hello@##world.pla net.com", "''thello@world.com" }, false },
new object[] { new List<string> { "/hello.com", "test@domain.com", "''thello@world.com" }, false },
new object[] { new List<string> { "héllö@world.com", "hello@world.planet.com", "hello@world.planet.com" }, false },
new object[] { new List<string> { }, false },
new object[] { new List<string>
{
"test1@domain.com", "test2@domain.com", "test3@domain.com", "test4@domain.com", "test5@domain.com",
"test6@domain.com", "test7@domain.com", "test8@domain.com", "test9@domain.com", "test10@domain.com",
"test11@domain.com", "test12@domain.com", "test13@domain.com", "test14@domain.com", "test15@domain.com",
"test16@domain.com", "test17@domain.com", "test18@domain.com", "test19@domain.com", "test20@domain.com",
"test21@domain.com", "test22@domain.com", "test23@domain.com", "test24@domain.com", "test25@domain.com",
}, false },
new object[] { new List<string>
{
"test1domaincomtest2domaincomtest3domaincomtest4domaincomtest5domaincomtest6domaincomtest7domaincomtest8domaincomtest9domaincomtest10domaincomtest1domaincomtest2domaincomtest3domaincomtest4domaincomtest5domaincomtest6domaincomtest7domaincomtest8domaincomtest9domaincomtest10domaincom@test.com",
"test@domain.com"
}, false } // > 256 character email
new object[] { new List<string> { "test@domain.com", "test@sub.domain.com", "hello@world.planet.com" }, true },
new object[] { new List<string> { "/hello@world.com", "hello@##world.pla net.com", "''thello@world.com" }, false },
new object[] { new List<string> { "/hello.com", "test@domain.com", "''thello@world.com" }, false },
new object[] { new List<string> { "llö@world.com", "hello@world.planet.com", "hello@world.planet.com" }, false },
new object[] { new List<string> { }, false },
new object[] { new List<string>
{
"test1@domain.com", "test2@domain.com", "test3@domain.com", "test4@domain.com", "test5@domain.com",
"test6@domain.com", "test7@domain.com", "test8@domain.com", "test9@domain.com", "test10@domain.com",
"test11@domain.com", "test12@domain.com", "test13@domain.com", "test14@domain.com", "test15@domain.com",
"test16@domain.com", "test17@domain.com", "test18@domain.com", "test19@domain.com", "test20@domain.com",
"test21@domain.com", "test22@domain.com", "test23@domain.com", "test24@domain.com", "test25@domain.com",
}, false },
new object[] { new List<string>
{
"test1domaincomtest2domaincomtest3domaincomtest4domaincomtest5domaincomtest6domaincomtest7domaincomtest8domaincomtest9domaincomtest10domaincomtest1domaincomtest2domaincomtest3domaincomtest4domaincomtest5domaincomtest6domaincomtest7domaincomtest8domaincomtest9domaincomtest10domaincom@test.com",
"test@domain.com"
}, false } // > 256 character email
};
};
[Theory]
[MemberData(nameof(EmailList))]
public void IsListValid_ReturnsTrue_WhenValid(List<string> emailList, bool valid)
{
var sut = new StrictEmailAddressListAttribute();
[Theory]
[MemberData(nameof(EmailList))]
public void IsListValid_ReturnsTrue_WhenValid(List<string> emailList, bool valid)
{
var sut = new StrictEmailAddressListAttribute();
var actual = sut.IsValid(emailList);
var actual = sut.IsValid(emailList);
Assert.Equal(actual, valid);
}
Assert.Equal(actual, valid);
}
[Theory]
[InlineData("single@email.com", false)]
[InlineData(null, false)]
public void IsValid_ReturnsTrue_WhenValid(string email, bool valid)
{
var sut = new StrictEmailAddressListAttribute();
[Theory]
[InlineData("single@email.com", false)]
[InlineData(null, false)]
public void IsValid_ReturnsTrue_WhenValid(string email, bool valid)
{
var sut = new StrictEmailAddressListAttribute();
var actual = sut.IsValid(email);
var actual = sut.IsValid(email);
Assert.Equal(actual, valid);
}
Assert.Equal(actual, valid);
}
}