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

cipher share data and key response

This commit is contained in:
Kyle Spearrin 2017-02-18 01:17:09 -05:00
parent f7be17d1c5
commit 2b72197f0a
13 changed files with 105 additions and 34 deletions

1
.gitignore vendored
View File

@ -200,3 +200,4 @@ FakesAssemblies/
project.lock.json project.lock.json
*.jfm *.jfm
mail_dist/ mail_dist/
*.refactorlog

View File

@ -33,29 +33,32 @@ namespace Bit.Api.Controllers
[HttpGet("{id}")] [HttpGet("{id}")]
public async Task<CipherResponseModel> Get(string id) public async Task<CipherResponseModel> Get(string id)
{ {
var cipher = await _cipherRepository.GetByIdAsync(new Guid(id), _userService.GetProperUserId(User).Value); var userId = _userService.GetProperUserId(User).Value;
var cipher = await _cipherRepository.GetByIdAsync(new Guid(id), userId);
if(cipher == null) if(cipher == null)
{ {
throw new NotFoundException(); throw new NotFoundException();
} }
return new CipherResponseModel(cipher); return new CipherResponseModel(cipher, userId);
} }
[HttpGet("")] [HttpGet("")]
public async Task<ListResponseModel<CipherResponseModel>> Get() public async Task<ListResponseModel<CipherResponseModel>> Get()
{ {
var ciphers = await _cipherRepository.GetManyByUserIdAsync(_userService.GetProperUserId(User).Value); var userId = _userService.GetProperUserId(User).Value;
var responses = ciphers.Select(c => new CipherResponseModel(c)); var ciphers = await _cipherRepository.GetManyByUserIdAsync(userId);
var responses = ciphers.Select(c => new CipherResponseModel(c, userId));
return new ListResponseModel<CipherResponseModel>(responses); return new ListResponseModel<CipherResponseModel>(responses);
} }
[HttpGet("history")] [HttpGet("history")]
public async Task<CipherHistoryResponseModel> Get(DateTime since) public async Task<CipherHistoryResponseModel> Get(DateTime since)
{ {
var userId = _userService.GetProperUserId(User).Value;
var history = await _cipherRepository.GetManySinceRevisionDateAndUserIdWithDeleteHistoryAsync( var history = await _cipherRepository.GetManySinceRevisionDateAndUserIdWithDeleteHistoryAsync(
since, _userService.GetProperUserId(User).Value); since, userId);
return new CipherHistoryResponseModel(history.Item1, history.Item2); return new CipherHistoryResponseModel(history.Item1, history.Item2, userId);
} }
[HttpPost("import")] [HttpPost("import")]

View File

@ -34,44 +34,48 @@ namespace Bit.Api.Controllers
[HttpGet("{id}")] [HttpGet("{id}")]
public async Task<FolderResponseModel> Get(string id) public async Task<FolderResponseModel> Get(string id)
{ {
var userId = _userService.GetProperUserId(User).Value;
var folder = await _cipherRepository.GetByIdAsync(new Guid(id), _userService.GetProperUserId(User).Value); var folder = await _cipherRepository.GetByIdAsync(new Guid(id), _userService.GetProperUserId(User).Value);
if(folder == null || folder.Type != Core.Enums.CipherType.Folder) if(folder == null || folder.Type != Core.Enums.CipherType.Folder)
{ {
throw new NotFoundException(); throw new NotFoundException();
} }
return new FolderResponseModel(folder); return new FolderResponseModel(folder, userId);
} }
[HttpGet("")] [HttpGet("")]
public async Task<ListResponseModel<FolderResponseModel>> Get() public async Task<ListResponseModel<FolderResponseModel>> Get()
{ {
var userId = _userService.GetProperUserId(User).Value;
ICollection<Cipher> folders = await _cipherRepository.GetManyByTypeAndUserIdAsync(Core.Enums.CipherType.Folder, ICollection<Cipher> folders = await _cipherRepository.GetManyByTypeAndUserIdAsync(Core.Enums.CipherType.Folder,
_userService.GetProperUserId(User).Value); userId);
var responses = folders.Select(f => new FolderResponseModel(f)); var responses = folders.Select(f => new FolderResponseModel(f, userId));
return new ListResponseModel<FolderResponseModel>(responses); return new ListResponseModel<FolderResponseModel>(responses);
} }
[HttpPost("")] [HttpPost("")]
public async Task<FolderResponseModel> Post([FromBody]FolderRequestModel model) public async Task<FolderResponseModel> Post([FromBody]FolderRequestModel model)
{ {
var userId = _userService.GetProperUserId(User).Value;
var folder = model.ToCipher(_userService.GetProperUserId(User).Value); var folder = model.ToCipher(_userService.GetProperUserId(User).Value);
await _cipherService.SaveAsync(folder); await _cipherService.SaveAsync(folder);
return new FolderResponseModel(folder); return new FolderResponseModel(folder, userId);
} }
[HttpPut("{id}")] [HttpPut("{id}")]
[HttpPost("{id}")] [HttpPost("{id}")]
public async Task<FolderResponseModel> Put(string id, [FromBody]FolderRequestModel model) public async Task<FolderResponseModel> Put(string id, [FromBody]FolderRequestModel model)
{ {
var folder = await _cipherRepository.GetByIdAsync(new Guid(id), _userService.GetProperUserId(User).Value); var userId = _userService.GetProperUserId(User).Value;
var folder = await _cipherRepository.GetByIdAsync(new Guid(id), userId);
if(folder == null || folder.Type != Core.Enums.CipherType.Folder) if(folder == null || folder.Type != Core.Enums.CipherType.Folder)
{ {
throw new NotFoundException(); throw new NotFoundException();
} }
await _cipherService.SaveAsync(model.ToCipher(folder)); await _cipherService.SaveAsync(model.ToCipher(folder));
return new FolderResponseModel(folder); return new FolderResponseModel(folder, userId);
} }
[HttpDelete("{id}")] [HttpDelete("{id}")]

View File

@ -36,35 +36,38 @@ namespace Bit.Api.Controllers
[HttpGet("{id}")] [HttpGet("{id}")]
public async Task<LoginResponseModel> Get(string id, string[] expand = null) public async Task<LoginResponseModel> Get(string id, string[] expand = null)
{ {
var login = await _cipherRepository.GetByIdAsync(new Guid(id), _userService.GetProperUserId(User).Value); var userId = _userService.GetProperUserId(User).Value;
var login = await _cipherRepository.GetByIdAsync(new Guid(id), userId);
if(login == null || login.Type != Core.Enums.CipherType.Login) if(login == null || login.Type != Core.Enums.CipherType.Login)
{ {
throw new NotFoundException(); throw new NotFoundException();
} }
var response = new LoginResponseModel(login); var response = new LoginResponseModel(login, userId);
await ExpandAsync(login, response, expand, null); await ExpandAsync(login, response, expand, null, userId);
return response; return response;
} }
[HttpGet("")] [HttpGet("")]
public async Task<ListResponseModel<LoginResponseModel>> Get(string[] expand = null) public async Task<ListResponseModel<LoginResponseModel>> Get(string[] expand = null)
{ {
var userId = _userService.GetProperUserId(User).Value;
ICollection<Cipher> logins = await _cipherRepository.GetManyByTypeAndUserIdAsync(Core.Enums.CipherType.Login, ICollection<Cipher> logins = await _cipherRepository.GetManyByTypeAndUserIdAsync(Core.Enums.CipherType.Login,
_userService.GetProperUserId(User).Value); userId);
var responses = logins.Select(s => new LoginResponseModel(s)).ToList(); var responses = logins.Select(s => new LoginResponseModel(s, userId)).ToList();
await ExpandManyAsync(logins, responses, expand, null); await ExpandManyAsync(logins, responses, expand, null, userId);
return new ListResponseModel<LoginResponseModel>(responses); return new ListResponseModel<LoginResponseModel>(responses);
} }
[HttpPost("")] [HttpPost("")]
public async Task<LoginResponseModel> Post([FromBody]LoginRequestModel model, string[] expand = null) public async Task<LoginResponseModel> Post([FromBody]LoginRequestModel model, string[] expand = null)
{ {
var login = model.ToCipher(_userService.GetProperUserId(User).Value); var userId = _userService.GetProperUserId(User).Value;
var login = model.ToCipher(userId);
await _cipherService.SaveAsync(login); await _cipherService.SaveAsync(login);
var response = new LoginResponseModel(login); var response = new LoginResponseModel(login, userId);
await ExpandAsync(login, response, expand, null); await ExpandAsync(login, response, expand, null, userId);
return response; return response;
} }
@ -72,6 +75,7 @@ namespace Bit.Api.Controllers
[HttpPost("{id}")] [HttpPost("{id}")]
public async Task<LoginResponseModel> Put(string id, [FromBody]LoginRequestModel model, string[] expand = null) public async Task<LoginResponseModel> Put(string id, [FromBody]LoginRequestModel model, string[] expand = null)
{ {
var userId = _userService.GetProperUserId(User).Value;
var login = await _cipherRepository.GetByIdAsync(new Guid(id), _userService.GetProperUserId(User).Value); var login = await _cipherRepository.GetByIdAsync(new Guid(id), _userService.GetProperUserId(User).Value);
if(login == null || login.Type != Core.Enums.CipherType.Login) if(login == null || login.Type != Core.Enums.CipherType.Login)
{ {
@ -80,8 +84,8 @@ namespace Bit.Api.Controllers
await _cipherService.SaveAsync(model.ToCipher(login)); await _cipherService.SaveAsync(model.ToCipher(login));
var response = new LoginResponseModel(login); var response = new LoginResponseModel(login, userId);
await ExpandAsync(login, response, expand, null); await ExpandAsync(login, response, expand, null, userId);
return response; return response;
} }
@ -98,7 +102,7 @@ namespace Bit.Api.Controllers
await _cipherService.DeleteAsync(login); await _cipherService.DeleteAsync(login);
} }
private async Task ExpandAsync(Cipher login, LoginResponseModel response, string[] expand, Cipher folder) private async Task ExpandAsync(Cipher login, LoginResponseModel response, string[] expand, Cipher folder, Guid userId)
{ {
if(expand == null || expand.Count() == 0) if(expand == null || expand.Count() == 0)
{ {
@ -112,12 +116,12 @@ namespace Bit.Api.Controllers
folder = await _cipherRepository.GetByIdAsync(login.FolderId.Value); folder = await _cipherRepository.GetByIdAsync(login.FolderId.Value);
} }
response.Folder = new FolderResponseModel(folder); response.Folder = new FolderResponseModel(folder, userId);
} }
} }
private async Task ExpandManyAsync(IEnumerable<Cipher> logins, ICollection<LoginResponseModel> responses, private async Task ExpandManyAsync(IEnumerable<Cipher> logins, ICollection<LoginResponseModel> responses,
string[] expand, IEnumerable<Cipher> folders) string[] expand, IEnumerable<Cipher> folders, Guid userId)
{ {
if(expand == null || expand.Count() == 0) if(expand == null || expand.Count() == 0)
{ {
@ -148,7 +152,7 @@ namespace Bit.Api.Controllers
continue; continue;
} }
response.Folder = new FolderResponseModel(folder); response.Folder = new FolderResponseModel(folder, userId);
} }
} }
} }

View File

@ -7,7 +7,7 @@ namespace Bit.Api.Models
{ {
public class CipherHistoryResponseModel : ResponseModel public class CipherHistoryResponseModel : ResponseModel
{ {
public CipherHistoryResponseModel(IEnumerable<Cipher> revisedCiphers, IEnumerable<Guid> deletedIds) public CipherHistoryResponseModel(IEnumerable<Cipher> revisedCiphers, IEnumerable<Guid> deletedIds, Guid userId)
: base("cipherHistory") : base("cipherHistory")
{ {
if(revisedCiphers == null) if(revisedCiphers == null)
@ -20,7 +20,7 @@ namespace Bit.Api.Models
throw new ArgumentNullException(nameof(deletedIds)); throw new ArgumentNullException(nameof(deletedIds));
} }
Revised = revisedCiphers.Select(c => new CipherResponseModel(c)); Revised = revisedCiphers.Select(c => new CipherResponseModel(c, userId));
Deleted = deletedIds.Select(id => id.ToString()); Deleted = deletedIds.Select(id => id.ToString());
} }

View File

@ -1,11 +1,14 @@
using System; using System;
using Bit.Core.Domains; using Bit.Core.Domains;
using System.Collections.Generic;
using Newtonsoft.Json;
using System.Linq;
namespace Bit.Api.Models namespace Bit.Api.Models
{ {
public class CipherResponseModel : ResponseModel public class CipherResponseModel : ResponseModel
{ {
public CipherResponseModel(Cipher cipher) public CipherResponseModel(Cipher cipher, Guid userId)
: base("cipher") : base("cipher")
{ {
if(cipher == null) if(cipher == null)
@ -30,6 +33,16 @@ namespace Bit.Api.Models
default: default:
throw new ArgumentException("Unsupported " + nameof(Type) + "."); throw new ArgumentException("Unsupported " + nameof(Type) + ".");
} }
if(!string.IsNullOrWhiteSpace(cipher.Shares))
{
var shares = JsonConvert.DeserializeObject<IEnumerable<Cipher.Share>>(cipher.Shares);
var userShare = shares.FirstOrDefault(s => s.UserId == userId);
if(userShare != null)
{
Key = userShare.Key;
}
}
} }
public string Id { get; set; } public string Id { get; set; }
@ -37,6 +50,7 @@ namespace Bit.Api.Models
public Core.Enums.CipherType Type { get; set; } public Core.Enums.CipherType Type { get; set; }
public bool Favorite { get; set; } public bool Favorite { get; set; }
public dynamic Data { get; set; } public dynamic Data { get; set; }
public string Key { get; set; }
public DateTime RevisionDate { get; set; } public DateTime RevisionDate { get; set; }
} }
} }

View File

@ -1,11 +1,14 @@
using System; using System;
using Bit.Core.Domains; using Bit.Core.Domains;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Linq;
namespace Bit.Api.Models namespace Bit.Api.Models
{ {
public class FolderResponseModel : ResponseModel public class FolderResponseModel : ResponseModel
{ {
public FolderResponseModel(Cipher cipher) public FolderResponseModel(Cipher cipher, Guid userId)
: base("folder") : base("folder")
{ {
if(cipher == null) if(cipher == null)
@ -23,10 +26,21 @@ namespace Bit.Api.Models
Id = cipher.Id.ToString(); Id = cipher.Id.ToString();
Name = data.Name; Name = data.Name;
RevisionDate = cipher.RevisionDate; RevisionDate = cipher.RevisionDate;
if(!string.IsNullOrWhiteSpace(cipher.Shares))
{
var shares = JsonConvert.DeserializeObject<IEnumerable<Cipher.Share>>(cipher.Shares);
var userShare = shares.FirstOrDefault(s => s.UserId == userId);
if(userShare != null)
{
Key = userShare.Key;
}
}
} }
public string Id { get; set; } public string Id { get; set; }
public string Name { get; set; } public string Name { get; set; }
public string Key { get; set; }
public DateTime RevisionDate { get; set; } public DateTime RevisionDate { get; set; }
} }
} }

View File

@ -1,11 +1,14 @@
using System; using System;
using Bit.Core.Domains; using Bit.Core.Domains;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Linq;
namespace Bit.Api.Models namespace Bit.Api.Models
{ {
public class LoginResponseModel : ResponseModel public class LoginResponseModel : ResponseModel
{ {
public LoginResponseModel(Cipher cipher) public LoginResponseModel(Cipher cipher, Guid userId)
: base("login") : base("login")
{ {
if(cipher == null) if(cipher == null)
@ -29,6 +32,16 @@ namespace Bit.Api.Models
Password = data.Password; Password = data.Password;
Notes = data.Notes; Notes = data.Notes;
RevisionDate = cipher.RevisionDate; RevisionDate = cipher.RevisionDate;
if(!string.IsNullOrWhiteSpace(cipher.Shares))
{
var shares = JsonConvert.DeserializeObject<IEnumerable<Cipher.Share>>(cipher.Shares);
var userShare = shares.FirstOrDefault(s => s.UserId == userId);
if(userShare != null)
{
Key = userShare.Key;
}
}
} }
public string Id { get; set; } public string Id { get; set; }
@ -39,6 +52,7 @@ namespace Bit.Api.Models
public string Username { get; set; } public string Username { get; set; }
public string Password { get; set; } public string Password { get; set; }
public string Notes { get; set; } public string Notes { get; set; }
public string Key { get; set; }
public DateTime RevisionDate { get; set; } public DateTime RevisionDate { get; set; }
// Expandables // Expandables

View File

@ -11,6 +11,7 @@ namespace Bit.Core.Domains
public Enums.CipherType Type { get; set; } public Enums.CipherType Type { get; set; }
public bool Favorite { get; set; } public bool Favorite { get; set; }
public string Data { get; set; } public string Data { get; set; }
public string Shares { get; set; }
public DateTime CreationDate { get; internal set; } = DateTime.UtcNow; public DateTime CreationDate { get; internal set; } = DateTime.UtcNow;
public DateTime RevisionDate { get; internal set; } = DateTime.UtcNow; public DateTime RevisionDate { get; internal set; } = DateTime.UtcNow;
@ -18,5 +19,12 @@ namespace Bit.Core.Domains
{ {
Id = CoreHelpers.GenerateComb(); Id = CoreHelpers.GenerateComb();
} }
public class Share
{
public Guid UserId { get; set; }
public string Key { get; set; }
// TODO: permission flags?
}
} }
} }

View File

@ -104,4 +104,7 @@
<Build Include="dbo\Stored Procedures\Grant_Save.sql" /> <Build Include="dbo\Stored Procedures\Grant_Save.sql" />
<Build Include="dbo\Stored Procedures\User_ReadAccountRevisionDateById.sql" /> <Build Include="dbo\Stored Procedures\User_ReadAccountRevisionDateById.sql" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<RefactorLog Include="Sql.refactorlog" />
</ItemGroup>
</Project> </Project>

View File

@ -5,6 +5,7 @@
@Type TINYINT, @Type TINYINT,
@Favorite BIT, @Favorite BIT,
@Data NVARCHAR(MAX), @Data NVARCHAR(MAX),
@Shares NVARCHAR(MAX),
@CreationDate DATETIME2(7), @CreationDate DATETIME2(7),
@RevisionDate DATETIME2(7) @RevisionDate DATETIME2(7)
AS AS
@ -19,6 +20,7 @@ BEGIN
[Type], [Type],
[Favorite], [Favorite],
[Data], [Data],
[Shares],
[CreationDate], [CreationDate],
[RevisionDate] [RevisionDate]
) )
@ -30,6 +32,7 @@ BEGIN
@Type, @Type,
@Favorite, @Favorite,
@Data, @Data,
@Shares,
@CreationDate, @CreationDate,
@RevisionDate @RevisionDate
) )

View File

@ -5,6 +5,7 @@
@Type TINYINT, @Type TINYINT,
@Favorite BIT, @Favorite BIT,
@Data NVARCHAR(MAX), @Data NVARCHAR(MAX),
@Shares NVARCHAR(MAX),
@CreationDate DATETIME2(7), @CreationDate DATETIME2(7),
@RevisionDate DATETIME2(7) @RevisionDate DATETIME2(7)
AS AS
@ -19,6 +20,7 @@ BEGIN
[Type] = @Type, [Type] = @Type,
[Favorite] = @Favorite, [Favorite] = @Favorite,
[Data] = @Data, [Data] = @Data,
[Shares] = @Shares,
[CreationDate] = @CreationDate, [CreationDate] = @CreationDate,
[RevisionDate] = @RevisionDate [RevisionDate] = @RevisionDate
WHERE WHERE

View File

@ -5,6 +5,7 @@
[Type] TINYINT NOT NULL, [Type] TINYINT NOT NULL,
[Favorite] BIT NOT NULL, [Favorite] BIT NOT NULL,
[Data] NVARCHAR (MAX) NOT NULL, [Data] NVARCHAR (MAX) NOT NULL,
[Shares] NVARCHAR (MAX) NULL,
[CreationDate] DATETIME2 (7) NOT NULL, [CreationDate] DATETIME2 (7) NOT NULL,
[RevisionDate] DATETIME2 (7) NOT NULL, [RevisionDate] DATETIME2 (7) NOT NULL,
CONSTRAINT [PK_Cipher] PRIMARY KEY CLUSTERED ([Id] ASC), CONSTRAINT [PK_Cipher] PRIMARY KEY CLUSTERED ([Id] ASC),