mirror of
https://github.com/bitwarden/server
synced 2025-12-23 03:33:35 +00:00
[PM-21612] [Unified] Fix unhandled error when editing an invited member (#5817)
* Check for UserId instead of passing potentially default value to bump account revision date method. * Pass explicit UserId into CipherRepository.CreateAsync method used for imports.
This commit is contained in:
@@ -36,6 +36,11 @@ public class User : ITableObject<Guid>, IStorableSubscriber, IRevisable, ITwoFac
|
||||
public string? TwoFactorRecoveryCode { get; set; }
|
||||
public string? EquivalentDomains { get; set; }
|
||||
public string? ExcludedGlobalEquivalentDomains { get; set; }
|
||||
/// <summary>
|
||||
/// The Account Revision Date is used to check if new sync needs to occur. It should be updated
|
||||
/// whenever a change is made that affects a client's sync data; for example, updating their vault or
|
||||
/// organization membership.
|
||||
/// </summary>
|
||||
public DateTime AccountRevisionDate { get; set; } = DateTime.UtcNow;
|
||||
public string? Key { get; set; }
|
||||
public string? PublicKey { get; set; }
|
||||
|
||||
@@ -115,7 +115,7 @@ public class ImportCiphersCommand : IImportCiphersCommand
|
||||
}
|
||||
|
||||
// Create it all
|
||||
await _cipherRepository.CreateAsync(ciphers, newFolders);
|
||||
await _cipherRepository.CreateAsync(importingUserId, ciphers, newFolders);
|
||||
|
||||
// push
|
||||
await _pushService.PushSyncVaultAsync(importingUserId);
|
||||
|
||||
@@ -32,7 +32,10 @@ public interface ICipherRepository : IRepository<Cipher, Guid>
|
||||
Task DeleteByUserIdAsync(Guid userId);
|
||||
Task DeleteByOrganizationIdAsync(Guid organizationId);
|
||||
Task UpdateCiphersAsync(Guid userId, IEnumerable<Cipher> ciphers);
|
||||
Task CreateAsync(IEnumerable<Cipher> ciphers, IEnumerable<Folder> folders);
|
||||
/// <summary>
|
||||
/// Create ciphers and folders for the specified UserId. Must not be used to create organization owned items.
|
||||
/// </summary>
|
||||
Task CreateAsync(Guid userId, IEnumerable<Cipher> ciphers, IEnumerable<Folder> folders);
|
||||
Task CreateAsync(IEnumerable<Cipher> ciphers, IEnumerable<Collection> collections,
|
||||
IEnumerable<CollectionCipher> collectionCiphers, IEnumerable<CollectionUser> collectionUsers);
|
||||
Task SoftDeleteAsync(IEnumerable<Guid> ids, Guid userId);
|
||||
|
||||
@@ -484,7 +484,7 @@ public class CipherRepository : Repository<Cipher, Guid>, ICipherRepository
|
||||
}
|
||||
}
|
||||
|
||||
public async Task CreateAsync(IEnumerable<Cipher> ciphers, IEnumerable<Folder> folders)
|
||||
public async Task CreateAsync(Guid userId, IEnumerable<Cipher> ciphers, IEnumerable<Folder> folders)
|
||||
{
|
||||
if (!ciphers.Any())
|
||||
{
|
||||
@@ -518,7 +518,7 @@ public class CipherRepository : Repository<Cipher, Guid>, ICipherRepository
|
||||
|
||||
await connection.ExecuteAsync(
|
||||
$"[{Schema}].[User_BumpAccountRevisionDate]",
|
||||
new { Id = ciphers.First().UserId },
|
||||
new { Id = userId },
|
||||
commandType: CommandType.StoredProcedure, transaction: transaction);
|
||||
|
||||
transaction.Commit();
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using AutoMapper;
|
||||
using System.Diagnostics;
|
||||
using AutoMapper;
|
||||
using Bit.Core.AdminConsole.Enums;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Models;
|
||||
using Bit.Core.Enums;
|
||||
@@ -7,11 +8,12 @@ using Bit.Core.Models.Data;
|
||||
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Infrastructure.EntityFramework.Models;
|
||||
using Bit.Infrastructure.EntityFramework.Repositories;
|
||||
using Bit.Infrastructure.EntityFramework.Repositories.Queries;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Bit.Infrastructure.EntityFramework.Repositories;
|
||||
namespace Bit.Infrastructure.EntityFramework.AdminConsole.Repositories;
|
||||
|
||||
public class OrganizationUserRepository : Repository<Core.Entities.OrganizationUser, OrganizationUser, Guid>, IOrganizationUserRepository
|
||||
{
|
||||
@@ -440,15 +442,23 @@ public class OrganizationUserRepository : Repository<Core.Entities.OrganizationU
|
||||
}
|
||||
}
|
||||
|
||||
public async override Task ReplaceAsync(Core.Entities.OrganizationUser organizationUser)
|
||||
public override async Task ReplaceAsync(Core.Entities.OrganizationUser organizationUser)
|
||||
{
|
||||
await base.ReplaceAsync(organizationUser);
|
||||
using (var scope = ServiceScopeFactory.CreateScope())
|
||||
|
||||
// Only bump account revision dates for confirmed OrgUsers,
|
||||
// as this is the only status that receives sync data from the organization
|
||||
if (organizationUser.Status is not OrganizationUserStatusType.Confirmed)
|
||||
{
|
||||
var dbContext = GetDatabaseContext(scope);
|
||||
await dbContext.UserBumpAccountRevisionDateAsync(organizationUser.UserId.GetValueOrDefault());
|
||||
await dbContext.SaveChangesAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
Debug.Assert(organizationUser.UserId is not null, "OrganizationUser is confirmed but does not have a UserId.");
|
||||
|
||||
using var scope = ServiceScopeFactory.CreateScope();
|
||||
var dbContext = GetDatabaseContext(scope);
|
||||
await dbContext.UserBumpAccountRevisionDateAsync(organizationUser.UserId.Value);
|
||||
await dbContext.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task ReplaceAsync(Core.Entities.OrganizationUser obj, IEnumerable<CollectionAccessSelection> requestedCollections)
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using System.Diagnostics;
|
||||
#nullable enable
|
||||
|
||||
using System.Diagnostics;
|
||||
using Bit.Core.AdminConsole.Enums.Provider;
|
||||
using Bit.Core.Auth.Enums;
|
||||
using Bit.Core.Enums;
|
||||
@@ -11,8 +13,18 @@ namespace Bit.Infrastructure.EntityFramework.Repositories;
|
||||
|
||||
public static class DatabaseContextExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Bump the account revision date for the user.
|
||||
/// The caller is responsible for providing a valid UserId (not a null or default Guid) for a user that exists
|
||||
/// in the database.
|
||||
/// </summary>
|
||||
public static async Task UserBumpAccountRevisionDateAsync(this DatabaseContext context, Guid userId)
|
||||
{
|
||||
if (userId == Guid.Empty)
|
||||
{
|
||||
throw new ArgumentException("Invalid UserId.");
|
||||
}
|
||||
|
||||
var user = await context.Users.FindAsync(userId);
|
||||
Debug.Assert(user is not null, "The user id is expected to be validated as a true-in database user before making this call.");
|
||||
user.AccountRevisionDate = DateTime.UtcNow;
|
||||
|
||||
@@ -142,8 +142,10 @@ public class CipherRepository : Repository<Core.Vault.Entities.Cipher, Cipher, G
|
||||
}
|
||||
}
|
||||
|
||||
public async Task CreateAsync(IEnumerable<Core.Vault.Entities.Cipher> ciphers, IEnumerable<Core.Vault.Entities.Folder> folders)
|
||||
public async Task CreateAsync(Guid userId, IEnumerable<Core.Vault.Entities.Cipher> ciphers,
|
||||
IEnumerable<Core.Vault.Entities.Folder> folders)
|
||||
{
|
||||
ciphers = ciphers.ToList();
|
||||
if (!ciphers.Any())
|
||||
{
|
||||
return;
|
||||
@@ -156,7 +158,8 @@ public class CipherRepository : Repository<Core.Vault.Entities.Cipher, Cipher, G
|
||||
await dbContext.BulkCopyAsync(base.DefaultBulkCopyOptions, folderEntities);
|
||||
var cipherEntities = Mapper.Map<List<Cipher>>(ciphers);
|
||||
await dbContext.BulkCopyAsync(base.DefaultBulkCopyOptions, cipherEntities);
|
||||
await dbContext.UserBumpAccountRevisionDateAsync(ciphers.First().UserId.GetValueOrDefault());
|
||||
await dbContext.UserBumpAccountRevisionDateAsync(userId);
|
||||
|
||||
await dbContext.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user