From 900e71d4dd048ea3bc57b299fc4560a066dc11c4 Mon Sep 17 00:00:00 2001 From: Kyle Spearrin Date: Tue, 21 Feb 2017 22:52:02 -0500 Subject: [PATCH] return share information with cipher API response --- src/Api/Controllers/CiphersController.cs | 15 ++++++----- .../ResourceOwnerPasswordValidator.cs | 11 +++++--- .../Models/Response/CipherResponseModel.cs | 23 +++++++++++++--- src/Core/Enums/SharePermissionType.cs | 8 ++++++ src/Core/Models/Data/CipherShare.cs | 11 ++++++++ src/Core/Repositories/ICipherRepository.cs | 3 +++ .../SqlServer/CipherRepository.cs | 27 +++++++++++++++++++ src/Sql/Sql.sqlproj | 3 +++ .../CipherShare_ReadById.sql | 13 +++++++++ .../CipherShare_ReadByUserId.sql | 13 +++++++++ src/Sql/dbo/Views/CipherShareView.sql | 11 ++++++++ 11 files changed, 123 insertions(+), 15 deletions(-) create mode 100644 src/Core/Enums/SharePermissionType.cs create mode 100644 src/Core/Models/Data/CipherShare.cs create mode 100644 src/Sql/dbo/Stored Procedures/CipherShare_ReadById.sql create mode 100644 src/Sql/dbo/Stored Procedures/CipherShare_ReadByUserId.sql create mode 100644 src/Sql/dbo/Views/CipherShareView.sql diff --git a/src/Api/Controllers/CiphersController.cs b/src/Api/Controllers/CiphersController.cs index 51e3a8445a..55f25c2ace 100644 --- a/src/Api/Controllers/CiphersController.cs +++ b/src/Api/Controllers/CiphersController.cs @@ -31,27 +31,28 @@ namespace Bit.Api.Controllers } [HttpGet("{id}")] - public async Task Get(string id) + public async Task Get(string id) { var userId = _userService.GetProperUserId(User).Value; - var cipher = await _cipherRepository.GetByIdAsync(new Guid(id), userId); + var cipher = await _cipherRepository.GetShareByIdAsync(new Guid(id), userId); if(cipher == null) { throw new NotFoundException(); } - return new CipherResponseModel(cipher, userId); + return new CipherShareResponseModel(cipher, userId); } [HttpGet("")] - public async Task> Get() + public async Task> Get() { var userId = _userService.GetProperUserId(User).Value; - var ciphers = await _cipherRepository.GetManyByUserIdAsync(userId); - var responses = ciphers.Select(c => new CipherResponseModel(c, userId)); - return new ListResponseModel(responses); + var ciphers = await _cipherRepository.GetManyShareByUserIdAsync(userId); + var responses = ciphers.Select(c => new CipherShareResponseModel(c, userId)); + return new ListResponseModel(responses); } + [Obsolete] [HttpGet("history")] public async Task Get(DateTime since) { diff --git a/src/Api/IdentityServer/ResourceOwnerPasswordValidator.cs b/src/Api/IdentityServer/ResourceOwnerPasswordValidator.cs index 46b3bf8439..6e0d1d3c0b 100644 --- a/src/Api/IdentityServer/ResourceOwnerPasswordValidator.cs +++ b/src/Api/IdentityServer/ResourceOwnerPasswordValidator.cs @@ -118,13 +118,16 @@ namespace Bit.Api.IdentityServer claims.Add(new Claim("device", device.Identifier)); } + var customResponse = new Dictionary(); + if(!string.IsNullOrWhiteSpace(user.PrivateKey)) + { + customResponse.Add("EncryptedPrivateKey", user.PrivateKey); + } + context.Result = new GrantValidationResult(user.Id.ToString(), "Application", identityProvider: "bitwarden", claims: claims.Count > 0 ? claims : null, - customResponse: new Dictionary - { - { "EncryptedPrivateKey", user.PrivateKey } - }); + customResponse: customResponse); } private void BuildTwoFactorResult(User user, ResourceOwnerPasswordValidationContext context) diff --git a/src/Api/Models/Response/CipherResponseModel.cs b/src/Api/Models/Response/CipherResponseModel.cs index b9ce73bfb1..ff3ee59dfb 100644 --- a/src/Api/Models/Response/CipherResponseModel.cs +++ b/src/Api/Models/Response/CipherResponseModel.cs @@ -1,15 +1,15 @@ using System; using Bit.Core.Domains; +using Bit.Core.Models.Data; using System.Collections.Generic; using Newtonsoft.Json; -using System.Linq; namespace Bit.Api.Models { public class CipherResponseModel : ResponseModel { - public CipherResponseModel(Cipher cipher, Guid userId) - : base("cipher") + public CipherResponseModel(Cipher cipher, Guid userId, string obj = "cipher") + : base(obj) { if(cipher == null) { @@ -40,7 +40,22 @@ namespace Bit.Api.Models public Core.Enums.CipherType Type { get; set; } public bool Favorite { get; set; } public dynamic Data { get; set; } - public string Key { get; set; } public DateTime RevisionDate { get; set; } } + + public class CipherShareResponseModel : CipherResponseModel + { + public CipherShareResponseModel(CipherShare cipherShare, Guid userId) + : base(cipherShare, userId, "cipherShare") + { + Key = cipherShare.Key; + Permissions = cipherShare.Permissions == null ? null : + JsonConvert.DeserializeObject>(cipherShare.Permissions); + Status = cipherShare.Status; + } + + public string Key { get; set; } + public IEnumerable Permissions { get; set; } + public Core.Enums.ShareStatusType? Status { get; set; } + } } diff --git a/src/Core/Enums/SharePermissionType.cs b/src/Core/Enums/SharePermissionType.cs new file mode 100644 index 0000000000..72f9a02403 --- /dev/null +++ b/src/Core/Enums/SharePermissionType.cs @@ -0,0 +1,8 @@ +namespace Bit.Core.Enums +{ + public enum SharePermissionType : byte + { + Reshare = 0, + Edit = 1 + } +} diff --git a/src/Core/Models/Data/CipherShare.cs b/src/Core/Models/Data/CipherShare.cs new file mode 100644 index 0000000000..a7150aa198 --- /dev/null +++ b/src/Core/Models/Data/CipherShare.cs @@ -0,0 +1,11 @@ +using Bit.Core.Domains; + +namespace Bit.Core.Models.Data +{ + public class CipherShare : Cipher + { + public string Key { get; internal set; } + public string Permissions { get; internal set; } + public Enums.ShareStatusType? Status { get; internal set; } + } +} diff --git a/src/Core/Repositories/ICipherRepository.cs b/src/Core/Repositories/ICipherRepository.cs index 612bcfb537..8978c26dd2 100644 --- a/src/Core/Repositories/ICipherRepository.cs +++ b/src/Core/Repositories/ICipherRepository.cs @@ -2,13 +2,16 @@ using System.Collections.Generic; using System.Threading.Tasks; using Bit.Core.Domains; +using Bit.Core.Models.Data; namespace Bit.Core.Repositories { public interface ICipherRepository : IRepository { Task GetByIdAsync(Guid id, Guid userId); + Task GetShareByIdAsync(Guid id, Guid userId); Task> GetManyByUserIdAsync(Guid userId); + Task> GetManyShareByUserIdAsync(Guid userId); Task> GetManyByTypeAndUserIdAsync(Enums.CipherType type, Guid userId); Task, ICollection>> GetManySinceRevisionDateAndUserIdWithDeleteHistoryAsync(DateTime sinceRevisionDate, Guid userId); diff --git a/src/Core/Repositories/SqlServer/CipherRepository.cs b/src/Core/Repositories/SqlServer/CipherRepository.cs index 774cb3f348..cbca04c6bd 100644 --- a/src/Core/Repositories/SqlServer/CipherRepository.cs +++ b/src/Core/Repositories/SqlServer/CipherRepository.cs @@ -7,6 +7,7 @@ using DataTableProxy; using Bit.Core.Domains; using System.Data; using Dapper; +using Bit.Core.Models.Data; namespace Bit.Core.Repositories.SqlServer { @@ -31,6 +32,19 @@ namespace Bit.Core.Repositories.SqlServer return cipher; } + public async Task GetShareByIdAsync(Guid id, Guid userId) + { + using(var connection = new SqlConnection(ConnectionString)) + { + var results = await connection.QueryAsync( + $"[{Schema}].[CipherShare_ReadById]", + new { UserId = userId }, + commandType: CommandType.StoredProcedure); + + return results.FirstOrDefault(c => c.UserId == userId); + } + } + public async Task> GetManyByUserIdAsync(Guid userId) { using(var connection = new SqlConnection(ConnectionString)) @@ -44,6 +58,19 @@ namespace Bit.Core.Repositories.SqlServer } } + public async Task> GetManyShareByUserIdAsync(Guid userId) + { + using(var connection = new SqlConnection(ConnectionString)) + { + var results = await connection.QueryAsync( + $"[{Schema}].[CipherShare_ReadByUserId]", + new { UserId = userId }, + commandType: CommandType.StoredProcedure); + + return results.ToList(); + } + } + public async Task> GetManyByTypeAndUserIdAsync(Enums.CipherType type, Guid userId) { using(var connection = new SqlConnection(ConnectionString)) diff --git a/src/Sql/Sql.sqlproj b/src/Sql/Sql.sqlproj index eef9bad201..c7659a12a6 100644 --- a/src/Sql/Sql.sqlproj +++ b/src/Sql/Sql.sqlproj @@ -109,5 +109,8 @@ + + + \ No newline at end of file diff --git a/src/Sql/dbo/Stored Procedures/CipherShare_ReadById.sql b/src/Sql/dbo/Stored Procedures/CipherShare_ReadById.sql new file mode 100644 index 0000000000..dc841a9be9 --- /dev/null +++ b/src/Sql/dbo/Stored Procedures/CipherShare_ReadById.sql @@ -0,0 +1,13 @@ +CREATE PROCEDURE [dbo].[CipherShare_ReadById] + @Id UNIQUEIDENTIFIER +AS +BEGIN + SET NOCOUNT ON + + SELECT + * + FROM + [dbo].[CipherShareView] + WHERE + [Id] = @Id +END \ No newline at end of file diff --git a/src/Sql/dbo/Stored Procedures/CipherShare_ReadByUserId.sql b/src/Sql/dbo/Stored Procedures/CipherShare_ReadByUserId.sql new file mode 100644 index 0000000000..46bebd21d2 --- /dev/null +++ b/src/Sql/dbo/Stored Procedures/CipherShare_ReadByUserId.sql @@ -0,0 +1,13 @@ +CREATE PROCEDURE [dbo].[CipherShare_ReadByUserId] + @UserId UNIQUEIDENTIFIER +AS +BEGIN + SET NOCOUNT ON + + SELECT + * + FROM + [dbo].[CipherShareView] + WHERE + [UserId] = @UserId +END \ No newline at end of file diff --git a/src/Sql/dbo/Views/CipherShareView.sql b/src/Sql/dbo/Views/CipherShareView.sql new file mode 100644 index 0000000000..9e7ce4cb02 --- /dev/null +++ b/src/Sql/dbo/Views/CipherShareView.sql @@ -0,0 +1,11 @@ +CREATE VIEW [dbo].[CipherShareView] +AS +SELECT + C.*, + S.[Key], + S.[Permissions], + S.[Status] +FROM + [dbo].[Cipher] C +LEFT JOIN + [dbo].[Share] S ON C.[Id] = S.[CipherId] \ No newline at end of file