mirror of
https://github.com/bitwarden/server.git
synced 2025-07-03 17:12:49 -05:00
[SG-998] Move files to Vault folders (#2724)
* Move Api files * Move Core files * Move Infrastructure files * Move Sql Files * Move Api Sync files to Vault * Move test vault files * Update Sql.sqlproj paths * Update Codeowners * Fix vault file paths in sqlproj * Update CipherDetails.sql path in sqlproj * Update Core models and entities namespaces * Update namespaces Core Services and Repositories * Missed service namespaces * Update Api namespaces * Update Infrastructure namespaces * Move infrastructure queries that were missed * Tests namespace updates * Admin and Events namespace updates * Remove unused usings * Remove extra CiphersController usings * Rename folder * Fix CipherDetails namespace * Sqlproj fixes * Move stored procs into folders by table * using order fix
This commit is contained in:
@ -1,796 +0,0 @@
|
||||
using AutoMapper;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Models.Data;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Utilities;
|
||||
using Bit.Infrastructure.EntityFramework.Models;
|
||||
using Bit.Infrastructure.EntityFramework.Repositories.Queries;
|
||||
using Core.Models.Data;
|
||||
using LinqToDB.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using User = Bit.Core.Entities.User;
|
||||
|
||||
namespace Bit.Infrastructure.EntityFramework.Repositories;
|
||||
|
||||
public class CipherRepository : Repository<Core.Entities.Cipher, Cipher, Guid>, ICipherRepository
|
||||
{
|
||||
public CipherRepository(IServiceScopeFactory serviceScopeFactory, IMapper mapper)
|
||||
: base(serviceScopeFactory, mapper, (DatabaseContext context) => context.Ciphers)
|
||||
{ }
|
||||
|
||||
public override async Task<Core.Entities.Cipher> CreateAsync(Core.Entities.Cipher cipher)
|
||||
{
|
||||
cipher = await base.CreateAsync(cipher);
|
||||
using (var scope = ServiceScopeFactory.CreateScope())
|
||||
{
|
||||
var dbContext = GetDatabaseContext(scope);
|
||||
if (cipher.OrganizationId.HasValue)
|
||||
{
|
||||
await dbContext.UserBumpAccountRevisionDateByCipherIdAsync(cipher.Id, cipher.OrganizationId.Value);
|
||||
}
|
||||
else if (cipher.UserId.HasValue)
|
||||
{
|
||||
await dbContext.UserBumpAccountRevisionDateAsync(cipher.UserId.Value);
|
||||
}
|
||||
await dbContext.SaveChangesAsync();
|
||||
}
|
||||
return cipher;
|
||||
}
|
||||
|
||||
public override async Task DeleteAsync(Core.Entities.Cipher cipher)
|
||||
{
|
||||
using (var scope = ServiceScopeFactory.CreateScope())
|
||||
{
|
||||
var dbContext = GetDatabaseContext(scope);
|
||||
var cipherInfo = await dbContext.Ciphers
|
||||
.Where(c => c.Id == cipher.Id)
|
||||
.Select(c => new { c.UserId, c.OrganizationId, HasAttachments = c.Attachments != null })
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
await base.DeleteAsync(cipher);
|
||||
|
||||
if (cipherInfo?.OrganizationId != null)
|
||||
{
|
||||
if (cipherInfo.HasAttachments == true)
|
||||
{
|
||||
await OrganizationUpdateStorage(cipherInfo.OrganizationId.Value);
|
||||
}
|
||||
|
||||
await dbContext.UserBumpAccountRevisionDateByCipherIdAsync(cipher.Id, cipherInfo.OrganizationId.Value);
|
||||
}
|
||||
else if (cipherInfo?.UserId != null)
|
||||
{
|
||||
if (cipherInfo.HasAttachments)
|
||||
{
|
||||
await UserUpdateStorage(cipherInfo.UserId.Value);
|
||||
}
|
||||
|
||||
await dbContext.UserBumpAccountRevisionDateAsync(cipherInfo.UserId.Value);
|
||||
}
|
||||
await dbContext.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task CreateAsync(Core.Entities.Cipher cipher, IEnumerable<Guid> collectionIds)
|
||||
{
|
||||
cipher = await CreateAsync(cipher);
|
||||
using (var scope = ServiceScopeFactory.CreateScope())
|
||||
{
|
||||
var dbContext = GetDatabaseContext(scope);
|
||||
await UpdateCollectionsAsync(dbContext, cipher.Id,
|
||||
cipher.UserId, cipher.OrganizationId, collectionIds);
|
||||
await dbContext.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task CreateAsync(CipherDetails cipher)
|
||||
{
|
||||
await CreateAsyncReturnCipher(cipher);
|
||||
}
|
||||
|
||||
private async Task<CipherDetails> CreateAsyncReturnCipher(CipherDetails cipher)
|
||||
{
|
||||
cipher.SetNewId();
|
||||
using (var scope = ServiceScopeFactory.CreateScope())
|
||||
{
|
||||
var dbContext = GetDatabaseContext(scope);
|
||||
var userIdKey = $"\"{cipher.UserId}\"";
|
||||
cipher.UserId = cipher.OrganizationId.HasValue ? null : cipher.UserId;
|
||||
cipher.Favorites = cipher.Favorite ?
|
||||
$"{{{userIdKey}:true}}" :
|
||||
null;
|
||||
cipher.Folders = cipher.FolderId.HasValue ?
|
||||
$"{{{userIdKey}:\"{cipher.FolderId}\"}}" :
|
||||
null;
|
||||
var entity = Mapper.Map<Cipher>((Core.Entities.Cipher)cipher);
|
||||
await dbContext.AddAsync(entity);
|
||||
|
||||
if (cipher.OrganizationId.HasValue)
|
||||
{
|
||||
await dbContext.UserBumpAccountRevisionDateByCipherIdAsync(cipher.Id, cipher.OrganizationId.Value);
|
||||
}
|
||||
else if (cipher.UserId.HasValue)
|
||||
{
|
||||
await dbContext.UserBumpAccountRevisionDateAsync(cipher.UserId.Value);
|
||||
}
|
||||
|
||||
await dbContext.SaveChangesAsync();
|
||||
}
|
||||
return cipher;
|
||||
}
|
||||
|
||||
public async Task CreateAsync(CipherDetails cipher, IEnumerable<Guid> collectionIds)
|
||||
{
|
||||
cipher = await CreateAsyncReturnCipher(cipher);
|
||||
using (var scope = ServiceScopeFactory.CreateScope())
|
||||
{
|
||||
var dbContext = GetDatabaseContext(scope);
|
||||
await UpdateCollectionsAsync(dbContext, cipher.Id,
|
||||
cipher.UserId, cipher.OrganizationId, collectionIds);
|
||||
await dbContext.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task CreateAsync(IEnumerable<Core.Entities.Cipher> ciphers, IEnumerable<Core.Entities.Folder> folders)
|
||||
{
|
||||
if (!ciphers.Any())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
using (var scope = ServiceScopeFactory.CreateScope())
|
||||
{
|
||||
var dbContext = GetDatabaseContext(scope);
|
||||
var folderEntities = Mapper.Map<List<Folder>>(folders);
|
||||
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.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task CreateAsync(IEnumerable<Core.Entities.Cipher> ciphers, IEnumerable<Core.Entities.Collection> collections, IEnumerable<Core.Entities.CollectionCipher> collectionCiphers)
|
||||
{
|
||||
if (!ciphers.Any())
|
||||
{
|
||||
return;
|
||||
}
|
||||
using (var scope = ServiceScopeFactory.CreateScope())
|
||||
{
|
||||
var dbContext = GetDatabaseContext(scope);
|
||||
var cipherEntities = Mapper.Map<List<Cipher>>(ciphers);
|
||||
await dbContext.BulkCopyAsync(base.DefaultBulkCopyOptions, cipherEntities);
|
||||
if (collections.Any())
|
||||
{
|
||||
var collectionEntities = Mapper.Map<List<Collection>>(collections);
|
||||
await dbContext.BulkCopyAsync(base.DefaultBulkCopyOptions, collectionEntities);
|
||||
|
||||
if (collectionCiphers.Any())
|
||||
{
|
||||
var collectionCipherEntities = Mapper.Map<List<CollectionCipher>>(collectionCiphers);
|
||||
await dbContext.BulkCopyAsync(base.DefaultBulkCopyOptions, collectionCipherEntities);
|
||||
}
|
||||
}
|
||||
await dbContext.UserBumpAccountRevisionDateByOrganizationIdAsync(ciphers.First().OrganizationId.Value);
|
||||
await dbContext.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task DeleteAsync(IEnumerable<Guid> ids, Guid userId)
|
||||
{
|
||||
await ToggleCipherStates(ids, userId, CipherStateAction.HardDelete);
|
||||
}
|
||||
|
||||
public async Task DeleteAttachmentAsync(Guid cipherId, string attachmentId)
|
||||
{
|
||||
using (var scope = ServiceScopeFactory.CreateScope())
|
||||
{
|
||||
var dbContext = GetDatabaseContext(scope);
|
||||
var cipher = await dbContext.Ciphers.FindAsync(cipherId);
|
||||
var attachmentsJson = JObject.Parse(cipher.Attachments);
|
||||
attachmentsJson.Remove(attachmentId);
|
||||
cipher.Attachments = JsonConvert.SerializeObject(attachmentsJson);
|
||||
await dbContext.SaveChangesAsync();
|
||||
|
||||
if (cipher.OrganizationId.HasValue)
|
||||
{
|
||||
await OrganizationUpdateStorage(cipher.OrganizationId.Value);
|
||||
await dbContext.UserBumpAccountRevisionDateByCipherIdAsync(cipher.Id, cipher.OrganizationId.Value);
|
||||
}
|
||||
else if (cipher.UserId.HasValue)
|
||||
{
|
||||
await UserUpdateStorage(cipher.UserId.Value);
|
||||
await dbContext.UserBumpAccountRevisionDateAsync(cipher.UserId.Value);
|
||||
}
|
||||
await dbContext.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task DeleteByIdsOrganizationIdAsync(IEnumerable<Guid> ids, Guid organizationId)
|
||||
{
|
||||
using (var scope = ServiceScopeFactory.CreateScope())
|
||||
{
|
||||
var dbContext = GetDatabaseContext(scope);
|
||||
var ciphers = from c in dbContext.Ciphers
|
||||
where c.OrganizationId == organizationId &&
|
||||
ids.Contains(c.Id)
|
||||
select c;
|
||||
dbContext.RemoveRange(ciphers);
|
||||
await dbContext.SaveChangesAsync();
|
||||
await OrganizationUpdateStorage(organizationId);
|
||||
await dbContext.UserBumpAccountRevisionDateByOrganizationIdAsync(organizationId);
|
||||
await dbContext.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task DeleteByOrganizationIdAsync(Guid organizationId)
|
||||
{
|
||||
using (var scope = ServiceScopeFactory.CreateScope())
|
||||
{
|
||||
var dbContext = GetDatabaseContext(scope);
|
||||
|
||||
var collectionCiphers = from cc in dbContext.CollectionCiphers
|
||||
join c in dbContext.Collections
|
||||
on cc.CollectionId equals c.Id
|
||||
where c.OrganizationId == organizationId
|
||||
select cc;
|
||||
dbContext.RemoveRange(collectionCiphers);
|
||||
|
||||
var ciphers = from c in dbContext.Ciphers
|
||||
where c.OrganizationId == organizationId
|
||||
select c;
|
||||
dbContext.RemoveRange(ciphers);
|
||||
|
||||
await OrganizationUpdateStorage(organizationId);
|
||||
await dbContext.UserBumpAccountRevisionDateByOrganizationIdAsync(organizationId);
|
||||
await dbContext.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task DeleteByUserIdAsync(Guid userId)
|
||||
{
|
||||
using (var scope = ServiceScopeFactory.CreateScope())
|
||||
{
|
||||
var dbContext = GetDatabaseContext(scope);
|
||||
var ciphers = from c in dbContext.Ciphers
|
||||
where c.UserId == userId
|
||||
select c;
|
||||
dbContext.RemoveRange(ciphers);
|
||||
var folders = from f in dbContext.Folders
|
||||
where f.UserId == userId
|
||||
select f;
|
||||
dbContext.RemoveRange(folders);
|
||||
await dbContext.SaveChangesAsync();
|
||||
await UserUpdateStorage(userId);
|
||||
await dbContext.UserBumpAccountRevisionDateAsync(userId);
|
||||
await dbContext.SaveChangesAsync();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public async Task DeleteDeletedAsync(DateTime deletedDateBefore)
|
||||
{
|
||||
using (var scope = ServiceScopeFactory.CreateScope())
|
||||
{
|
||||
var dbContext = GetDatabaseContext(scope);
|
||||
var query = dbContext.Ciphers.Where(c => c.DeletedDate < deletedDateBefore);
|
||||
dbContext.RemoveRange(query);
|
||||
await dbContext.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<CipherDetails> GetByIdAsync(Guid id, Guid userId)
|
||||
{
|
||||
using (var scope = ServiceScopeFactory.CreateScope())
|
||||
{
|
||||
var dbContext = GetDatabaseContext(scope);
|
||||
var userCipherDetails = new UserCipherDetailsQuery(userId);
|
||||
var data = await userCipherDetails.Run(dbContext).FirstOrDefaultAsync(c => c.Id == id);
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ICollection<CipherOrganizationDetails>> GetManyOrganizationDetailsByOrganizationIdAsync(
|
||||
Guid organizationId)
|
||||
{
|
||||
using (var scope = ServiceScopeFactory.CreateScope())
|
||||
{
|
||||
var dbContext = GetDatabaseContext(scope);
|
||||
var query = new CipherOrganizationDetailsReadByOrganizationIdQuery(organizationId);
|
||||
var data = await query.Run(dbContext).ToListAsync();
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> GetCanEditByIdAsync(Guid userId, Guid cipherId)
|
||||
{
|
||||
using (var scope = ServiceScopeFactory.CreateScope())
|
||||
{
|
||||
var dbContext = GetDatabaseContext(scope);
|
||||
var query = new CipherReadCanEditByIdUserIdQuery(userId, cipherId);
|
||||
var canEdit = await query.Run(dbContext).AnyAsync();
|
||||
return canEdit;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ICollection<Core.Entities.Cipher>> GetManyByOrganizationIdAsync(Guid organizationId)
|
||||
{
|
||||
using (var scope = ServiceScopeFactory.CreateScope())
|
||||
{
|
||||
var dbContext = GetDatabaseContext(scope);
|
||||
var query = dbContext.Ciphers.Where(x => !x.UserId.HasValue && x.OrganizationId == organizationId);
|
||||
var data = await query.ToListAsync();
|
||||
return Mapper.Map<List<Core.Entities.Cipher>>(data);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ICollection<CipherDetails>> GetManyByUserIdAsync(Guid userId, bool withOrganizations = true)
|
||||
{
|
||||
using (var scope = ServiceScopeFactory.CreateScope())
|
||||
{
|
||||
var dbContext = GetDatabaseContext(scope);
|
||||
IQueryable<CipherDetails> cipherDetailsView = withOrganizations ?
|
||||
new UserCipherDetailsQuery(userId).Run(dbContext) :
|
||||
new CipherDetailsQuery(userId).Run(dbContext);
|
||||
if (!withOrganizations)
|
||||
{
|
||||
cipherDetailsView = from c in cipherDetailsView
|
||||
where c.UserId == userId
|
||||
select new CipherDetails
|
||||
{
|
||||
Id = c.Id,
|
||||
UserId = c.UserId,
|
||||
OrganizationId = c.OrganizationId,
|
||||
Type = c.Type,
|
||||
Data = c.Data,
|
||||
Attachments = c.Attachments,
|
||||
CreationDate = c.CreationDate,
|
||||
RevisionDate = c.RevisionDate,
|
||||
DeletedDate = c.DeletedDate,
|
||||
Favorite = c.Favorite,
|
||||
FolderId = c.FolderId,
|
||||
Edit = true,
|
||||
Reprompt = c.Reprompt,
|
||||
ViewPassword = true,
|
||||
OrganizationUseTotp = false,
|
||||
};
|
||||
}
|
||||
var ciphers = await cipherDetailsView.ToListAsync();
|
||||
return ciphers;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<CipherOrganizationDetails> GetOrganizationDetailsByIdAsync(Guid id)
|
||||
{
|
||||
using (var scope = ServiceScopeFactory.CreateScope())
|
||||
{
|
||||
var dbContext = GetDatabaseContext(scope);
|
||||
var query = new CipherOrganizationDetailsReadByIdQuery(id);
|
||||
var data = await query.Run(dbContext).FirstOrDefaultAsync();
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task MoveAsync(IEnumerable<Guid> ids, Guid? folderId, Guid userId)
|
||||
{
|
||||
using (var scope = ServiceScopeFactory.CreateScope())
|
||||
{
|
||||
var dbContext = GetDatabaseContext(scope);
|
||||
var cipherEntities = dbContext.Ciphers.Where(c => ids.Contains(c.Id));
|
||||
var userCipherDetails = new UserCipherDetailsQuery(userId).Run(dbContext);
|
||||
var idsToMove = from ucd in userCipherDetails
|
||||
join c in cipherEntities
|
||||
on ucd.Id equals c.Id
|
||||
select c;
|
||||
await idsToMove.ForEachAsync(cipher =>
|
||||
{
|
||||
var foldersJson = string.IsNullOrWhiteSpace(cipher.Folders) ?
|
||||
new JObject() :
|
||||
JObject.Parse(cipher.Folders);
|
||||
|
||||
if (folderId.HasValue)
|
||||
{
|
||||
foldersJson.Remove(userId.ToString());
|
||||
foldersJson.Add(userId.ToString(), folderId.Value.ToString());
|
||||
}
|
||||
else if (!string.IsNullOrWhiteSpace(cipher.Folders))
|
||||
{
|
||||
foldersJson.Remove(userId.ToString());
|
||||
}
|
||||
dbContext.Attach(cipher);
|
||||
cipher.Folders = JsonConvert.SerializeObject(foldersJson);
|
||||
});
|
||||
await dbContext.UserBumpAccountRevisionDateAsync(userId);
|
||||
await dbContext.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task ReplaceAsync(CipherDetails cipher)
|
||||
{
|
||||
cipher.UserId = cipher.OrganizationId.HasValue ?
|
||||
null :
|
||||
cipher.UserId;
|
||||
using (var scope = ServiceScopeFactory.CreateScope())
|
||||
{
|
||||
var dbContext = GetDatabaseContext(scope);
|
||||
var entity = await dbContext.Ciphers.FindAsync(cipher.Id);
|
||||
if (entity != null)
|
||||
{
|
||||
var userIdKey = $"\"{cipher.UserId}\"";
|
||||
if (cipher.Favorite)
|
||||
{
|
||||
if (cipher.Favorites == null)
|
||||
{
|
||||
cipher.Favorites = $"{{{userIdKey}:true}}";
|
||||
}
|
||||
else
|
||||
{
|
||||
var favorites = CoreHelpers.LoadClassFromJsonData<Dictionary<Guid, bool>>(cipher.Favorites);
|
||||
favorites.Add(cipher.UserId.Value, true);
|
||||
cipher.Favorites = JsonConvert.SerializeObject(favorites);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cipher.Favorites != null && cipher.Favorites.Contains(cipher.UserId.Value.ToString()))
|
||||
{
|
||||
var favorites = CoreHelpers.LoadClassFromJsonData<Dictionary<Guid, bool>>(cipher.Favorites);
|
||||
favorites.Remove(cipher.UserId.Value);
|
||||
cipher.Favorites = JsonConvert.SerializeObject(favorites);
|
||||
}
|
||||
}
|
||||
if (cipher.FolderId.HasValue)
|
||||
{
|
||||
if (cipher.Folders == null)
|
||||
{
|
||||
cipher.Folders = $"{{{userIdKey}:\"{cipher.FolderId}\"}}";
|
||||
}
|
||||
else
|
||||
{
|
||||
var folders = CoreHelpers.LoadClassFromJsonData<Dictionary<Guid, Guid>>(cipher.Folders);
|
||||
folders.Add(cipher.UserId.Value, cipher.FolderId.Value);
|
||||
cipher.Folders = JsonConvert.SerializeObject(folders);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cipher.Folders != null && cipher.Folders.Contains(cipher.UserId.Value.ToString()))
|
||||
{
|
||||
var folders = CoreHelpers.LoadClassFromJsonData<Dictionary<Guid, bool>>(cipher.Favorites);
|
||||
folders.Remove(cipher.UserId.Value);
|
||||
cipher.Favorites = JsonConvert.SerializeObject(folders);
|
||||
}
|
||||
}
|
||||
var mappedEntity = Mapper.Map<Cipher>((Core.Entities.Cipher)cipher);
|
||||
dbContext.Entry(entity).CurrentValues.SetValues(mappedEntity);
|
||||
|
||||
if (cipher.OrganizationId.HasValue)
|
||||
{
|
||||
await dbContext.UserBumpAccountRevisionDateByCipherIdAsync(cipher.Id, cipher.OrganizationId.Value);
|
||||
}
|
||||
else if (cipher.UserId.HasValue)
|
||||
{
|
||||
await dbContext.UserBumpAccountRevisionDateAsync(cipher.UserId.Value);
|
||||
}
|
||||
|
||||
await dbContext.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task<int> UpdateCollectionsAsync(DatabaseContext context, Guid id, Guid? userId, Guid? organizationId, IEnumerable<Guid> collectionIds)
|
||||
{
|
||||
if (!organizationId.HasValue || !collectionIds.Any())
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
IQueryable<Guid> availableCollectionsQuery;
|
||||
|
||||
if (!userId.HasValue)
|
||||
{
|
||||
availableCollectionsQuery = context.Collections
|
||||
.Where(c => c.OrganizationId == organizationId.Value)
|
||||
.Select(c => c.Id);
|
||||
}
|
||||
else
|
||||
{
|
||||
availableCollectionsQuery = from c in context.Collections
|
||||
join o in context.Organizations
|
||||
on c.OrganizationId equals o.Id
|
||||
join ou in context.OrganizationUsers
|
||||
on new { OrganizationId = o.Id, UserId = userId } equals
|
||||
new { ou.OrganizationId, ou.UserId }
|
||||
join cu in context.CollectionUsers
|
||||
on new { ou.AccessAll, CollectionId = c.Id, OrganizationUserId = ou.Id } equals
|
||||
new { AccessAll = false, cu.CollectionId, cu.OrganizationUserId } into cu_g
|
||||
from cu in cu_g.DefaultIfEmpty()
|
||||
join gu in context.GroupUsers
|
||||
on new { CollectionId = (Guid?)cu.CollectionId, ou.AccessAll, OrganizationUserId = ou.Id } equals
|
||||
new { CollectionId = (Guid?)null, AccessAll = false, gu.OrganizationUserId } into gu_g
|
||||
from gu in gu_g.DefaultIfEmpty()
|
||||
join g in context.Groups
|
||||
on gu.GroupId equals g.Id into g_g
|
||||
from g in g_g.DefaultIfEmpty()
|
||||
join cg in context.CollectionGroups
|
||||
on new { g.AccessAll, CollectionId = c.Id, gu.GroupId } equals
|
||||
new { AccessAll = false, cg.CollectionId, cg.GroupId } into cg_g
|
||||
from cg in cg_g.DefaultIfEmpty()
|
||||
where o.Id == organizationId &&
|
||||
o.Enabled &&
|
||||
ou.Status == OrganizationUserStatusType.Confirmed &&
|
||||
(ou.AccessAll || !cu.ReadOnly || g.AccessAll || !cg.ReadOnly)
|
||||
select c.Id;
|
||||
}
|
||||
|
||||
var availableCollections = await availableCollectionsQuery.ToListAsync();
|
||||
|
||||
if (!availableCollections.Any())
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
var collectionCiphers = collectionIds
|
||||
.Where(collectionId => availableCollections.Contains(collectionId))
|
||||
.Select(collectionId => new CollectionCipher
|
||||
{
|
||||
CollectionId = collectionId,
|
||||
CipherId = id,
|
||||
});
|
||||
context.CollectionCiphers.AddRange(collectionCiphers);
|
||||
return 0;
|
||||
}
|
||||
|
||||
public async Task<bool> ReplaceAsync(Core.Entities.Cipher cipher, IEnumerable<Guid> collectionIds)
|
||||
{
|
||||
using (var scope = ServiceScopeFactory.CreateScope())
|
||||
{
|
||||
var dbContext = GetDatabaseContext(scope);
|
||||
var transaction = await dbContext.Database.BeginTransactionAsync();
|
||||
var successes = await UpdateCollectionsAsync(
|
||||
dbContext, cipher.Id, cipher.UserId,
|
||||
cipher.OrganizationId, collectionIds);
|
||||
|
||||
if (successes < 0)
|
||||
{
|
||||
await transaction.CommitAsync();
|
||||
return false;
|
||||
}
|
||||
|
||||
var trackedCipher = await dbContext.Ciphers.FindAsync(cipher.Id);
|
||||
|
||||
trackedCipher.UserId = null;
|
||||
trackedCipher.OrganizationId = cipher.OrganizationId;
|
||||
trackedCipher.Data = cipher.Data;
|
||||
trackedCipher.Attachments = cipher.Attachments;
|
||||
trackedCipher.RevisionDate = cipher.RevisionDate;
|
||||
trackedCipher.DeletedDate = cipher.DeletedDate;
|
||||
|
||||
await transaction.CommitAsync();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(cipher.Attachments))
|
||||
{
|
||||
if (cipher.OrganizationId.HasValue)
|
||||
{
|
||||
await OrganizationUpdateStorage(cipher.OrganizationId.Value);
|
||||
}
|
||||
else if (cipher.UserId.HasValue)
|
||||
{
|
||||
await UserUpdateStorage(cipher.UserId.Value);
|
||||
}
|
||||
}
|
||||
|
||||
if (cipher.OrganizationId.HasValue)
|
||||
{
|
||||
await dbContext.UserBumpAccountRevisionDateByCipherIdAsync(cipher.Id, cipher.OrganizationId.Value);
|
||||
}
|
||||
else if (cipher.UserId.HasValue)
|
||||
{
|
||||
await dbContext.UserBumpAccountRevisionDateAsync(cipher.UserId.Value);
|
||||
}
|
||||
|
||||
await dbContext.SaveChangesAsync();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<DateTime> RestoreAsync(IEnumerable<Guid> ids, Guid userId)
|
||||
{
|
||||
return await ToggleCipherStates(ids, userId, CipherStateAction.Restore);
|
||||
}
|
||||
|
||||
public async Task SoftDeleteAsync(IEnumerable<Guid> ids, Guid userId)
|
||||
{
|
||||
await ToggleCipherStates(ids, userId, CipherStateAction.SoftDelete);
|
||||
}
|
||||
|
||||
private async Task<DateTime> ToggleCipherStates(IEnumerable<Guid> ids, Guid userId, CipherStateAction action)
|
||||
{
|
||||
static bool FilterDeletedDate(CipherStateAction action, CipherDetails ucd)
|
||||
{
|
||||
return action switch
|
||||
{
|
||||
CipherStateAction.Restore => ucd.DeletedDate != null,
|
||||
CipherStateAction.SoftDelete => ucd.DeletedDate == null,
|
||||
_ => true,
|
||||
};
|
||||
}
|
||||
|
||||
using (var scope = ServiceScopeFactory.CreateScope())
|
||||
{
|
||||
var dbContext = GetDatabaseContext(scope);
|
||||
var userCipherDetailsQuery = new UserCipherDetailsQuery(userId);
|
||||
var cipherEntitiesToCheck = await (dbContext.Ciphers.Where(c => ids.Contains(c.Id))).ToListAsync();
|
||||
var query = from ucd in await (userCipherDetailsQuery.Run(dbContext)).ToListAsync()
|
||||
join c in cipherEntitiesToCheck
|
||||
on ucd.Id equals c.Id
|
||||
where ucd.Edit && FilterDeletedDate(action, ucd)
|
||||
select c;
|
||||
|
||||
var utcNow = DateTime.UtcNow;
|
||||
var cipherIdsToModify = query.Select(c => c.Id);
|
||||
var cipherEntitiesToModify = dbContext.Ciphers.Where(x => cipherIdsToModify.Contains(x.Id));
|
||||
if (action == CipherStateAction.HardDelete)
|
||||
{
|
||||
dbContext.RemoveRange(cipherEntitiesToModify);
|
||||
}
|
||||
else
|
||||
{
|
||||
await cipherEntitiesToModify.ForEachAsync(cipher =>
|
||||
{
|
||||
dbContext.Attach(cipher);
|
||||
cipher.DeletedDate = action == CipherStateAction.Restore ? null : utcNow;
|
||||
cipher.RevisionDate = utcNow;
|
||||
});
|
||||
}
|
||||
|
||||
var orgIds = query
|
||||
.Where(c => c.OrganizationId.HasValue)
|
||||
.GroupBy(c => c.OrganizationId).Select(x => x.Key);
|
||||
|
||||
foreach (var orgId in orgIds)
|
||||
{
|
||||
await OrganizationUpdateStorage(orgId.Value);
|
||||
await dbContext.UserBumpAccountRevisionDateByOrganizationIdAsync(orgId.Value);
|
||||
}
|
||||
if (query.Any(c => c.UserId.HasValue && !string.IsNullOrWhiteSpace(c.Attachments)))
|
||||
{
|
||||
await UserUpdateStorage(userId);
|
||||
}
|
||||
await dbContext.UserBumpAccountRevisionDateAsync(userId);
|
||||
await dbContext.SaveChangesAsync();
|
||||
return utcNow;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task SoftDeleteByIdsOrganizationIdAsync(IEnumerable<Guid> ids, Guid organizationId)
|
||||
{
|
||||
using (var scope = ServiceScopeFactory.CreateScope())
|
||||
{
|
||||
var dbContext = GetDatabaseContext(scope);
|
||||
var utcNow = DateTime.UtcNow;
|
||||
var ciphers = dbContext.Ciphers.Where(c => ids.Contains(c.Id) && c.OrganizationId == organizationId);
|
||||
await ciphers.ForEachAsync(cipher =>
|
||||
{
|
||||
dbContext.Attach(cipher);
|
||||
cipher.DeletedDate = utcNow;
|
||||
cipher.RevisionDate = utcNow;
|
||||
});
|
||||
await OrganizationUpdateStorage(organizationId);
|
||||
await dbContext.UserBumpAccountRevisionDateByOrganizationIdAsync(organizationId);
|
||||
await dbContext.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task UpdateAttachmentAsync(CipherAttachment attachment)
|
||||
{
|
||||
using (var scope = ServiceScopeFactory.CreateScope())
|
||||
{
|
||||
var dbContext = GetDatabaseContext(scope);
|
||||
var cipher = await dbContext.Ciphers.FindAsync(attachment.Id);
|
||||
var attachments = string.IsNullOrWhiteSpace(cipher.Attachments) ?
|
||||
new Dictionary<string, CipherAttachment.MetaData>() :
|
||||
JsonConvert.DeserializeObject<Dictionary<string, CipherAttachment.MetaData>>(cipher.Attachments);
|
||||
var metaData = JsonConvert.DeserializeObject<CipherAttachment.MetaData>(attachment.AttachmentData);
|
||||
attachments[attachment.AttachmentId] = metaData;
|
||||
cipher.Attachments = JsonConvert.SerializeObject(attachments);
|
||||
await dbContext.SaveChangesAsync();
|
||||
|
||||
if (attachment.OrganizationId.HasValue)
|
||||
{
|
||||
await OrganizationUpdateStorage(cipher.OrganizationId.Value);
|
||||
await dbContext.UserBumpAccountRevisionDateByCipherIdAsync(cipher.Id, cipher.OrganizationId.Value);
|
||||
}
|
||||
else if (attachment.UserId.HasValue)
|
||||
{
|
||||
await UserUpdateStorage(attachment.UserId.Value);
|
||||
await dbContext.UserBumpAccountRevisionDateAsync(attachment.UserId.Value);
|
||||
}
|
||||
await dbContext.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task UpdateCiphersAsync(Guid userId, IEnumerable<Core.Entities.Cipher> ciphers)
|
||||
{
|
||||
if (!ciphers.Any())
|
||||
{
|
||||
return;
|
||||
}
|
||||
using (var scope = ServiceScopeFactory.CreateScope())
|
||||
{
|
||||
var dbContext = GetDatabaseContext(scope);
|
||||
var entities = Mapper.Map<List<Cipher>>(ciphers);
|
||||
await dbContext.BulkCopyAsync(base.DefaultBulkCopyOptions, entities);
|
||||
await dbContext.UserBumpAccountRevisionDateAsync(userId);
|
||||
await dbContext.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task UpdatePartialAsync(Guid id, Guid userId, Guid? folderId, bool favorite)
|
||||
{
|
||||
using (var scope = ServiceScopeFactory.CreateScope())
|
||||
{
|
||||
var dbContext = GetDatabaseContext(scope);
|
||||
var cipher = await dbContext.Ciphers.FindAsync(id);
|
||||
|
||||
var foldersJson = JObject.Parse(cipher.Folders);
|
||||
if (foldersJson == null && folderId.HasValue)
|
||||
{
|
||||
foldersJson.Add(userId.ToString(), folderId.Value);
|
||||
}
|
||||
else if (foldersJson != null && folderId.HasValue)
|
||||
{
|
||||
foldersJson[userId] = folderId.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
foldersJson.Remove(userId.ToString());
|
||||
}
|
||||
|
||||
var favoritesJson = JObject.Parse(cipher.Favorites);
|
||||
if (favorite)
|
||||
{
|
||||
favoritesJson.Add(userId.ToString(), favorite);
|
||||
}
|
||||
else
|
||||
{
|
||||
favoritesJson.Remove(userId.ToString());
|
||||
}
|
||||
|
||||
await dbContext.UserBumpAccountRevisionDateAsync(userId);
|
||||
await dbContext.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task UpdateUserKeysAndCiphersAsync(User user, IEnumerable<Core.Entities.Cipher> ciphers, IEnumerable<Core.Entities.Folder> folders, IEnumerable<Core.Entities.Send> sends)
|
||||
{
|
||||
using (var scope = ServiceScopeFactory.CreateScope())
|
||||
{
|
||||
var dbContext = GetDatabaseContext(scope);
|
||||
await UserUpdateKeys(user);
|
||||
var cipherEntities = Mapper.Map<List<Cipher>>(ciphers);
|
||||
await dbContext.BulkCopyAsync(base.DefaultBulkCopyOptions, cipherEntities);
|
||||
var folderEntities = Mapper.Map<List<Folder>>(folders);
|
||||
await dbContext.BulkCopyAsync(base.DefaultBulkCopyOptions, folderEntities);
|
||||
var sendEntities = Mapper.Map<List<Send>>(sends);
|
||||
await dbContext.BulkCopyAsync(base.DefaultBulkCopyOptions, sendEntities);
|
||||
await dbContext.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task UpsertAsync(CipherDetails cipher)
|
||||
{
|
||||
if (cipher.Id.Equals(default))
|
||||
{
|
||||
await CreateAsync(cipher);
|
||||
}
|
||||
else
|
||||
{
|
||||
await ReplaceAsync(cipher);
|
||||
}
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@
|
||||
using Bit.Infrastructure.EntityFramework.Converters;
|
||||
using Bit.Infrastructure.EntityFramework.Models;
|
||||
using Bit.Infrastructure.EntityFramework.SecretsManager.Models;
|
||||
using Bit.Infrastructure.EntityFramework.Vault.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
@ -6,7 +6,7 @@ using Bit.Infrastructure.EntityFramework.Repositories.Queries;
|
||||
using LinqToDB.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Cipher = Bit.Core.Entities.Cipher;
|
||||
using Cipher = Bit.Core.Vault.Entities.Cipher;
|
||||
|
||||
namespace Bit.Infrastructure.EntityFramework.Repositories;
|
||||
|
||||
|
@ -1,38 +0,0 @@
|
||||
using AutoMapper;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Infrastructure.EntityFramework.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Bit.Infrastructure.EntityFramework.Repositories;
|
||||
|
||||
public class FolderRepository : Repository<Core.Entities.Folder, Folder, Guid>, IFolderRepository
|
||||
{
|
||||
public FolderRepository(IServiceScopeFactory serviceScopeFactory, IMapper mapper)
|
||||
: base(serviceScopeFactory, mapper, (DatabaseContext context) => context.Folders)
|
||||
{ }
|
||||
|
||||
public async Task<Core.Entities.Folder> GetByIdAsync(Guid id, Guid userId)
|
||||
{
|
||||
var folder = await base.GetByIdAsync(id);
|
||||
if (folder == null || folder.UserId != userId)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return folder;
|
||||
}
|
||||
|
||||
public async Task<ICollection<Core.Entities.Folder>> GetManyByUserIdAsync(Guid userId)
|
||||
{
|
||||
using (var scope = ServiceScopeFactory.CreateScope())
|
||||
{
|
||||
var dbContext = GetDatabaseContext(scope);
|
||||
var query = from f in dbContext.Folders
|
||||
where f.UserId == userId
|
||||
select f;
|
||||
var folders = await query.ToListAsync();
|
||||
return Mapper.Map<List<Core.Entities.Folder>>(folders);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
using Bit.Core.Utilities;
|
||||
using Core.Models.Data;
|
||||
|
||||
namespace Bit.Infrastructure.EntityFramework.Repositories.Queries;
|
||||
|
||||
public class CipherDetailsQuery : IQuery<CipherDetails>
|
||||
{
|
||||
private readonly Guid? _userId;
|
||||
private readonly bool _ignoreFolders;
|
||||
public CipherDetailsQuery(Guid? userId, bool ignoreFolders = false)
|
||||
{
|
||||
_userId = userId;
|
||||
_ignoreFolders = ignoreFolders;
|
||||
}
|
||||
public virtual IQueryable<CipherDetails> Run(DatabaseContext dbContext)
|
||||
{
|
||||
var query = from c in dbContext.Ciphers
|
||||
select new CipherDetails
|
||||
{
|
||||
Id = c.Id,
|
||||
UserId = c.UserId,
|
||||
OrganizationId = c.OrganizationId,
|
||||
Type = c.Type,
|
||||
Data = c.Data,
|
||||
Attachments = c.Attachments,
|
||||
CreationDate = c.CreationDate,
|
||||
RevisionDate = c.RevisionDate,
|
||||
DeletedDate = c.DeletedDate,
|
||||
Reprompt = c.Reprompt,
|
||||
Favorite = _userId.HasValue && c.Favorites != null && c.Favorites.ToLowerInvariant().Contains($"\"{_userId}\":true"),
|
||||
FolderId = (_ignoreFolders || !_userId.HasValue || c.Folders == null || !c.Folders.ToLowerInvariant().Contains(_userId.Value.ToString())) ?
|
||||
null :
|
||||
CoreHelpers.LoadClassFromJsonData<Dictionary<Guid, Guid>>(c.Folders)[_userId.Value],
|
||||
};
|
||||
return query;
|
||||
}
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
using Core.Models.Data;
|
||||
|
||||
namespace Bit.Infrastructure.EntityFramework.Repositories.Queries;
|
||||
|
||||
public class CipherOrganizationDetailsReadByIdQuery : IQuery<CipherOrganizationDetails>
|
||||
{
|
||||
private readonly Guid _cipherId;
|
||||
|
||||
public CipherOrganizationDetailsReadByIdQuery(Guid cipherId)
|
||||
{
|
||||
_cipherId = cipherId;
|
||||
}
|
||||
|
||||
public virtual IQueryable<CipherOrganizationDetails> Run(DatabaseContext dbContext)
|
||||
{
|
||||
var query = from c in dbContext.Ciphers
|
||||
join o in dbContext.Organizations
|
||||
on c.OrganizationId equals o.Id into o_g
|
||||
from o in o_g.DefaultIfEmpty()
|
||||
where c.Id == _cipherId
|
||||
select new CipherOrganizationDetails
|
||||
{
|
||||
Id = c.Id,
|
||||
UserId = c.UserId,
|
||||
OrganizationId = c.OrganizationId,
|
||||
Type = c.Type,
|
||||
Data = c.Data,
|
||||
Favorites = c.Favorites,
|
||||
Folders = c.Folders,
|
||||
Attachments = c.Attachments,
|
||||
CreationDate = c.CreationDate,
|
||||
RevisionDate = c.RevisionDate,
|
||||
DeletedDate = c.DeletedDate,
|
||||
OrganizationUseTotp = o.UseTotp,
|
||||
};
|
||||
return query;
|
||||
}
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
using Core.Models.Data;
|
||||
|
||||
namespace Bit.Infrastructure.EntityFramework.Repositories.Queries;
|
||||
|
||||
public class CipherOrganizationDetailsReadByOrganizationIdQuery : IQuery<CipherOrganizationDetails>
|
||||
{
|
||||
private readonly Guid _organizationId;
|
||||
|
||||
public CipherOrganizationDetailsReadByOrganizationIdQuery(Guid organizationId)
|
||||
{
|
||||
_organizationId = organizationId;
|
||||
}
|
||||
public virtual IQueryable<CipherOrganizationDetails> Run(DatabaseContext dbContext)
|
||||
{
|
||||
var query = from c in dbContext.Ciphers
|
||||
join o in dbContext.Organizations
|
||||
on c.OrganizationId equals o.Id into o_g
|
||||
from o in o_g.DefaultIfEmpty()
|
||||
where c.OrganizationId == _organizationId
|
||||
select new CipherOrganizationDetails
|
||||
{
|
||||
Id = c.Id,
|
||||
UserId = c.UserId,
|
||||
OrganizationId = c.OrganizationId,
|
||||
Type = c.Type,
|
||||
Data = c.Data,
|
||||
Favorites = c.Favorites,
|
||||
Folders = c.Folders,
|
||||
Attachments = c.Attachments,
|
||||
CreationDate = c.CreationDate,
|
||||
RevisionDate = c.RevisionDate,
|
||||
DeletedDate = c.DeletedDate,
|
||||
OrganizationUseTotp = o.UseTotp,
|
||||
};
|
||||
return query;
|
||||
}
|
||||
}
|
@ -1,68 +0,0 @@
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Infrastructure.EntityFramework.Models;
|
||||
|
||||
namespace Bit.Infrastructure.EntityFramework.Repositories.Queries;
|
||||
|
||||
public class CipherReadCanEditByIdUserIdQuery : IQuery<Cipher>
|
||||
{
|
||||
private readonly Guid _userId;
|
||||
private readonly Guid _cipherId;
|
||||
|
||||
public CipherReadCanEditByIdUserIdQuery(Guid userId, Guid cipherId)
|
||||
{
|
||||
_userId = userId;
|
||||
_cipherId = cipherId;
|
||||
}
|
||||
|
||||
public virtual IQueryable<Cipher> Run(DatabaseContext dbContext)
|
||||
{
|
||||
var query = from c in dbContext.Ciphers
|
||||
|
||||
join o in dbContext.Organizations
|
||||
on new { c.UserId, c.OrganizationId } equals
|
||||
new { UserId = (Guid?)null, OrganizationId = (Guid?)o.Id } into o_g
|
||||
from o in o_g.DefaultIfEmpty()
|
||||
|
||||
join ou in dbContext.OrganizationUsers
|
||||
on new { OrganizationId = o.Id, UserId = (Guid?)_userId } equals
|
||||
new { ou.OrganizationId, ou.UserId } into ou_g
|
||||
from ou in ou_g.DefaultIfEmpty()
|
||||
|
||||
join cc in dbContext.CollectionCiphers
|
||||
on new { c.UserId, ou.AccessAll, CipherId = c.Id } equals
|
||||
new { UserId = (Guid?)null, AccessAll = false, cc.CipherId } into cc_g
|
||||
from cc in cc_g.DefaultIfEmpty()
|
||||
|
||||
join cu in dbContext.CollectionUsers
|
||||
on new { cc.CollectionId, OrganizationUserId = ou.Id } equals
|
||||
new { cu.CollectionId, cu.OrganizationUserId } into cu_g
|
||||
from cu in cu_g.DefaultIfEmpty()
|
||||
|
||||
join gu in dbContext.GroupUsers
|
||||
on new { c.UserId, CollectionId = (Guid?)cu.CollectionId, ou.AccessAll, OrganizationUserId = ou.Id } equals
|
||||
new { UserId = (Guid?)null, CollectionId = (Guid?)null, AccessAll = false, gu.OrganizationUserId } into gu_g
|
||||
from gu in gu_g.DefaultIfEmpty()
|
||||
|
||||
join g in dbContext.Groups
|
||||
on gu.GroupId equals g.Id into g_g
|
||||
from g in g_g.DefaultIfEmpty()
|
||||
|
||||
join cg in dbContext.CollectionGroups
|
||||
on new { g.AccessAll, cc.CollectionId, gu.GroupId } equals
|
||||
new { AccessAll = false, cg.CollectionId, cg.GroupId } into cg_g
|
||||
from cg in cg_g.DefaultIfEmpty()
|
||||
|
||||
where
|
||||
c.Id == _cipherId &&
|
||||
(
|
||||
c.UserId == _userId ||
|
||||
(
|
||||
!c.UserId.HasValue && ou.Status == OrganizationUserStatusType.Confirmed && o.Enabled &&
|
||||
(ou.AccessAll || cu.CollectionId != null || g.AccessAll || cg.CollectionId != null)
|
||||
)
|
||||
) &&
|
||||
(c.UserId.HasValue || ou.AccessAll || !cu.ReadOnly || g.AccessAll || !cg.ReadOnly)
|
||||
select c;
|
||||
return query;
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Models.Data;
|
||||
using Bit.Core.Models.Data;
|
||||
using Bit.Core.Vault.Entities;
|
||||
using Event = Bit.Infrastructure.EntityFramework.Models.Event;
|
||||
|
||||
namespace Bit.Infrastructure.EntityFramework.Repositories.Queries;
|
||||
|
@ -1,6 +1,7 @@
|
||||
using System.Text.Json;
|
||||
using Bit.Core.Enums;
|
||||
using Core.Models.Data;
|
||||
using Bit.Core.Vault.Models.Data;
|
||||
using Bit.Infrastructure.EntityFramework.Vault.Models;
|
||||
|
||||
namespace Bit.Infrastructure.EntityFramework.Repositories.Queries;
|
||||
|
||||
@ -76,7 +77,7 @@ public class UserCipherDetailsQuery : IQuery<CipherDetails>
|
||||
return union;
|
||||
}
|
||||
|
||||
private static Guid? GetFolderId(Guid? userId, Models.Cipher cipher)
|
||||
private static Guid? GetFolderId(Guid? userId, Cipher cipher)
|
||||
{
|
||||
if (userId.HasValue && !string.IsNullOrWhiteSpace(cipher.Folders))
|
||||
{
|
||||
|
Reference in New Issue
Block a user