using Bit.Core.Auth.Enums; using Bit.Core.Auth.Models; using Bit.Core.Auth.Services; using Bit.Core.Context; using Bit.Core.Entities; using Bit.Core.Enums; using Bit.Core.Services; using Bit.Core.Utilities; using Bit.Test.Common.AutoFixture; using Bit.Test.Common.AutoFixture.Attributes; using Core.Auth.Enums; using Microsoft.AspNetCore.Identity; using NSubstitute; using Xunit; namespace Bit.Core.Test.Auth.Services; [SutProviderCustomize] public class TwoFactorEmailServiceTests { [Theory, BitAutoData] public async Task SendTwoFactorEmailAsync_Success(SutProvider sutProvider, User user) { var email = user.Email.ToLowerInvariant(); var token = "thisisatokentocompare"; var IpAddress = "1.1.1.1"; var deviceType = "Android"; var userTwoFactorTokenProvider = Substitute.For>(); userTwoFactorTokenProvider .CanGenerateTwoFactorTokenAsync(Arg.Any>(), user) .Returns(Task.FromResult(true)); userTwoFactorTokenProvider .GenerateAsync("TwoFactor", Arg.Any>(), user) .Returns(Task.FromResult(token)); var context = sutProvider.GetDependency(); context.DeviceType = DeviceType.Android; context.IpAddress = IpAddress; var userManager = sutProvider.GetDependency>(); userManager.RegisterTokenProvider(CoreHelpers.CustomProviderName(TwoFactorProviderType.Email), userTwoFactorTokenProvider); user.SetTwoFactorProviders(new Dictionary { [TwoFactorProviderType.Email] = new TwoFactorProvider { MetaData = new Dictionary { ["Email"] = email }, Enabled = true } }); await sutProvider.Sut.SendTwoFactorEmailAsync(user); await sutProvider.GetDependency() .Received(1) .SendTwoFactorEmailAsync(email, user.Email, token, IpAddress, deviceType, TwoFactorEmailPurpose.Login); } [Theory, BitAutoData] public async Task SendTwoFactorEmailAsync_ExceptionBecauseNoProviderOnUser(SutProvider sutProvider, User user) { user.TwoFactorProviders = null; await Assert.ThrowsAsync("No email.", () => sutProvider.Sut.SendTwoFactorEmailAsync(user)); } [Theory, BitAutoData] public async Task SendTwoFactorEmailAsync_ExceptionBecauseNoProviderMetadataOnUser(SutProvider sutProvider, User user) { user.SetTwoFactorProviders(new Dictionary { [TwoFactorProviderType.Email] = new TwoFactorProvider { MetaData = null, Enabled = true } }); await Assert.ThrowsAsync("No email.", () => sutProvider.Sut.SendTwoFactorEmailAsync(user)); } [Theory, BitAutoData] public async Task SendTwoFactorEmailAsync_ExceptionBecauseNoProviderEmailMetadataOnUser(SutProvider sutProvider, User user) { user.SetTwoFactorProviders(new Dictionary { [TwoFactorProviderType.Email] = new TwoFactorProvider { MetaData = new Dictionary { ["qweqwe"] = user.Email.ToLowerInvariant() }, Enabled = true } }); await Assert.ThrowsAsync("No email.", () => sutProvider.Sut.SendTwoFactorEmailAsync(user)); } [Theory, BitAutoData] public async Task SendNewDeviceVerificationEmailAsync_ExceptionBecauseUserNull(SutProvider sutProvider) { await Assert.ThrowsAsync(() => sutProvider.Sut.SendNewDeviceVerificationEmailAsync(null)); } [Theory] [BitAutoData(DeviceType.UnknownBrowser, "Unknown Browser")] [BitAutoData(DeviceType.Android, "Android")] public async Task SendNewDeviceVerificationEmailAsync_DeviceMatches(DeviceType deviceType, string deviceTypeName, User user) { var sutProvider = new SutProvider(); var context = sutProvider.GetDependency(); context.DeviceType = deviceType; context.IpAddress = "1.1.1.1"; await sutProvider.Sut.SendNewDeviceVerificationEmailAsync(user); await sutProvider.GetDependency() .Received(1) .SendTwoFactorEmailAsync(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any(), deviceTypeName, Arg.Any()); } [Theory, BitAutoData] public async Task SendNewDeviceVerificationEmailAsync_NullDeviceTypeShouldSendUnkownBrowserType(User user) { var sutProvider = new SutProvider(); var context = sutProvider.GetDependency(); context.DeviceType = null; context.IpAddress = "1.1.1.1"; await sutProvider.Sut.SendNewDeviceVerificationEmailAsync(user); await sutProvider.GetDependency() .Received(1) .SendTwoFactorEmailAsync(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any(), "Unknown Browser", Arg.Any()); } // [Theory, BitAutoData] // public async Task ResendNewDeviceVerificationEmail_UserNull_SendTwoFactorEmailAsyncNotCalled( // SutProvider sutProvider, string email, string secret) // { // sutProvider.GetDependency() // .GetByEmailAsync(email) // .Returns(null as User); // await sutProvider.Sut.ResendNewDeviceVerificationEmail(email, secret); // await sutProvider.GetDependency() // .DidNotReceive() // .SendTwoFactorEmailAsync(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()); // } // [Theory, BitAutoData] // public async Task ResendNewDeviceVerificationEmail_SecretNotValid_SendTwoFactorEmailAsyncNotCalled( // SutProvider sutProvider, string email, string secret) // { // sutProvider.GetDependency() // .GetByEmailAsync(email) // .Returns(null as User); // await sutProvider.Sut.ResendNewDeviceVerificationEmail(email, secret); // await sutProvider.GetDependency() // .DidNotReceive() // .SendTwoFactorEmailAsync(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()); // } // [Theory, BitAutoData] // public async Task ResendNewDeviceVerificationEmail_SendsToken_Success(User user) // { // // Arrange // var testPassword = "test_password"; // SetupUserAndDevice(user, true); // var sutProvider = new SutProvider(); // // Setup the fake password verification // sutProvider // .GetDependency>() // .GetPasswordHashAsync(user, Arg.Any()) // .Returns((ci) => // { // return Task.FromResult("hashed_test_password"); // }); // sutProvider.GetDependency>() // .VerifyHashedPassword(user, "hashed_test_password", testPassword) // .Returns((ci) => // { // return PasswordVerificationResult.Success; // }); // sutProvider.GetDependency() // .GetByEmailAsync(user.Email) // .Returns(user); // var context = sutProvider.GetDependency(); // context.DeviceType = DeviceType.Android; // context.IpAddress = "1.1.1.1"; // await sutProvider.Sut.ResendNewDeviceVerificationEmail(user.Email, testPassword); // await sutProvider.GetDependency() // .Received(1) // .SendTwoFactorEmailAsync(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()); // } }