1
0
mirror of https://github.com/bitwarden/server.git synced 2025-05-28 23:04:50 -05:00

cipher details create/update

This commit is contained in:
Kyle Spearrin 2017-03-18 23:41:46 -04:00
parent 3d5437e238
commit 26b553c248
16 changed files with 159 additions and 44 deletions

View File

@ -65,7 +65,7 @@ namespace Bit.Api.Controllers
{ {
var userId = _userService.GetProperUserId(User).Value; var userId = _userService.GetProperUserId(User).Value;
var folderCiphers = model.Folders.Select(f => f.ToFolder(userId)).ToList(); var folderCiphers = model.Folders.Select(f => f.ToFolder(userId)).ToList();
var otherCiphers = model.Logins.Select(s => s.ToCipher(userId)).ToList(); var otherCiphers = model.Logins.Select(s => s.ToCipherDetails(userId)).ToList();
await _cipherService.ImportCiphersAsync( await _cipherService.ImportCiphersAsync(
folderCiphers, folderCiphers,

View File

@ -58,7 +58,7 @@ namespace Bit.Api.Controllers
public async Task<LoginResponseModel> Post([FromBody]LoginRequestModel model) public async Task<LoginResponseModel> Post([FromBody]LoginRequestModel model)
{ {
var userId = _userService.GetProperUserId(User).Value; var userId = _userService.GetProperUserId(User).Value;
var login = model.ToCipher(userId); var login = model.ToCipherDetails(userId);
await _cipherService.SaveAsync(login); await _cipherService.SaveAsync(login);
var response = new LoginResponseModel(login); var response = new LoginResponseModel(login);
@ -76,7 +76,7 @@ namespace Bit.Api.Controllers
throw new NotFoundException(); throw new NotFoundException();
} }
await _cipherService.SaveAsync(model.ToCipher(login)); await _cipherService.SaveAsync(model.ToCipherDetails(login));
var response = new LoginResponseModel(login); var response = new LoginResponseModel(login);
return response; return response;

View File

@ -1,7 +1,6 @@
using System; using System;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using Bit.Core.Utilities; using Bit.Core.Utilities;
using Bit.Core.Models.Table;
using Newtonsoft.Json; using Newtonsoft.Json;
using Core.Models.Data; using Core.Models.Data;
@ -29,15 +28,15 @@ namespace Bit.Core.Models.Api
[StringLength(10000)] [StringLength(10000)]
public string Notes { get; set; } public string Notes { get; set; }
public CipherDetails ToCipher(Guid userId) public CipherDetails ToCipherDetails(Guid userId)
{ {
return ToCipher(new CipherDetails return ToCipherDetails(new CipherDetails
{ {
UserId = userId UserId = userId
}); });
} }
public CipherDetails ToCipher(CipherDetails existingLogin) public CipherDetails ToCipherDetails(CipherDetails existingLogin)
{ {
existingLogin.FolderId = string.IsNullOrWhiteSpace(FolderId) ? null : (Guid?)new Guid(FolderId); existingLogin.FolderId = string.IsNullOrWhiteSpace(FolderId) ? null : (Guid?)new Guid(FolderId);
existingLogin.Favorite = Favorite; existingLogin.Favorite = Favorite;

View File

@ -20,7 +20,7 @@ namespace Bit.Core.Models.Api
throw new ArgumentNullException(nameof(deletedIds)); throw new ArgumentNullException(nameof(deletedIds));
} }
Revised = revisedCiphers.Select(c => new CipherResponseModel(c)); //Revised = revisedCiphers.Select(c => new CipherResponseModel(c));
Deleted = deletedIds.Select(id => id.ToString()); Deleted = deletedIds.Select(id => id.ToString());
} }

View File

@ -1,32 +1,10 @@
using System; using System;
using Bit.Core.Models.Table;
using Core.Models.Data; using Core.Models.Data;
namespace Bit.Core.Models.Api namespace Bit.Core.Models.Api
{ {
public class CipherResponseModel : ResponseModel public class CipherResponseModel : ResponseModel
{ {
public CipherResponseModel(Cipher cipher, string obj = "cipher")
: base(obj)
{
if(cipher == null)
{
throw new ArgumentNullException(nameof(cipher));
}
Id = cipher.Id.ToString();
Type = cipher.Type;
RevisionDate = cipher.RevisionDate;
switch(cipher.Type)
{
case Enums.CipherType.Login:
Data = new LoginDataModel(cipher);
break;
default:
throw new ArgumentException("Unsupported " + nameof(Type) + ".");
}
}
public CipherResponseModel(CipherDetails cipher, string obj = "cipher") public CipherResponseModel(CipherDetails cipher, string obj = "cipher")
: base(obj) : base(obj)
{ {
@ -38,6 +16,8 @@ namespace Bit.Core.Models.Api
Id = cipher.Id.ToString(); Id = cipher.Id.ToString();
Type = cipher.Type; Type = cipher.Type;
RevisionDate = cipher.RevisionDate; RevisionDate = cipher.RevisionDate;
FolderId = cipher.FolderId?.ToString();
Favorite = cipher.Favorite;
switch(cipher.Type) switch(cipher.Type)
{ {

View File

@ -1,6 +1,5 @@
using System; using System;
using Core.Models.Data; using Core.Models.Data;
using Bit.Core.Models.Table;
namespace Bit.Core.Models.Api namespace Bit.Core.Models.Api
{ {
@ -41,8 +40,5 @@ namespace Bit.Core.Models.Api
public string Password { get; set; } public string Password { get; set; }
public string Notes { get; set; } public string Notes { get; set; }
public DateTime RevisionDate { get; set; } public DateTime RevisionDate { get; set; }
// Expandables
public FolderResponseModel Folder { get; set; }
} }
} }

View File

@ -13,6 +13,9 @@ namespace Bit.Core.Repositories
Task<ICollection<CipherDetails>> GetManyByTypeAndUserIdAsync(Enums.CipherType type, Guid userId); Task<ICollection<CipherDetails>> GetManyByTypeAndUserIdAsync(Enums.CipherType type, Guid userId);
Task<Tuple<ICollection<CipherDetails>, ICollection<Guid>>> GetManySinceRevisionDateAndUserIdWithDeleteHistoryAsync( Task<Tuple<ICollection<CipherDetails>, ICollection<Guid>>> GetManySinceRevisionDateAndUserIdWithDeleteHistoryAsync(
DateTime sinceRevisionDate, Guid userId); DateTime sinceRevisionDate, Guid userId);
Task CreateAsync(CipherDetails cipher);
Task ReplaceAsync(CipherDetails cipher);
Task UpsertAsync(CipherDetails cipher);
Task UpdateUserEmailPasswordAndCiphersAsync(User user, IEnumerable<Cipher> ciphers); Task UpdateUserEmailPasswordAndCiphersAsync(User user, IEnumerable<Cipher> ciphers);
Task CreateAsync(IEnumerable<Cipher> ciphers); Task CreateAsync(IEnumerable<Cipher> ciphers);
} }

View File

@ -85,6 +85,41 @@ namespace Bit.Core.Repositories.SqlServer
} }
} }
public async Task CreateAsync(CipherDetails cipher)
{
cipher.SetNewId();
using(var connection = new SqlConnection(ConnectionString))
{
var results = await connection.ExecuteAsync(
$"[{Schema}].[CipherDetails_Create]",
cipher,
commandType: CommandType.StoredProcedure);
}
}
public async Task ReplaceAsync(CipherDetails obj)
{
using(var connection = new SqlConnection(ConnectionString))
{
var results = await connection.ExecuteAsync(
$"[{Schema}].[CipherDetails_Update]",
obj,
commandType: CommandType.StoredProcedure);
}
}
public async Task UpsertAsync(CipherDetails cipher)
{
if(cipher.Id.Equals(default(Guid)))
{
await CreateAsync(cipher);
}
else
{
await ReplaceAsync(cipher);
}
}
public Task UpdateUserEmailPasswordAndCiphersAsync(User user, IEnumerable<Cipher> ciphers) public Task UpdateUserEmailPasswordAndCiphersAsync(User user, IEnumerable<Cipher> ciphers)
{ {
if(ciphers.Count() == 0) if(ciphers.Count() == 0)

View File

@ -7,7 +7,7 @@ namespace Bit.Core.Services
{ {
public interface ICipherService public interface ICipherService
{ {
Task SaveAsync(Cipher cipher); Task SaveAsync(CipherDetails cipher);
Task DeleteAsync(Cipher cipher); Task DeleteAsync(Cipher cipher);
Task SaveFolderAsync(Folder folder); Task SaveFolderAsync(Folder folder);
Task DeleteFolderAsync(Folder folder); Task DeleteFolderAsync(Folder folder);

View File

@ -27,7 +27,7 @@ namespace Bit.Core.Services
_pushService = pushService; _pushService = pushService;
} }
public async Task SaveAsync(Cipher cipher) public async Task SaveAsync(CipherDetails cipher)
{ {
if(cipher.Id == default(Guid)) if(cipher.Id == default(Guid))
{ {

View File

@ -165,5 +165,8 @@
<Build Include="dbo\Stored Procedures\CipherDetails_ReadById.sql" /> <Build Include="dbo\Stored Procedures\CipherDetails_ReadById.sql" />
<Build Include="dbo\Views\FolderView.sql" /> <Build Include="dbo\Views\FolderView.sql" />
<Build Include="dbo\Stored Procedures\Folder_ReadByUserId.sql" /> <Build Include="dbo\Stored Procedures\Folder_ReadByUserId.sql" />
<Build Include="dbo\Stored Procedures\CipherDetails_Update.sql" />
<Build Include="dbo\Stored Procedures\CipherDetails_Create.sql" />
<Build Include="dbo\Stored Procedures\FolderCipher_DeleteByUserId.sql" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -0,0 +1,45 @@
CREATE PROCEDURE [dbo].[CipherDetails_Create]
@Id UNIQUEIDENTIFIER,
@UserId UNIQUEIDENTIFIER,
@OrganizationId UNIQUEIDENTIFIER,
@Type TINYINT,
@Data NVARCHAR(MAX),
@CreationDate DATETIME2(7),
@RevisionDate DATETIME2(7),
@FolderId UNIQUEIDENTIFIER,
@Favorite BIT
AS
BEGIN
SET NOCOUNT ON
INSERT INTO [dbo].[Cipher]
(
[Id],
[UserId],
[OrganizationId],
[Type],
[Data],
[CreationDate],
[RevisionDate]
)
VALUES
(
@Id,
@UserId,
@OrganizationId,
@Type,
@Data,
@CreationDate,
@RevisionDate
)
IF @FolderId IS NOT NULL
BEGIN
EXEC [dbo].[FolderCipher_Create] @FolderId, @Id
END
IF @Favorite = 1
BEGIN
EXEC [dbo].[Favorite_Create] @UserId, @Id
END
END

View File

@ -0,0 +1,44 @@
CREATE PROCEDURE [dbo].[CipherDetails_Update]
@Id UNIQUEIDENTIFIER,
@UserId UNIQUEIDENTIFIER,
@OrganizationId UNIQUEIDENTIFIER,
@Type TINYINT,
@Data NVARCHAR(MAX),
@CreationDate DATETIME2(7),
@RevisionDate DATETIME2(7),
@FolderId UNIQUEIDENTIFIER,
@Favorite BIT
AS
BEGIN
SET NOCOUNT ON
UPDATE
[dbo].[Cipher]
SET
[UserId] = @UserId,
[OrganizationId] = @OrganizationId,
[Type] = @Type,
[Data] = @Data,
[CreationDate] = @CreationDate,
[RevisionDate] = @RevisionDate
WHERE
[Id] = @Id
IF @FolderId IS NULL
BEGIN
EXEC [dbo].[FolderCipher_DeleteByUserId] @UserId, @Id
END
ELSE IF (SELECT COUNT(1) FROM [dbo].[FolderCipher] WHERE [FolderId] = @FolderId AND [CipherId] = @Id) = 0
BEGIN
EXEC [dbo].[FolderCipher_Create] @FolderId, @Id
END
IF @Favorite = 0
BEGIN
EXEC [dbo].[Favorite_Delete] @UserId, @Id
END
ELSE IF (SELECT COUNT(1) FROM [dbo].[Favorite] WHERE [UserId] = @UserId AND [CipherId] = @Id) = 0
BEGIN
EXEC [dbo].[Favorite_Create] @UserId, @Id
END
END

View File

@ -5,10 +5,7 @@
@Type TINYINT, @Type TINYINT,
@Data NVARCHAR(MAX), @Data NVARCHAR(MAX),
@CreationDate DATETIME2(7), @CreationDate DATETIME2(7),
@RevisionDate DATETIME2(7), @RevisionDate DATETIME2(7)
-- Extra, unused props from cipher details model since dapper maps all child properties too. This is kind of a hack.
@FolderId UNIQUEIDENTIFIER,
@Favorite BIT
AS AS
BEGIN BEGIN
SET NOCOUNT ON SET NOCOUNT ON

View File

@ -5,10 +5,7 @@
@Type TINYINT, @Type TINYINT,
@Data NVARCHAR(MAX), @Data NVARCHAR(MAX),
@CreationDate DATETIME2(7), @CreationDate DATETIME2(7),
@RevisionDate DATETIME2(7), @RevisionDate DATETIME2(7)
-- Extra, unused props from cipher details model since dapper maps all child properties too. This is kind of a hack.
@FolderId UNIQUEIDENTIFIER,
@Favorite BIT
AS AS
BEGIN BEGIN
SET NOCOUNT ON SET NOCOUNT ON

View File

@ -0,0 +1,16 @@
CREATE PROCEDURE [dbo].[FolderCipher_DeleteByUserId]
@UserId UNIQUEIDENTIFIER,
@CipherId UNIQUEIDENTIFIER
AS
BEGIN
SET NOCOUNT ON
DELETE FC
FROM
[dbo].[FolderCipher] FC
INNER JOIN
[dbo].[Folder] F ON F.[Id] = FC.[FolderId]
WHERE
F.[UserId] = @UserId
AND [CipherId] = @CipherId
END