1
0
mirror of https://github.com/bitwarden/server synced 2025-12-19 17:53:44 +00:00

Add UpdateAccountCryptographicState repository function (#6669)

* Add user repository update function for account cryptographic state

* Remove comment

* Remove transaction logic

* Fix security version

* Apply feedback

* Update tests

* Add support for external actions
This commit is contained in:
Bernd Schoolmann
2025-12-11 12:10:50 +01:00
committed by GitHub
parent 1aad410128
commit 919d0be6d2
7 changed files with 374 additions and 3 deletions

View File

@@ -2,16 +2,16 @@
using System.Text.Json;
using Bit.Core;
using Bit.Core.Entities;
using Bit.Core.KeyManagement.Models.Data;
using Bit.Core.KeyManagement.UserKey;
using Bit.Core.Models.Data;
using Bit.Core.Repositories;
using Bit.Core.Settings;
using Bit.Core.Utilities;
using Dapper;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.Data.SqlClient;
#nullable enable
namespace Bit.Infrastructure.Dapper.Repositories;
public class UserRepository : Repository<User, Guid>, IUserRepository
@@ -288,6 +288,63 @@ public class UserRepository : Repository<User, Guid>, IUserRepository
UnprotectData(user);
}
public async Task SetV2AccountCryptographicStateAsync(
Guid userId,
UserAccountKeysData accountKeysData,
IEnumerable<UpdateUserData>? updateUserDataActions = null)
{
if (!accountKeysData.IsV2Encryption())
{
throw new ArgumentException("Provided account keys data is not valid V2 encryption data.", nameof(accountKeysData));
}
var timestamp = DateTime.UtcNow;
var signatureKeyPairId = CoreHelpers.GenerateComb();
await using var connection = new SqlConnection(ConnectionString);
await connection.OpenAsync();
await using var transaction = connection.BeginTransaction();
try
{
await connection.ExecuteAsync(
"[dbo].[User_UpdateAccountCryptographicState]",
new
{
Id = userId,
PublicKey = accountKeysData.PublicKeyEncryptionKeyPairData.PublicKey,
PrivateKey = accountKeysData.PublicKeyEncryptionKeyPairData.WrappedPrivateKey,
SignedPublicKey = accountKeysData.PublicKeyEncryptionKeyPairData.SignedPublicKey,
SecurityState = accountKeysData.SecurityStateData!.SecurityState,
SecurityVersion = accountKeysData.SecurityStateData!.SecurityVersion,
SignatureKeyPairId = signatureKeyPairId,
SignatureAlgorithm = accountKeysData.SignatureKeyPairData!.SignatureAlgorithm,
SigningKey = accountKeysData.SignatureKeyPairData!.WrappedSigningKey,
VerifyingKey = accountKeysData.SignatureKeyPairData!.VerifyingKey,
RevisionDate = timestamp,
AccountRevisionDate = timestamp
},
transaction: transaction,
commandType: CommandType.StoredProcedure);
// Update user data that depends on cryptographic state
if (updateUserDataActions != null)
{
foreach (var action in updateUserDataActions)
{
await action(connection, transaction);
}
}
await transaction.CommitAsync();
}
catch
{
await transaction.RollbackAsync();
throw;
}
}
public async Task<IEnumerable<User>> GetManyAsync(IEnumerable<Guid> ids)
{
using (var connection = new SqlConnection(ReadOnlyConnectionString))