mirror of
https://github.com/bitwarden/server.git
synced 2025-07-03 09:02:48 -05:00
user can edit responses and cipher partial updates
This commit is contained in:
11
src/Core/Models/Api/Request/CipherPartialRequestModel.cs
Normal file
11
src/Core/Models/Api/Request/CipherPartialRequestModel.cs
Normal file
@ -0,0 +1,11 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Bit.Core.Models.Api
|
||||
{
|
||||
public class CipherPartialRequestModel
|
||||
{
|
||||
[StringLength(36)]
|
||||
public string FolderId { get; set; }
|
||||
public bool Favorite { get; set; }
|
||||
}
|
||||
}
|
@ -43,4 +43,15 @@ namespace Bit.Core.Models.Api
|
||||
public string Notes { get; set; }
|
||||
public DateTime RevisionDate { get; set; }
|
||||
}
|
||||
|
||||
public class LoginDetailsResponseModel : LoginResponseModel
|
||||
{
|
||||
public LoginDetailsResponseModel(CipherFullDetails cipher)
|
||||
: base(cipher, "loginDetails")
|
||||
{
|
||||
Edit = cipher.Edit;
|
||||
}
|
||||
|
||||
public bool Edit { get; set; }
|
||||
}
|
||||
}
|
||||
|
7
src/Core/Models/Data/CipherFullDetails.cs
Normal file
7
src/Core/Models/Data/CipherFullDetails.cs
Normal file
@ -0,0 +1,7 @@
|
||||
namespace Core.Models.Data
|
||||
{
|
||||
public class CipherFullDetails : CipherDetails
|
||||
{
|
||||
public bool Edit { get; set; }
|
||||
}
|
||||
}
|
@ -9,6 +9,7 @@ namespace Bit.Core.Repositories
|
||||
public interface ICipherRepository : IRepository<Cipher, Guid>
|
||||
{
|
||||
Task<CipherDetails> GetByIdAsync(Guid id, Guid userId);
|
||||
Task<CipherFullDetails> GetFullDetailsByIdAsync(Guid id, Guid userId);
|
||||
Task<ICollection<CipherDetails>> GetManyByUserIdAsync(Guid userId);
|
||||
Task<ICollection<CipherDetails>> GetManyByUserIdHasSubvaultsAsync(Guid userId);
|
||||
Task<ICollection<CipherDetails>> GetManyByTypeAndUserIdAsync(Enums.CipherType type, Guid userId);
|
||||
@ -18,6 +19,7 @@ namespace Bit.Core.Repositories
|
||||
Task ReplaceAsync(CipherDetails cipher);
|
||||
Task UpsertAsync(CipherDetails cipher);
|
||||
Task ReplaceAsync(Cipher obj, IEnumerable<Guid> subvaultIds);
|
||||
Task UpdatePartialAsync(Guid id, Guid userId, Guid? folderId, bool favorite);
|
||||
Task UpdateUserEmailPasswordAndCiphersAsync(User user, IEnumerable<Cipher> ciphers);
|
||||
Task CreateAsync(IEnumerable<Cipher> ciphers);
|
||||
}
|
||||
|
@ -12,6 +12,6 @@ namespace Bit.Core.Repositories
|
||||
Task<ICollection<SubvaultUserDetails>> GetManyDetailsByUserIdAsync(Guid userId);
|
||||
Task<ICollection<SubvaultUserPermissions>> GetPermissionsByUserIdAsync(Guid userId, IEnumerable<Guid> subvaultIds,
|
||||
Guid organizationId);
|
||||
Task<bool> GetIsAdminByUserIdCipherIdAsync(Guid userId, Guid cipherId);
|
||||
Task<bool> GetCanEditByUserIdCipherIdAsync(Guid userId, Guid cipherId);
|
||||
}
|
||||
}
|
||||
|
@ -36,6 +36,19 @@ namespace Bit.Core.Repositories.SqlServer
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<CipherFullDetails> GetFullDetailsByIdAsync(Guid id, Guid userId)
|
||||
{
|
||||
using(var connection = new SqlConnection(ConnectionString))
|
||||
{
|
||||
var results = await connection.QueryAsync<CipherFullDetails>(
|
||||
$"[{Schema}].[CipherFullDetails_ReadByIdUserId]",
|
||||
new { Id = id, UserId = userId },
|
||||
commandType: CommandType.StoredProcedure);
|
||||
|
||||
return results.FirstOrDefault();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ICollection<CipherDetails>> GetManyByUserIdAsync(Guid userId)
|
||||
{
|
||||
using(var connection = new SqlConnection(ConnectionString))
|
||||
@ -149,6 +162,17 @@ namespace Bit.Core.Repositories.SqlServer
|
||||
}
|
||||
}
|
||||
|
||||
public async Task UpdatePartialAsync(Guid id, Guid userId, Guid? folderId, bool favorite)
|
||||
{
|
||||
using(var connection = new SqlConnection(ConnectionString))
|
||||
{
|
||||
var results = await connection.ExecuteAsync(
|
||||
$"[{Schema}].[Cipher_UpdatePartial]",
|
||||
new { Id = id, UserId = userId, FolderId = folderId, Favorite = favorite },
|
||||
commandType: CommandType.StoredProcedure);
|
||||
}
|
||||
}
|
||||
|
||||
public Task UpdateUserEmailPasswordAndCiphersAsync(User user, IEnumerable<Cipher> ciphers)
|
||||
{
|
||||
if(ciphers.Count() == 0)
|
||||
|
@ -61,12 +61,12 @@ namespace Bit.Core.Repositories.SqlServer
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> GetIsAdminByUserIdCipherIdAsync(Guid userId, Guid cipherId)
|
||||
public async Task<bool> GetCanEditByUserIdCipherIdAsync(Guid userId, Guid cipherId)
|
||||
{
|
||||
using(var connection = new SqlConnection(ConnectionString))
|
||||
{
|
||||
var result = await connection.QueryFirstOrDefaultAsync<bool>(
|
||||
$"[{Schema}].[SubvaultUser_ReadIsAdminByCipherIdUserId]",
|
||||
$"[{Schema}].[SubvaultUser_ReadCanEditByCipherIdUserId]",
|
||||
new { UserId = userId, CipherId = cipherId },
|
||||
commandType: CommandType.StoredProcedure);
|
||||
|
||||
|
@ -9,6 +9,7 @@ namespace Bit.Core.Services
|
||||
public interface ICipherService
|
||||
{
|
||||
Task SaveAsync(CipherDetails cipher, Guid savingUserId);
|
||||
Task UpdatePartialAsync(Guid cipherId, Guid savingUserId, Guid? folderId, bool favorite);
|
||||
Task DeleteAsync(CipherDetails cipher, Guid deletingUserId);
|
||||
Task SaveFolderAsync(Folder folder);
|
||||
Task DeleteFolderAsync(Folder folder);
|
||||
|
@ -39,7 +39,7 @@ namespace Bit.Core.Services
|
||||
|
||||
public async Task SaveAsync(CipherDetails cipher, Guid savingUserId)
|
||||
{
|
||||
if(!(await UserHasAdminRights(cipher, savingUserId)))
|
||||
if(!(await UserCanEditAsync(cipher, savingUserId)))
|
||||
{
|
||||
throw new BadRequestException("Not an admin.");
|
||||
}
|
||||
@ -62,9 +62,19 @@ namespace Bit.Core.Services
|
||||
}
|
||||
}
|
||||
|
||||
public async Task UpdatePartialAsync(Guid cipherId, Guid savingUserId, Guid? folderId, bool favorite)
|
||||
{
|
||||
if(!(await UserCanPartialEditAsync(cipherId, savingUserId)))
|
||||
{
|
||||
throw new BadRequestException("Cannot edit.");
|
||||
}
|
||||
|
||||
await _cipherRepository.UpdatePartialAsync(cipherId, savingUserId, folderId, favorite);
|
||||
}
|
||||
|
||||
public async Task DeleteAsync(CipherDetails cipher, Guid deletingUserId)
|
||||
{
|
||||
if(!(await UserHasAdminRights(cipher, deletingUserId)))
|
||||
if(!(await UserCanEditAsync(cipher, deletingUserId)))
|
||||
{
|
||||
throw new BadRequestException("Not an admin.");
|
||||
}
|
||||
@ -163,14 +173,22 @@ namespace Bit.Core.Services
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<bool> UserHasAdminRights(CipherDetails cipher, Guid userId)
|
||||
private async Task<bool> UserCanEditAsync(CipherDetails cipher, Guid userId)
|
||||
{
|
||||
if(!cipher.OrganizationId.HasValue && cipher.UserId.HasValue && cipher.UserId.Value == userId)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return await _subvaultUserRepository.GetIsAdminByUserIdCipherIdAsync(userId, cipher.Id);
|
||||
return await _subvaultUserRepository.GetCanEditByUserIdCipherIdAsync(userId, cipher.Id);
|
||||
}
|
||||
|
||||
private Task<bool> UserCanPartialEditAsync(Guid cipherId, Guid userId)
|
||||
{
|
||||
// TODO: implement
|
||||
|
||||
return Task.FromResult(true);
|
||||
//return await _subvaultUserRepository.GetCanEditByUserIdCipherIdAsync(userId, cipherId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user