1
0
mirror of https://github.com/bitwarden/server.git synced 2025-06-12 06:00:36 -05:00

Add signing key repositories, models, and sql migration scripts

This commit is contained in:
Bernd Schoolmann 2025-06-02 14:50:50 +02:00
parent d7d90e7f3e
commit 20999391b3
No known key found for this signature in database
20 changed files with 615 additions and 1 deletions

View File

@ -22,6 +22,9 @@ public class User : ITableObject<Guid>, IStorableSubscriber, IRevisable, ITwoFac
[MaxLength(256)]
public string Email { get; set; } = null!;
public bool EmailVerified { get; set; }
/// <summary>
/// The server-side master-password hash
/// </summary>
[MaxLength(300)]
public string? MasterPassword { get; set; }
[MaxLength(50)]
@ -42,9 +45,22 @@ public class User : ITableObject<Guid>, IStorableSubscriber, IRevisable, ITwoFac
/// organization membership.
/// </summary>
public DateTime AccountRevisionDate { get; set; } = DateTime.UtcNow;
/// <summary>
/// The master-password-sealed user key.
/// </summary>
public string? Key { get; set; }
/// <summary>
/// The raw public key, without a signature from the user's signature key.
/// </summary>
public string? PublicKey { get; set; }
/// <summary>
/// User key wrapped private key.
/// </summary>
public string? PrivateKey { get; set; }
/// <summary>
/// The public key, signed by the user's signature key.
/// </summary>
public string? SignedPublicKey { get; set; }
public bool Premium { get; set; }
public DateTime? PremiumExpirationDate { get; set; }
public DateTime? RenewalReminderDate { get; set; }

View File

@ -0,0 +1,27 @@
using System.ComponentModel.DataAnnotations;
using Bit.Core.Enums;
using Bit.Core.Utilities;
#nullable enable
namespace Bit.Core.Entities;
public class UserSigningKeys : ITableObject<Guid>, IRevisable
{
public Guid Id { get; set; }
public Guid UserId { get; set; }
public SigningKeyType KeyType { get; set; }
[MaxLength(500)]
public string? VerifyingKey { get; set; }
[MaxLength(500)]
public string? SigningKey { get; set; }
public DateTime CreationDate { get; set; } = DateTime.UtcNow;
public DateTime RevisionDate { get; set; } = DateTime.UtcNow;
public void SetNewId()
{
Id = CoreHelpers.GenerateComb();
}
}

View File

@ -0,0 +1,6 @@
namespace Bit.Core.Enums;
public enum SigningKeyType : byte
{
Ed25519 = 0
}

View File

@ -0,0 +1,10 @@
using Bit.Core.Enums;
namespace Bit.Core.KeyManagement.Models.Data;
public class SigningKeyData
{
public SigningKeyType KeyAlgorithm { get; set; }
public string WrappedSigningKey { get; set; }
public string VerifyingKey { get; set; }
}

View File

@ -0,0 +1,14 @@
#nullable enable
using Bit.Core.Entities;
using Bit.Core.KeyManagement.Models.Data;
using Bit.Core.KeyManagement.UserKey;
using Bit.Core.Repositories;
namespace Bit.Core.KeyManagement.Repositories;
public interface IUserSigningKeysRepository : IRepository<UserSigningKeys, Guid>
{
public Task<SigningKeyData?> GetByUserIdAsync(Guid userId);
public UpdateEncryptedDataForKeyRotation UpdateForKeyRotation(Guid grantorId, SigningKeyData signingKeys);
public UpdateEncryptedDataForKeyRotation SetUserSigningKeys(Guid userId, SigningKeyData signingKeys);
}

View File

@ -68,6 +68,7 @@ public static class DapperServiceCollectionExtensions
services.AddSingleton<ISecurityTaskRepository, SecurityTaskRepository>();
services.AddSingleton<IUserAsymmetricKeysRepository, UserAsymmetricKeysRepository>();
services.AddSingleton<IOrganizationInstallationRepository, OrganizationInstallationRepository>();
services.AddSingleton<IUserSigningKeysRepository, UserSigningKeysRepository>();
if (selfHosted)
{

View File

@ -0,0 +1,79 @@
#nullable enable
using System.Data;
using Bit.Core.Entities;
using Bit.Core.KeyManagement.Models.Data;
using Bit.Core.KeyManagement.Repositories;
using Bit.Core.KeyManagement.UserKey;
using Bit.Core.Settings;
using Bit.Infrastructure.Dapper.Repositories;
using Dapper;
using Microsoft.Data.SqlClient;
namespace Bit.Infrastructure.Dapper.KeyManagement.Repositories;
public class UserSigningKeysRepository : Repository<UserSigningKeys, Guid>, IUserSigningKeysRepository
{
public UserSigningKeysRepository(GlobalSettings globalSettings)
: this(globalSettings.SqlServer.ConnectionString, globalSettings.SqlServer.ReadOnlyConnectionString)
{
}
public UserSigningKeysRepository(string connectionString, string readOnlyConnectionString) : base(
connectionString, readOnlyConnectionString)
{
}
public async Task<SigningKeyData?> GetByUserIdAsync(Guid userId)
{
using (var connection = new SqlConnection(ConnectionString))
{
return await connection.QuerySingleOrDefaultAsync<SigningKeyData>(
"[dbo].[UserSigningKeys_ReadByUserId]",
new
{
UserId = userId
},
commandType: CommandType.StoredProcedure);
}
}
public UpdateEncryptedDataForKeyRotation SetUserSigningKeys(Guid userId, SigningKeyData signingKeys)
{
return async (SqlConnection connection, SqlTransaction transaction) =>
{
await connection.QueryAsync(
"[dbo].[UserSigningKeys_SetForRotation]",
new
{
Id = Guid.NewGuid(),
UserId = userId,
KeyType = (byte)signingKeys.KeyAlgorithm,
signingKeys.VerifyingKey,
SigningKey = signingKeys.WrappedSigningKey,
CreationDate = DateTime.UtcNow,
RevisionDate = DateTime.UtcNow
},
commandType: CommandType.StoredProcedure,
transaction: transaction);
};
}
public UpdateEncryptedDataForKeyRotation UpdateForKeyRotation(Guid grantorId, SigningKeyData signingKeys)
{
return async (SqlConnection connection, SqlTransaction transaction) =>
{
await connection.QueryAsync(
"[dbo].[UserSigningKeys_UpdateForRotation]",
new
{
UserId = grantorId,
KeyType = (byte)signingKeys.KeyAlgorithm,
signingKeys.VerifyingKey,
SigningKey = signingKeys.WrappedSigningKey,
RevisionDate = DateTime.UtcNow
},
commandType: CommandType.StoredProcedure,
transaction: transaction);
};
}
}

View File

@ -104,6 +104,7 @@ public static class EntityFrameworkServiceCollectionExtensions
services.AddSingleton<IPasswordHealthReportApplicationRepository, PasswordHealthReportApplicationRepository>();
services.AddSingleton<ISecurityTaskRepository, SecurityTaskRepository>();
services.AddSingleton<IUserAsymmetricKeysRepository, UserAsymmetricKeysRepository>();
services.AddSingleton<IUserSigningKeysRepository, UserSigningKeysRepository>();
services.AddSingleton<IOrganizationInstallationRepository, OrganizationInstallationRepository>();
if (selfHosted)

View File

@ -0,0 +1,74 @@
#nullable enable
using AutoMapper;
using Bit.Core.KeyManagement.Models.Data;
using Bit.Core.KeyManagement.Repositories;
using Bit.Core.KeyManagement.UserKey;
using Bit.Infrastructure.EntityFramework.Repositories;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
namespace Bit.Infrastructure.EntityFramework.KeyManagement.Repositories;
public class UserSigningKeysRepository : Repository<Core.Entities.UserSigningKeys, Models.UserSigningKeys, Guid>, IUserSigningKeysRepository
{
public UserSigningKeysRepository(IServiceScopeFactory serviceScopeFactory, IMapper mapper) : base(serviceScopeFactory, mapper, context => context.UserSigningKeys)
{
}
public async Task<SigningKeyData?> GetByUserIdAsync(Guid userId)
{
await using var scope = ServiceScopeFactory.CreateAsyncScope();
var dbContext = GetDatabaseContext(scope);
var signingKeys = await dbContext.UserSigningKeys.FindAsync(userId);
if (signingKeys == null)
{
return null;
}
return new SigningKeyData
{
KeyAlgorithm = signingKeys.KeyType,
VerifyingKey = signingKeys.VerifyingKey,
WrappedSigningKey = signingKeys.SigningKey,
};
}
public UpdateEncryptedDataForKeyRotation SetUserSigningKeys(Guid userId, SigningKeyData signingKeys)
{
return async (_, _) =>
{
await using var scope = ServiceScopeFactory.CreateAsyncScope();
var dbContext = GetDatabaseContext(scope);
var entity = new Models.UserSigningKeys
{
Id = Guid.NewGuid(),
UserId = userId,
KeyType = signingKeys.KeyAlgorithm,
VerifyingKey = signingKeys.VerifyingKey,
SigningKey = signingKeys.WrappedSigningKey,
CreationDate = DateTime.UtcNow,
RevisionDate = DateTime.UtcNow,
};
await dbContext.UserSigningKeys.AddAsync(entity);
await dbContext.SaveChangesAsync();
};
}
public UpdateEncryptedDataForKeyRotation UpdateForKeyRotation(Guid grantorId, SigningKeyData signingKeys)
{
return async (_, _) =>
{
await using var scope = ServiceScopeFactory.CreateAsyncScope();
var dbContext = GetDatabaseContext(scope);
var entity = await dbContext.UserSigningKeys.FirstOrDefaultAsync(x => x.UserId == grantorId);
if (entity != null)
{
entity.KeyType = signingKeys.KeyAlgorithm;
entity.VerifyingKey = signingKeys.VerifyingKey;
entity.SigningKey = signingKeys.WrappedSigningKey;
entity.RevisionDate = DateTime.UtcNow;
await dbContext.SaveChangesAsync();
}
};
}
}

View File

@ -0,0 +1,16 @@
using AutoMapper;
namespace Bit.Infrastructure.EntityFramework.Models;
public class UserSigningKeys : Core.Entities.UserSigningKeys
{
public virtual User User { get; set; }
}
public class UserSigningKeysMapperProfile : Profile
{
public UserSigningKeysMapperProfile()
{
CreateMap<Core.Entities.UserSigningKeys, UserSigningKeys>().ReverseMap();
}
}

View File

@ -71,6 +71,7 @@ public class DatabaseContext : DbContext
public DbSet<TaxRate> TaxRates { get; set; }
public DbSet<Transaction> Transactions { get; set; }
public DbSet<User> Users { get; set; }
public DbSet<UserSigningKeys> UserSigningKeys { get; set; }
public DbSet<AuthRequest> AuthRequests { get; set; }
public DbSet<OrganizationDomain> OrganizationDomains { get; set; }
public DbSet<WebAuthnCredential> WebAuthnCredentials { get; set; }
@ -108,6 +109,7 @@ public class DatabaseContext : DbContext
var eSsoConfig = builder.Entity<SsoConfig>();
var eTaxRate = builder.Entity<TaxRate>();
var eUser = builder.Entity<User>();
var eUserSigningKeys = builder.Entity<UserSigningKeys>();
var eOrganizationApiKey = builder.Entity<OrganizationApiKey>();
var eOrganizationConnection = builder.Entity<OrganizationConnection>();
var eOrganizationDomain = builder.Entity<OrganizationDomain>();
@ -128,6 +130,7 @@ public class DatabaseContext : DbContext
eOrganizationConnection.Property(c => c.Id).ValueGeneratedNever();
eOrganizationDomain.Property(ar => ar.Id).ValueGeneratedNever();
aWebAuthnCredential.Property(ar => ar.Id).ValueGeneratedNever();
eUserSigningKeys.Property(ar => ar.Id).ValueGeneratedNever();
eCollectionCipher.HasKey(cc => new { cc.CollectionId, cc.CipherId });
eCollectionUser.HasKey(cu => new { cu.CollectionId, cu.OrganizationUserId });
@ -168,6 +171,7 @@ public class DatabaseContext : DbContext
eOrganizationConnection.ToTable(nameof(OrganizationConnection));
eOrganizationDomain.ToTable(nameof(OrganizationDomain));
aWebAuthnCredential.ToTable(nameof(WebAuthnCredential));
eUserSigningKeys.ToTable(nameof(UserSigningKeys));
ConfigureDateTimeUtcQueries(builder);
}

View File

@ -0,0 +1,8 @@
CREATE PROCEDURE [dbo].[UserSigningKeys_ReadByUserId]
@UserId UNIQUEIDENTIFIER
AS
BEGIN
SELECT *
FROM [dbo].[UserSigningKeys]
WHERE [UserId] = @UserId;
END

View File

@ -0,0 +1,15 @@
CREATE PROCEDURE [dbo].[UserSigningKeys_UpdateForRotation]
@UserId UNIQUEIDENTIFIER,
@KeyType TINYINT,
@VerifyingKey VARCHAR(MAX),
@SigningKey VARCHAR(MAX),
@RevisionDate DATETIME2(7)
AS
BEGIN
UPDATE [dbo].[UserSigningKeys]
SET [KeyType] = @KeyType,
[VerifyingKey] = @VerifyingKey,
[SigningKey] = @SigningKey,
[RevisionDate] = @RevisionDate
WHERE [UserId] = @UserId;
END

View File

@ -0,0 +1,13 @@
CREATE PROCEDURE [dbo].[UserSigningKeys_SetForRotation]
@Id UNIQUEIDENTIFIER,
@UserId UNIQUEIDENTIFIER,
@KeyType TINYINT,
@VerifyingKey VARCHAR(MAX),
@SigningKey VARCHAR(MAX),
@CreationDate DATETIME2(7),
@RevisionDate DATETIME2(7)
AS
BEGIN
INSERT INTO [dbo].[UserSigningKeys] ([Id], [UserId], [KeyType], [VerifyingKey], [SigningKey], [CreationDate], [RevisionDate])
VALUES (@Id, @UserId, @KeyType, @VerifyingKey, @SigningKey, @CreationDate, @RevisionDate)
END

View File

@ -14,6 +14,7 @@
@AccountRevisionDate DATETIME2(7),
@Key NVARCHAR(MAX),
@PublicKey NVARCHAR(MAX),
@SignedPublicKeyOwnershipClaim NVARCHAR(MAX),
@PrivateKey NVARCHAR(MAX),
@Premium BIT,
@PremiumExpirationDate DATETIME2(7),
@ -63,6 +64,7 @@ BEGIN
[AccountRevisionDate],
[Key],
[PublicKey],
[SignedPublicKeyOwnershipClaim],
[PrivateKey],
[Premium],
[PremiumExpirationDate],
@ -109,6 +111,7 @@ BEGIN
@AccountRevisionDate,
@Key,
@PublicKey,
@SignedPublicKeyOwnershipClaim,
@PrivateKey,
@Premium,
@PremiumExpirationDate,

View File

@ -14,6 +14,7 @@
@AccountRevisionDate DATETIME2(7),
@Key NVARCHAR(MAX),
@PublicKey NVARCHAR(MAX),
@SignedPublicKeyOwnershipClaim NVARCHAR(MAX),
@PrivateKey NVARCHAR(MAX),
@Premium BIT,
@PremiumExpirationDate DATETIME2(7),
@ -63,6 +64,7 @@ BEGIN
[AccountRevisionDate] = @AccountRevisionDate,
[Key] = @Key,
[PublicKey] = @PublicKey,
[SignedPublicKeyOwnershipClaim] = @SignedPublicKeyOwnershipClaim,
[PrivateKey] = @PrivateKey,
[Premium] = @Premium,
[PremiumExpirationDate] = @PremiumExpirationDate,

View File

@ -14,6 +14,7 @@
[AccountRevisionDate] DATETIME2 (7) NOT NULL,
[Key] VARCHAR (MAX) NULL,
[PublicKey] VARCHAR (MAX) NULL,
[SignedPublicKeyOwnershipClaim] VARCHAR (MAX) NULL,
[PrivateKey] VARCHAR (MAX) NULL,
[Premium] BIT NOT NULL,
[PremiumExpirationDate] DATETIME2 (7) NULL,

View File

@ -0,0 +1,11 @@
CREATE TABLE [dbo].[UserSigningKeys] (
[Id] UNIQUEIDENTIFIER NOT NULL,
[UserId] UNIQUEIDENTIFIER,
[KeyType] TINYINT NOT NULL,
[VerifyingKey] VARCHAR(MAX) NOT NULL,
[SigningKey] VARCHAR(MAX) NOT NULL,
[CreationDate] DATETIME2 (7) NOT NULL,
[RevisionDate] DATETIME2 (7) NOT NULL,
CONSTRAINT [PK_UserSigningKeys] PRIMARY KEY CLUSTERED ([Id] ASC),
CONSTRAINT [FK_UserSigningKeys_User] FOREIGN KEY ([UserId]) REFERENCES [dbo].[User] ([Id]),
);

View File

@ -29,7 +29,8 @@ public class UserCompare : IEqualityComparer<User>
x.LicenseKey == y.LicenseKey &&
x.ApiKey == y.ApiKey &&
x.Kdf == y.Kdf &&
x.KdfIterations == y.KdfIterations;
x.KdfIterations == y.KdfIterations &&
x.SignedPublicKey == y.SignedPublicKey;
}
public int GetHashCode([DisallowNull] User obj)

View File

@ -0,0 +1,312 @@
CREATE TABLE [dbo].[UserSigningKeys] (
[Id] UNIQUEIDENTIFIER NOT NULL,
[UserId] UNIQUEIDENTIFIER,
[KeyType] TINYINT NOT NULL,
[VerifyingKey] VARCHAR(MAX) NOT NULL,
[SigningKey] VARCHAR(MAX) NOT NULL,
[CreationDate] DATETIME2 (7) NOT NULL,
[RevisionDate] DATETIME2 (7) NOT NULL,
CONSTRAINT [PK_UserSigningKeys] PRIMARY KEY CLUSTERED ([Id] ASC),
CONSTRAINT [FK_UserSigningKeys_User] FOREIGN KEY ([UserId]) REFERENCES [dbo].[User] ([Id])
);
GO
CREATE PROCEDURE [dbo].[UserSigningKeys_ReadByUserId]
@UserId UNIQUEIDENTIFIER
AS
BEGIN
SELECT *
FROM [dbo].[UserSigningKeys]
WHERE [UserId] = @UserId;
END
GO
CREATE PROCEDURE [dbo].[UserSigningKeys_UpdateForRotation]
@UserId UNIQUEIDENTIFIER,
@KeyType TINYINT,
@VerifyingKey VARCHAR(MAX),
@SigningKey VARCHAR(MAX),
@RevisionDate DATETIME2(7)
AS
BEGIN
UPDATE [dbo].[UserSigningKeys]
SET [KeyType] = @KeyType,
[VerifyingKey] = @VerifyingKey,
[SigningKey] = @SigningKey,
[RevisionDate] = @RevisionDate
WHERE [UserId] = @UserId;
END
GO
CREATE PROCEDURE [dbo].[UserSigningKeys_SetForRotation]
@Id UNIQUEIDENTIFIER,
@UserId UNIQUEIDENTIFIER,
@KeyType TINYINT,
@VerifyingKey VARCHAR(MAX),
@SigningKey VARCHAR(MAX),
@CreationDate DATETIME2(7),
@RevisionDate DATETIME2(7)
AS
BEGIN
INSERT INTO [dbo].[UserSigningKeys] ([Id], [UserId], [KeyType], [VerifyingKey], [SigningKey], [CreationDate], [RevisionDate])
VALUES (@Id, @UserId, @KeyType, @VerifyingKey, @SigningKey, @CreationDate, @RevisionDate)
END
GO
IF COL_LENGTH('[dbo].[User]', 'SignedPublicKeyOwnershipClaim') IS NULL
BEGIN
ALTER TABLE
[dbo].[User]
ADD
[SignedPublicKeyOwnershipClaim] VARCHAR(MAX) NULL;
END
GO
EXECUTE sp_refreshview 'dbo.UserView'
GO
CREATE OR ALTER 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),
@SignedPublicKeyOwnershipClaim 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,
@KdfMemory INT = NULL,
@KdfParallelism INT = NULL,
@CreationDate DATETIME2(7),
@RevisionDate DATETIME2(7),
@ApiKey VARCHAR(30),
@ForcePasswordReset BIT = 0,
@UsesKeyConnector BIT = 0,
@FailedLoginCount INT = 0,
@LastFailedLoginDate DATETIME2(7),
@AvatarColor VARCHAR(7) = NULL,
@LastPasswordChangeDate DATETIME2(7) = NULL,
@LastKdfChangeDate DATETIME2(7) = NULL,
@LastKeyRotationDate DATETIME2(7) = NULL,
@LastEmailChangeDate DATETIME2(7) = NULL,
@VerifyDevices 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],
[SignedPublicKeyOwnershipClaim],
[PrivateKey],
[Premium],
[PremiumExpirationDate],
[RenewalReminderDate],
[Storage],
[MaxStorageGb],
[Gateway],
[GatewayCustomerId],
[GatewaySubscriptionId],
[ReferenceData],
[LicenseKey],
[Kdf],
[KdfIterations],
[CreationDate],
[RevisionDate],
[ApiKey],
[ForcePasswordReset],
[UsesKeyConnector],
[FailedLoginCount],
[LastFailedLoginDate],
[AvatarColor],
[KdfMemory],
[KdfParallelism],
[LastPasswordChangeDate],
[LastKdfChangeDate],
[LastKeyRotationDate],
[LastEmailChangeDate],
[VerifyDevices]
)
VALUES
(
@Id,
@Name,
@Email,
@EmailVerified,
@MasterPassword,
@MasterPasswordHint,
@Culture,
@SecurityStamp,
@TwoFactorProviders,
@TwoFactorRecoveryCode,
@EquivalentDomains,
@ExcludedGlobalEquivalentDomains,
@AccountRevisionDate,
@Key,
@PublicKey,
@SignedPublicKeyOwnershipClaim,
@PrivateKey,
@Premium,
@PremiumExpirationDate,
@RenewalReminderDate,
@Storage,
@MaxStorageGb,
@Gateway,
@GatewayCustomerId,
@GatewaySubscriptionId,
@ReferenceData,
@LicenseKey,
@Kdf,
@KdfIterations,
@CreationDate,
@RevisionDate,
@ApiKey,
@ForcePasswordReset,
@UsesKeyConnector,
@FailedLoginCount,
@LastFailedLoginDate,
@AvatarColor,
@KdfMemory,
@KdfParallelism,
@LastPasswordChangeDate,
@LastKdfChangeDate,
@LastKeyRotationDate,
@LastEmailChangeDate,
@VerifyDevices
)
END
GO
CREATE OR ALTER 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),
@SignedPublicKeyOwnershipClaim 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,
@KdfMemory INT = NULL,
@KdfParallelism INT = NULL,
@CreationDate DATETIME2(7),
@RevisionDate DATETIME2(7),
@ApiKey VARCHAR(30),
@ForcePasswordReset BIT = 0,
@UsesKeyConnector BIT = 0,
@FailedLoginCount INT,
@LastFailedLoginDate DATETIME2(7),
@AvatarColor VARCHAR(7),
@LastPasswordChangeDate DATETIME2(7) = NULL,
@LastKdfChangeDate DATETIME2(7) = NULL,
@LastKeyRotationDate DATETIME2(7) = NULL,
@LastEmailChangeDate DATETIME2(7) = NULL,
@VerifyDevices BIT = 1
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,
[SignedPublicKeyOwnershipClaim] = @SignedPublicKeyOwnershipClaim,
[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,
[KdfMemory] = @KdfMemory,
[KdfParallelism] = @KdfParallelism,
[CreationDate] = @CreationDate,
[RevisionDate] = @RevisionDate,
[ApiKey] = @ApiKey,
[ForcePasswordReset] = @ForcePasswordReset,
[UsesKeyConnector] = @UsesKeyConnector,
[FailedLoginCount] = @FailedLoginCount,
[LastFailedLoginDate] = @LastFailedLoginDate,
[AvatarColor] = @AvatarColor,
[LastPasswordChangeDate] = @LastPasswordChangeDate,
[LastKdfChangeDate] = @LastKdfChangeDate,
[LastKeyRotationDate] = @LastKeyRotationDate,
[LastEmailChangeDate] = @LastEmailChangeDate,
[VerifyDevices] = @VerifyDevices
WHERE
[Id] = @Id
END
GO