1
0
mirror of https://github.com/bitwarden/server.git synced 2025-07-02 16:42:50 -05:00

apis for creating ciphers with org & collections

This commit is contained in:
Kyle Spearrin
2018-10-19 12:07:31 -04:00
parent e3f94bb67b
commit 96b492fa07
12 changed files with 437 additions and 61 deletions

View File

@ -36,13 +36,14 @@ namespace Bit.Core.Models.Api
public CipherIdentityModel Identity { get; set; }
public CipherSecureNoteModel SecureNote { get; set; }
public CipherDetails ToCipherDetails(Guid userId)
public CipherDetails ToCipherDetails(Guid userId, bool allowOrgIdSet = true)
{
var hasOrgId = !string.IsNullOrWhiteSpace(OrganizationId);
var cipher = new CipherDetails
{
Type = Type,
UserId = string.IsNullOrWhiteSpace(OrganizationId) ? (Guid?)userId : null,
OrganizationId = null,
UserId = !hasOrgId ? (Guid?)userId : null,
OrganizationId = allowOrgIdSet && hasOrgId ? new Guid(OrganizationId) : (Guid?)null,
Edit = true
};
ToCipherDetails(cipher);
@ -142,6 +143,22 @@ namespace Bit.Core.Models.Api
}
}
public class CipherCreateRequestModel : IValidatableObject
{
public IEnumerable<Guid> CollectionIds { get; set; }
[Required]
public CipherRequestModel Cipher { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if(!string.IsNullOrWhiteSpace(Cipher.OrganizationId) && (!CollectionIds?.Any() ?? true))
{
yield return new ValidationResult("You must select at least one collection.",
new string[] { nameof(CollectionIds) });
}
}
}
public class CipherShareRequestModel : IValidatableObject
{
[Required]

View File

@ -14,7 +14,9 @@ namespace Bit.Core.Repositories
Task<bool> GetCanEditByIdAsync(Guid userId, Guid cipherId);
Task<ICollection<CipherDetails>> GetManyByUserIdAsync(Guid userId, bool withOrganizations = true);
Task<ICollection<Cipher>> GetManyByOrganizationIdAsync(Guid organizationId);
Task CreateAsync(Cipher cipher, IEnumerable<Guid> collectionIds);
Task CreateAsync(CipherDetails cipher);
Task CreateAsync(CipherDetails cipher, IEnumerable<Guid> collectionIds);
Task ReplaceAsync(CipherDetails cipher);
Task UpsertAsync(CipherDetails cipher);
Task<bool> ReplaceAsync(Cipher obj, IEnumerable<Guid> collectionIds);

View File

@ -101,6 +101,21 @@ namespace Bit.Core.Repositories.SqlServer
}
}
public async Task CreateAsync(Cipher cipher, IEnumerable<Guid> collectionIds)
{
cipher.SetNewId();
var objWithCollections = JsonConvert.DeserializeObject<CipherWithCollections>(
JsonConvert.SerializeObject(cipher));
objWithCollections.CollectionIds = collectionIds.ToGuidIdArrayTVP();
using(var connection = new SqlConnection(ConnectionString))
{
var results = await connection.ExecuteAsync(
$"[{Schema}].[Cipher_CreateWithCollections]",
objWithCollections,
commandType: CommandType.StoredProcedure);
}
}
public async Task CreateAsync(CipherDetails cipher)
{
cipher.SetNewId();
@ -113,6 +128,21 @@ namespace Bit.Core.Repositories.SqlServer
}
}
public async Task CreateAsync(CipherDetails cipher, IEnumerable<Guid> collectionIds)
{
cipher.SetNewId();
var objWithCollections = JsonConvert.DeserializeObject<CipherDetailsWithCollections>(
JsonConvert.SerializeObject(cipher));
objWithCollections.CollectionIds = collectionIds.ToGuidIdArrayTVP();
using(var connection = new SqlConnection(ConnectionString))
{
var results = await connection.ExecuteAsync(
$"[{Schema}].[CipherDetails_CreateWithCollections]",
objWithCollections,
commandType: CommandType.StoredProcedure);
}
}
public async Task ReplaceAsync(CipherDetails obj)
{
using(var connection = new SqlConnection(ConnectionString))
@ -715,6 +745,11 @@ namespace Bit.Core.Repositories.SqlServer
return collectionCiphersTable;
}
public class CipherDetailsWithCollections : CipherDetails
{
public DataTable CollectionIds { get; set; }
}
public class CipherWithCollections : Cipher
{
public DataTable CollectionIds { get; set; }

View File

@ -9,8 +9,8 @@ namespace Bit.Core.Services
{
public interface ICipherService
{
Task SaveAsync(Cipher cipher, Guid savingUserId, bool orgAdmin = false);
Task SaveDetailsAsync(CipherDetails cipher, Guid savingUserId);
Task SaveAsync(Cipher cipher, Guid savingUserId, IEnumerable<Guid> collectionIds = null, bool skipPermissionCheck = false);
Task SaveDetailsAsync(CipherDetails cipher, Guid savingUserId, IEnumerable<Guid> collectionIds = null, bool skipPermissionCheck = false);
Task CreateAttachmentAsync(Cipher cipher, Stream stream, string fileName, long requestLength, Guid savingUserId,
bool orgAdmin = false);
Task CreateAttachmentShareAsync(Cipher cipher, Stream stream, string fileName, long requestLength, string attachmentId,

View File

@ -55,16 +55,24 @@ namespace Bit.Core.Services
_globalSettings = globalSettings;
}
public async Task SaveAsync(Cipher cipher, Guid savingUserId, bool orgAdmin = false)
public async Task SaveAsync(Cipher cipher, Guid savingUserId, IEnumerable<Guid> collectionIds = null,
bool skipPermissionCheck = false)
{
if(!orgAdmin && !(await UserCanEditAsync(cipher, savingUserId)))
if(!skipPermissionCheck && !(await UserCanEditAsync(cipher, savingUserId)))
{
throw new BadRequestException("You do not have permissions to edit this.");
}
if(cipher.Id == default(Guid))
{
await _cipherRepository.CreateAsync(cipher);
if(cipher.OrganizationId.HasValue && collectionIds != null)
{
await _cipherRepository.CreateAsync(cipher, collectionIds);
}
else
{
await _cipherRepository.CreateAsync(cipher);
}
await _eventService.LogCipherEventAsync(cipher, Enums.EventType.Cipher_Created);
// push
@ -72,6 +80,10 @@ namespace Bit.Core.Services
}
else
{
if(collectionIds != null)
{
throw new ArgumentException("Cannot create cipher with collection ids at the same time.");
}
cipher.RevisionDate = DateTime.UtcNow;
await _cipherRepository.ReplaceAsync(cipher);
await _eventService.LogCipherEventAsync(cipher, Enums.EventType.Cipher_Updated);
@ -81,9 +93,10 @@ namespace Bit.Core.Services
}
}
public async Task SaveDetailsAsync(CipherDetails cipher, Guid savingUserId)
public async Task SaveDetailsAsync(CipherDetails cipher, Guid savingUserId,
IEnumerable<Guid> collectionIds = null, bool skipPermissionCheck = false)
{
if(!(await UserCanEditAsync(cipher, savingUserId)))
if(!skipPermissionCheck && !(await UserCanEditAsync(cipher, savingUserId)))
{
throw new BadRequestException("You do not have permissions to edit this.");
}
@ -91,7 +104,14 @@ namespace Bit.Core.Services
cipher.UserId = savingUserId;
if(cipher.Id == default(Guid))
{
await _cipherRepository.CreateAsync(cipher);
if(cipher.OrganizationId.HasValue && collectionIds != null)
{
await _cipherRepository.CreateAsync(cipher, collectionIds);
}
else
{
await _cipherRepository.CreateAsync(cipher);
}
await _eventService.LogCipherEventAsync(cipher, Enums.EventType.Cipher_Created);
if(cipher.OrganizationId.HasValue)
@ -105,6 +125,10 @@ namespace Bit.Core.Services
}
else
{
if(collectionIds != null)
{
throw new ArgumentException("Cannot create cipher with collection ids at the same time.");
}
cipher.RevisionDate = DateTime.UtcNow;
await _cipherRepository.ReplaceAsync(cipher);
await _eventService.LogCipherEventAsync(cipher, Enums.EventType.Cipher_Updated);