1
0
mirror of https://github.com/bitwarden/server.git synced 2024-11-21 12:05:42 +01:00

[PS-589] Fix emergency contact takeover device verification and endpoints for its settings (#2016)

* Added UnknownDeviceVerificationEnabled on User that is turned off when emergency contact takes over the account. Also added endpoints to get and update 2fa device verification settings. And Updated migrations & tests

* Applied dotnet format

* Fixed method rename call on TwoFactorController

* PS-589 Format fixes

* PS-589 changed UnknownDeviceVerificationEnabled to be non-nullable
This commit is contained in:
Federico Maccaroni 2022-06-06 14:52:50 -03:00 committed by GitHub
parent 16c6b23a27
commit b070e9a387
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 3781 additions and 13 deletions

View File

@ -380,6 +380,42 @@ namespace Bit.Api.Controllers
}
}
[HttpGet("get-device-verification-settings")]
public async Task<DeviceVerificationResponseModel> GetDeviceVerificationSettings()
{
var user = await _userService.GetUserByPrincipalAsync(User);
if (user == null)
{
throw new UnauthorizedAccessException();
}
if (User.Claims.HasSsoIdP())
{
return new DeviceVerificationResponseModel(false, false);
}
return new DeviceVerificationResponseModel(_userService.CanEditDeviceVerificationSettings(user), user.UnknownDeviceVerificationEnabled);
}
[HttpPut("device-verification-settings")]
public async Task<DeviceVerificationResponseModel> PutDeviceVerificationSettings([FromBody] DeviceVerificationRequestModel model)
{
var user = await _userService.GetUserByPrincipalAsync(User);
if (user == null)
{
throw new UnauthorizedAccessException();
}
if (!_userService.CanEditDeviceVerificationSettings(user)
|| User.Claims.HasSsoIdP())
{
throw new InvalidOperationException("Can't update device verification settings");
}
model.ToUser(user);
await _userService.SaveUserAsync(user);
return new DeviceVerificationResponseModel(true, user.UnknownDeviceVerificationEnabled);
}
private async Task<User> CheckAsync(SecretVerificationRequestModel model, bool premium)
{
var user = await _userService.GetUserByPrincipalAsync(User);

View File

@ -0,0 +1,18 @@
using System;
using System.ComponentModel.DataAnnotations;
using Bit.Core.Entities;
namespace Bit.Api.Models.Request
{
public class DeviceVerificationRequestModel
{
[Required]
public bool UnknownDeviceVerificationEnabled { get; set; }
public User ToUser(User user)
{
user.UnknownDeviceVerificationEnabled = UnknownDeviceVerificationEnabled;
return user;
}
}
}

View File

@ -0,0 +1,18 @@
using System;
using Bit.Core.Models.Api;
namespace Bit.Api.Models.Response
{
public class DeviceVerificationResponseModel : ResponseModel
{
public DeviceVerificationResponseModel(bool isDeviceVerificationSectionEnabled, bool unknownDeviceVerificationEnabled)
: base("deviceVerificationSettings")
{
IsDeviceVerificationSectionEnabled = isDeviceVerificationSectionEnabled;
UnknownDeviceVerificationEnabled = unknownDeviceVerificationEnabled;
}
public bool IsDeviceVerificationSectionEnabled { get; }
public bool UnknownDeviceVerificationEnabled { get; }
}
}

View File

@ -62,6 +62,7 @@ namespace Bit.Core.Entities
public bool UsesKeyConnector { get; set; }
public int FailedLoginCount { get; set; }
public DateTime? LastFailedLoginDate { get; set; }
public bool UnknownDeviceVerificationEnabled { get; set; }
public void SetNewId()
{

View File

@ -79,5 +79,6 @@ namespace Bit.Core.Services
Task<bool> VerifyOTPAsync(User user, string token);
Task<bool> VerifySecretAsync(User user, string secret);
Task<bool> Needs2FABecauseNewDeviceAsync(User user, string deviceIdentifier, string grantType);
bool CanEditDeviceVerificationSettings(User user);
}
}

View File

@ -327,6 +327,7 @@ namespace Bit.Core.Services
grantor.Key = key;
// Disable TwoFactor providers since they will otherwise block logins
grantor.SetTwoFactorProviders(new Dictionary<TwoFactorProviderType, TwoFactorProvider>());
grantor.UnknownDeviceVerificationEnabled = false;
await _userRepository.ReplaceAsync(grantor);
// Remove grantor from all organizations unless Owner

View File

@ -1417,12 +1417,20 @@ namespace Bit.Core.Services
public async Task<bool> Needs2FABecauseNewDeviceAsync(User user, string deviceIdentifier, string grantType)
{
return _globalSettings.TwoFactorAuth.EmailOnNewDeviceLogin
&& user.EmailVerified
return CanEditDeviceVerificationSettings(user)
&& user.UnknownDeviceVerificationEnabled
&& grantType != "authorization_code"
&& await IsNewDeviceAndNotTheFirstOneAsync(user, deviceIdentifier);
}
public bool CanEditDeviceVerificationSettings(User user)
{
return _globalSettings.TwoFactorAuth.EmailOnNewDeviceLogin
&& user.EmailVerified
&& !user.UsesKeyConnector
&& !(user.GetTwoFactorProviders()?.Any() ?? false);
}
private async Task<bool> IsNewDeviceAndNotTheFirstOneAsync(User user, string deviceIdentifier)
{
if (user == null)

View File

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
namespace Bit.Core.Utilities
{
public static class ClaimsExtensions
{
public static bool HasSsoIdP(this IEnumerable<Claim> claims)
{
return claims.Any(c => c.Type == "idp" && c.Value == "sso");
}
}
}

View File

@ -33,7 +33,8 @@
@ForcePasswordReset BIT = 0,
@UsesKeyConnector BIT = 0,
@FailedLoginCount INT = 0,
@LastFailedLoginDate DATETIME2(7)
@LastFailedLoginDate DATETIME2(7),
@UnknownDeviceVerificationEnabled BIT NULL
AS
BEGIN
SET NOCOUNT ON
@ -74,7 +75,8 @@ BEGIN
[ForcePasswordReset],
[UsesKeyConnector],
[FailedLoginCount],
[LastFailedLoginDate]
[LastFailedLoginDate],
[UnknownDeviceVerificationEnabled]
)
VALUES
(
@ -112,6 +114,7 @@ BEGIN
@ForcePasswordReset,
@UsesKeyConnector,
@FailedLoginCount,
@LastFailedLoginDate
@LastFailedLoginDate,
@UnknownDeviceVerificationEnabled
)
END

View File

@ -33,7 +33,8 @@
@ForcePasswordReset BIT = 0,
@UsesKeyConnector BIT = 0,
@FailedLoginCount INT,
@LastFailedLoginDate DATETIME2(7)
@LastFailedLoginDate DATETIME2(7),
@UnknownDeviceVerificationEnabled BIT NULL
AS
BEGIN
SET NOCOUNT ON
@ -74,7 +75,8 @@ BEGIN
[ForcePasswordReset] = @ForcePasswordReset,
[UsesKeyConnector] = @UsesKeyConnector,
[FailedLoginCount] = @FailedLoginCount,
[LastFailedLoginDate] = @LastFailedLoginDate
[LastFailedLoginDate] = @LastFailedLoginDate,
[UnknownDeviceVerificationEnabled] = @UnknownDeviceVerificationEnabled
WHERE
[Id] = @Id
END

View File

@ -34,6 +34,7 @@
[UsesKeyConnector] BIT NOT NULL,
[FailedLoginCount] INT NOT NULL,
[LastFailedLoginDate] DATETIME2 (7) NULL,
[UnknownDeviceVerificationEnabled] BIT NULL,
CONSTRAINT [PK_User] PRIMARY KEY CLUSTERED ([Id] ASC)
);

View File

@ -1,7 +1,10 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Exceptions;
using Bit.Core.Models;
using Bit.Core.Repositories;
using Bit.Core.Services;
using Bit.Core.Test.AutoFixture;
@ -137,5 +140,37 @@ namespace Bit.Core.Test.Services
Assert.Contains("You cannot takeover an account that is using Key Connector", exception.Message);
}
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
public async Task PasswordAsync_Disables_2FA_Providers_And_Unknown_Device_Verification_On_The_Grantor(
SutProvider<EmergencyAccessService> sutProvider, User requestingUser, User grantor)
{
grantor.UsesKeyConnector = true;
grantor.UnknownDeviceVerificationEnabled = true;
grantor.SetTwoFactorProviders(new Dictionary<TwoFactorProviderType, TwoFactorProvider>
{
[TwoFactorProviderType.Email] = new TwoFactorProvider
{
MetaData = new Dictionary<string, object> { ["Email"] = "asdfasf" },
Enabled = true
}
});
var emergencyAccess = new EmergencyAccess
{
GrantorId = grantor.Id,
GranteeId = requestingUser.Id,
Status = Enums.EmergencyAccessStatusType.RecoveryApproved,
Type = Enums.EmergencyAccessType.Takeover,
};
sutProvider.GetDependency<IEmergencyAccessRepository>().GetByIdAsync(Arg.Any<Guid>()).Returns(emergencyAccess);
sutProvider.GetDependency<IUserRepository>().GetByIdAsync(grantor.Id).Returns(grantor);
await sutProvider.Sut.PasswordAsync(Guid.NewGuid(), requestingUser, "blablahash", "blablakey");
Assert.False(grantor.UnknownDeviceVerificationEnabled);
Assert.Empty(grantor.GetTwoFactorProviders());
await sutProvider.GetDependency<IUserRepository>().Received().ReplaceAsync(grantor);
}
}
}

View File

@ -161,8 +161,9 @@ namespace Bit.Core.Test.Services
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
public async Task Needs2FABecauseNewDeviceAsync_ReturnsTrue(SutProvider<UserService> sutProvider, User user)
{
user.Id = Guid.NewGuid();
user.EmailVerified = true;
user.TwoFactorProviders = null;
user.UnknownDeviceVerificationEnabled = true;
const string deviceIdToCheck = "7b01b586-b210-499f-8d52-0c3fdaa646fc";
const string deviceIdInRepo = "ea29126c-91b7-4cc4-8ce6-00105b37f64a";
@ -182,8 +183,8 @@ namespace Bit.Core.Test.Services
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
public async Task Needs2FABecauseNewDeviceAsync_ReturnsFalse_When_GranType_Is_AuthorizationCode(SutProvider<UserService> sutProvider, User user)
{
user.Id = Guid.NewGuid();
user.EmailVerified = true;
user.TwoFactorProviders = null;
const string deviceIdToCheck = "7b01b586-b210-499f-8d52-0c3fdaa646fc";
const string deviceIdInRepo = "ea29126c-91b7-4cc4-8ce6-00105b37f64a";
@ -200,8 +201,8 @@ namespace Bit.Core.Test.Services
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
public async Task Needs2FABecauseNewDeviceAsync_ReturnsFalse_When_Email_Is_Not_Verified(SutProvider<UserService> sutProvider, User user)
{
user.Id = Guid.NewGuid();
user.EmailVerified = false;
user.TwoFactorProviders = null;
const string deviceIdToCheck = "7b01b586-b210-499f-8d52-0c3fdaa646fc";
const string deviceIdInRepo = "ea29126c-91b7-4cc4-8ce6-00105b37f64a";
@ -218,8 +219,8 @@ namespace Bit.Core.Test.Services
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
public async Task Needs2FABecauseNewDeviceAsync_ReturnsFalse_When_Is_The_First_Device(SutProvider<UserService> sutProvider, User user)
{
user.Id = Guid.NewGuid();
user.EmailVerified = true;
user.TwoFactorProviders = null;
const string deviceIdToCheck = "7b01b586-b210-499f-8d52-0c3fdaa646fc";
sutProvider.GetDependency<IDeviceRepository>()
@ -232,8 +233,8 @@ namespace Bit.Core.Test.Services
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
public async Task Needs2FABecauseNewDeviceAsync_ReturnsFalse_When_DeviceId_Is_Already_In_Repo(SutProvider<UserService> sutProvider, User user)
{
user.Id = Guid.NewGuid();
user.EmailVerified = true;
user.TwoFactorProviders = null;
const string deviceIdToCheck = "7b01b586-b210-499f-8d52-0c3fdaa646fc";
sutProvider.GetDependency<IDeviceRepository>()
@ -249,8 +250,8 @@ namespace Bit.Core.Test.Services
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
public async Task Needs2FABecauseNewDeviceAsync_ReturnsFalse_When_GlobalSettings_2FA_EmailOnNewDeviceLogin_Is_Disabled(SutProvider<UserService> sutProvider, User user)
{
user.Id = Guid.NewGuid();
user.EmailVerified = true;
user.TwoFactorProviders = null;
const string deviceIdToCheck = "7b01b586-b210-499f-8d52-0c3fdaa646fc";
const string deviceIdInRepo = "ea29126c-91b7-4cc4-8ce6-00105b37f64a";
@ -265,5 +266,89 @@ namespace Bit.Core.Test.Services
Assert.False(await sutProvider.Sut.Needs2FABecauseNewDeviceAsync(user, deviceIdToCheck, "password"));
}
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
public async Task Needs2FABecauseNewDeviceAsync_ReturnsFalse_When_UnknownDeviceVerification_Is_Disabled(SutProvider<UserService> sutProvider, User user)
{
user.EmailVerified = true;
user.TwoFactorProviders = null;
user.UnknownDeviceVerificationEnabled = false;
const string deviceIdToCheck = "7b01b586-b210-499f-8d52-0c3fdaa646fc";
const string deviceIdInRepo = "ea29126c-91b7-4cc4-8ce6-00105b37f64a";
sutProvider.GetDependency<IDeviceRepository>()
.GetManyByUserIdAsync(user.Id)
.Returns(Task.FromResult<ICollection<Device>>(new List<Device>
{
new Device { Identifier = deviceIdInRepo }
}));
sutProvider.GetDependency<Settings.IGlobalSettings>().TwoFactorAuth.EmailOnNewDeviceLogin.Returns(true);
Assert.False(await sutProvider.Sut.Needs2FABecauseNewDeviceAsync(user, deviceIdToCheck, "password"));
}
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
public void CanEditDeviceVerificationSettings_ReturnsTrue(SutProvider<UserService> sutProvider, User user)
{
user.EmailVerified = true;
user.TwoFactorProviders = null;
sutProvider.GetDependency<Settings.IGlobalSettings>().TwoFactorAuth.EmailOnNewDeviceLogin.Returns(true);
Assert.True(sutProvider.Sut.CanEditDeviceVerificationSettings(user));
}
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
public void CanEditDeviceVerificationSettings_ReturnsFalse_When_GlobalSettings_2FA_EmailOnNewDeviceLogin_Is_Disabled(SutProvider<UserService> sutProvider, User user)
{
user.EmailVerified = true;
user.TwoFactorProviders = null;
sutProvider.GetDependency<Settings.IGlobalSettings>().TwoFactorAuth.EmailOnNewDeviceLogin.Returns(false);
Assert.False(sutProvider.Sut.CanEditDeviceVerificationSettings(user));
}
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
public void CanEditDeviceVerificationSettings_ReturnsFalse_When_Email_Is_Not_Verified(SutProvider<UserService> sutProvider, User user)
{
user.EmailVerified = false;
user.TwoFactorProviders = null;
sutProvider.GetDependency<Settings.IGlobalSettings>().TwoFactorAuth.EmailOnNewDeviceLogin.Returns(true);
Assert.False(sutProvider.Sut.CanEditDeviceVerificationSettings(user));
}
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
public void CanEditDeviceVerificationSettings_ReturnsFalse_When_User_Uses_Key_Connector(SutProvider<UserService> sutProvider, User user)
{
user.EmailVerified = true;
user.TwoFactorProviders = null;
user.UsesKeyConnector = true;
sutProvider.GetDependency<Settings.IGlobalSettings>().TwoFactorAuth.EmailOnNewDeviceLogin.Returns(true);
Assert.False(sutProvider.Sut.CanEditDeviceVerificationSettings(user));
}
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
public void CanEditDeviceVerificationSettings_ReturnsFalse_When_User_Has_A_2FA_Already_Set_Up(SutProvider<UserService> sutProvider, User user)
{
user.EmailVerified = true;
user.SetTwoFactorProviders(new Dictionary<TwoFactorProviderType, TwoFactorProvider>
{
[TwoFactorProviderType.Email] = new TwoFactorProvider
{
MetaData = new Dictionary<string, object> { ["Email"] = "asdfasf" },
Enabled = true
}
});
sutProvider.GetDependency<Settings.IGlobalSettings>().TwoFactorAuth.EmailOnNewDeviceLogin.Returns(true);
Assert.False(sutProvider.Sut.CanEditDeviceVerificationSettings(user));
}
}
}

View File

@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using System.Security.Claims;
using Bit.Core.Utilities;
using Xunit;
namespace Bit.Core.Test.Utilities
{
public class ClaimsExtensionsTests
{
[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());
}
[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_Are_Empty()
{
var claims = new List<Claim>();
Assert.False(claims.HasSsoIdP());
}
}
}

View File

@ -0,0 +1,245 @@
-- Table: User (UnknownDeviceVerificationEnabled)
IF COL_LENGTH('[dbo].[User]', 'UnknownDeviceVerificationEnabled') IS NULL
BEGIN
ALTER TABLE
[dbo].[User]
ADD
[UnknownDeviceVerificationEnabled] BIT NOT NULL CONSTRAINT D_User_UnknownDeviceVerificationEnabled DEFAULT 1
END
GO
-- View: User
IF EXISTS(SELECT * FROM sys.views WHERE [Name] = 'UserView')
BEGIN
DROP VIEW [dbo].[UserView]
END
GO
CREATE VIEW [dbo].[UserView]
AS
SELECT
*
FROM
[dbo].[User]
GO
-- Stored Procedure: User_Create
IF OBJECT_ID('[dbo].[User_Create]') IS NOT NULL
BEGIN
DROP PROCEDURE [dbo].[User_Create]
END
GO
CREATE PROCEDURE [dbo].[User_Create]
@Id UNIQUEIDENTIFIER OUTPUT,
@Name NVARCHAR(50),
@Email NVARCHAR(256),
@EmailVerified BIT,
@MasterPassword NVARCHAR(300),
@MasterPasswordHint NVARCHAR(50),
@Culture NVARCHAR(10),
@SecurityStamp NVARCHAR(50),
@TwoFactorProviders NVARCHAR(MAX),
@TwoFactorRecoveryCode NVARCHAR(32),
@EquivalentDomains NVARCHAR(MAX),
@ExcludedGlobalEquivalentDomains NVARCHAR(MAX),
@AccountRevisionDate DATETIME2(7),
@Key NVARCHAR(MAX),
@PublicKey NVARCHAR(MAX),
@PrivateKey NVARCHAR(MAX),
@Premium BIT,
@PremiumExpirationDate DATETIME2(7),
@RenewalReminderDate DATETIME2(7),
@Storage BIGINT,
@MaxStorageGb SMALLINT,
@Gateway TINYINT,
@GatewayCustomerId VARCHAR(50),
@GatewaySubscriptionId VARCHAR(50),
@ReferenceData VARCHAR(MAX),
@LicenseKey VARCHAR(100),
@Kdf TINYINT,
@KdfIterations INT,
@CreationDate DATETIME2(7),
@RevisionDate DATETIME2(7),
@ApiKey VARCHAR(30),
@ForcePasswordReset BIT = 0,
@UsesKeyConnector BIT = 0,
@FailedLoginCount INT = 0,
@LastFailedLoginDate DATETIME2(7),
@UnknownDeviceVerificationEnabled BIT = 1
AS
BEGIN
SET NOCOUNT ON
INSERT INTO [dbo].[User]
(
[Id],
[Name],
[Email],
[EmailVerified],
[MasterPassword],
[MasterPasswordHint],
[Culture],
[SecurityStamp],
[TwoFactorProviders],
[TwoFactorRecoveryCode],
[EquivalentDomains],
[ExcludedGlobalEquivalentDomains],
[AccountRevisionDate],
[Key],
[PublicKey],
[PrivateKey],
[Premium],
[PremiumExpirationDate],
[RenewalReminderDate],
[Storage],
[MaxStorageGb],
[Gateway],
[GatewayCustomerId],
[GatewaySubscriptionId],
[ReferenceData],
[LicenseKey],
[Kdf],
[KdfIterations],
[CreationDate],
[RevisionDate],
[ApiKey],
[ForcePasswordReset],
[UsesKeyConnector],
[FailedLoginCount],
[LastFailedLoginDate],
[UnknownDeviceVerificationEnabled]
)
VALUES
(
@Id,
@Name,
@Email,
@EmailVerified,
@MasterPassword,
@MasterPasswordHint,
@Culture,
@SecurityStamp,
@TwoFactorProviders,
@TwoFactorRecoveryCode,
@EquivalentDomains,
@ExcludedGlobalEquivalentDomains,
@AccountRevisionDate,
@Key,
@PublicKey,
@PrivateKey,
@Premium,
@PremiumExpirationDate,
@RenewalReminderDate,
@Storage,
@MaxStorageGb,
@Gateway,
@GatewayCustomerId,
@GatewaySubscriptionId,
@ReferenceData,
@LicenseKey,
@Kdf,
@KdfIterations,
@CreationDate,
@RevisionDate,
@ApiKey,
@ForcePasswordReset,
@UsesKeyConnector,
@FailedLoginCount,
@LastFailedLoginDate,
@UnknownDeviceVerificationEnabled
)
END
GO
-- Stored Procedure: User_Update
IF OBJECT_ID('[dbo].[User_Update]') IS NOT NULL
BEGIN
DROP PROCEDURE [dbo].[User_Update]
END
GO
CREATE PROCEDURE [dbo].[User_Update]
@Id UNIQUEIDENTIFIER,
@Name NVARCHAR(50),
@Email NVARCHAR(256),
@EmailVerified BIT,
@MasterPassword NVARCHAR(300),
@MasterPasswordHint NVARCHAR(50),
@Culture NVARCHAR(10),
@SecurityStamp NVARCHAR(50),
@TwoFactorProviders NVARCHAR(MAX),
@TwoFactorRecoveryCode NVARCHAR(32),
@EquivalentDomains NVARCHAR(MAX),
@ExcludedGlobalEquivalentDomains NVARCHAR(MAX),
@AccountRevisionDate DATETIME2(7),
@Key NVARCHAR(MAX),
@PublicKey NVARCHAR(MAX),
@PrivateKey NVARCHAR(MAX),
@Premium BIT,
@PremiumExpirationDate DATETIME2(7),
@RenewalReminderDate DATETIME2(7),
@Storage BIGINT,
@MaxStorageGb SMALLINT,
@Gateway TINYINT,
@GatewayCustomerId VARCHAR(50),
@GatewaySubscriptionId VARCHAR(50),
@ReferenceData VARCHAR(MAX),
@LicenseKey VARCHAR(100),
@Kdf TINYINT,
@KdfIterations INT,
@CreationDate DATETIME2(7),
@RevisionDate DATETIME2(7),
@ApiKey VARCHAR(30),
@ForcePasswordReset BIT = 0,
@UsesKeyConnector BIT = 0,
@FailedLoginCount INT,
@LastFailedLoginDate DATETIME2(7),
@UnknownDeviceVerificationEnabled BIT NULL
AS
BEGIN
SET NOCOUNT ON
UPDATE
[dbo].[User]
SET
[Name] = @Name,
[Email] = @Email,
[EmailVerified] = @EmailVerified,
[MasterPassword] = @MasterPassword,
[MasterPasswordHint] = @MasterPasswordHint,
[Culture] = @Culture,
[SecurityStamp] = @SecurityStamp,
[TwoFactorProviders] = @TwoFactorProviders,
[TwoFactorRecoveryCode] = @TwoFactorRecoveryCode,
[EquivalentDomains] = @EquivalentDomains,
[ExcludedGlobalEquivalentDomains] = @ExcludedGlobalEquivalentDomains,
[AccountRevisionDate] = @AccountRevisionDate,
[Key] = @Key,
[PublicKey] = @PublicKey,
[PrivateKey] = @PrivateKey,
[Premium] = @Premium,
[PremiumExpirationDate] = @PremiumExpirationDate,
[RenewalReminderDate] = @RenewalReminderDate,
[Storage] = @Storage,
[MaxStorageGb] = @MaxStorageGb,
[Gateway] = @Gateway,
[GatewayCustomerId] = @GatewayCustomerId,
[GatewaySubscriptionId] = @GatewaySubscriptionId,
[ReferenceData] = @ReferenceData,
[LicenseKey] = @LicenseKey,
[Kdf] = @Kdf,
[KdfIterations] = @KdfIterations,
[CreationDate] = @CreationDate,
[RevisionDate] = @RevisionDate,
[ApiKey] = @ApiKey,
[ForcePasswordReset] = @ForcePasswordReset,
[UsesKeyConnector] = @UsesKeyConnector,
[FailedLoginCount] = @FailedLoginCount,
[LastFailedLoginDate] = @LastFailedLoginDate,
[UnknownDeviceVerificationEnabled] = @UnknownDeviceVerificationEnabled
WHERE
[Id] = @Id
END
GO

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,24 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace Bit.MySqlMigrations.Migrations
{
public partial class DeviceUnknownVerification : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "UnknownDeviceVerificationEnabled",
table: "User",
type: "tinyint(1)",
nullable: false,
defaultValue: true);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "UnknownDeviceVerificationEnabled",
table: "User");
}
}
}

View File

@ -1192,6 +1192,9 @@ namespace Bit.MySqlMigrations.Migrations
.HasMaxLength(32)
.HasColumnType("varchar(32)");
b.Property<bool>("UnknownDeviceVerificationEnabled")
.HasColumnType("tinyint(1)");
b.Property<bool>("UsesKeyConnector")
.HasColumnType("tinyint(1)");

View File

@ -0,0 +1,8 @@
START TRANSACTION;
ALTER TABLE `User` ADD `UnknownDeviceVerificationEnabled` tinyint(1) NOT NULL DEFAULT 1;
INSERT INTO `__EFMigrationsHistory` (`MigrationId`, `ProductVersion`)
VALUES ('20220524171600_DeviceUnknownVerification', '5.0.12');
COMMIT;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,24 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace Bit.PostgresMigrations.Migrations
{
public partial class DeviceUnknownVerification : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "UnknownDeviceVerificationEnabled",
table: "User",
type: "boolean",
nullable: false,
defaultValue: true);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "UnknownDeviceVerificationEnabled",
table: "User");
}
}
}

View File

@ -1200,6 +1200,9 @@ namespace Bit.PostgresMigrations.Migrations
.HasMaxLength(32)
.HasColumnType("character varying(32)");
b.Property<bool>("UnknownDeviceVerificationEnabled")
.HasColumnType("boolean");
b.Property<bool>("UsesKeyConnector")
.HasColumnType("boolean");

View File

@ -0,0 +1,8 @@
START TRANSACTION;
ALTER TABLE "User" ADD "UnknownDeviceVerificationEnabled" boolean NOT NULL DEFAULT 1;
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
VALUES ('20220524170740_DeviceUnknownVerification', '5.0.12');
COMMIT;