1
0
mirror of https://github.com/bitwarden/server.git synced 2024-11-24 12:35:25 +01:00

[PS-165] Missing copy verification code (#2022)

* Made changes to organization details endpoint

* Fixed formatting

* Added script to utils directory
This commit is contained in:
Gbubemi Smith 2022-06-07 16:52:07 +01:00 committed by GitHub
parent 60a167f2b7
commit 64edad8f49
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 123 additions and 7 deletions

View File

@ -224,11 +224,12 @@ namespace Bit.Api.Controllers
throw new NotFoundException(); throw new NotFoundException();
} }
IEnumerable<Cipher> orgCiphers; IEnumerable<CipherOrganizationDetails> orgCiphers;
if (await _currentContext.OrganizationAdmin(orgIdGuid)) if (await _currentContext.OrganizationOwner(orgIdGuid))
{ {
// Admins, Owners and Providers can access all items even if not assigned to them // User may be a Provider for the organization, in which case GetManyByUserIdAsync won't return any results
orgCiphers = await _cipherRepository.GetManyByOrganizationIdAsync(orgIdGuid); // But they have access to all organization ciphers, so we can safely get by orgId instead
orgCiphers = await _cipherRepository.GetManyOrganizationDetailsByOrganizationIdAsync(orgIdGuid);
} }
else else
{ {
@ -245,7 +246,8 @@ namespace Bit.Api.Controllers
var responses = orgCiphers.Select(c => new CipherMiniDetailsResponseModel(c, _globalSettings, var responses = orgCiphers.Select(c => new CipherMiniDetailsResponseModel(c, _globalSettings,
collectionCiphersGroupDict)); collectionCiphersGroupDict, c.OrganizationUseTotp));
var providerId = await _currentContext.ProviderIdForOrg(orgIdGuid); var providerId = await _currentContext.ProviderIdForOrg(orgIdGuid);
if (providerId.HasValue) if (providerId.HasValue)

View File

@ -132,8 +132,8 @@ namespace Bit.Api.Models.Response
public class CipherMiniDetailsResponseModel : CipherMiniResponseModel public class CipherMiniDetailsResponseModel : CipherMiniResponseModel
{ {
public CipherMiniDetailsResponseModel(Cipher cipher, GlobalSettings globalSettings, public CipherMiniDetailsResponseModel(Cipher cipher, GlobalSettings globalSettings,
IDictionary<Guid, IGrouping<Guid, CollectionCipher>> collectionCiphers, string obj = "cipherMiniDetails") IDictionary<Guid, IGrouping<Guid, CollectionCipher>> collectionCiphers, bool orgUseTotp, string obj = "cipherMiniDetails")
: base(cipher, globalSettings, false, obj) : base(cipher, globalSettings, orgUseTotp, obj)
{ {
if (collectionCiphers?.ContainsKey(cipher.Id) ?? false) if (collectionCiphers?.ContainsKey(cipher.Id) ?? false)
{ {

View File

@ -11,6 +11,7 @@ namespace Bit.Core.Repositories
{ {
Task<CipherDetails> GetByIdAsync(Guid id, Guid userId); Task<CipherDetails> GetByIdAsync(Guid id, Guid userId);
Task<CipherOrganizationDetails> GetOrganizationDetailsByIdAsync(Guid id); Task<CipherOrganizationDetails> GetOrganizationDetailsByIdAsync(Guid id);
Task<ICollection<CipherOrganizationDetails>> GetManyOrganizationDetailsByOrganizationIdAsync(Guid organizationId);
Task<bool> GetCanEditByIdAsync(Guid userId, Guid cipherId); Task<bool> GetCanEditByIdAsync(Guid userId, Guid cipherId);
Task<ICollection<CipherDetails>> GetManyByUserIdAsync(Guid userId, bool withOrganizations = true); Task<ICollection<CipherDetails>> GetManyByUserIdAsync(Guid userId, bool withOrganizations = true);
Task<ICollection<Cipher>> GetManyByOrganizationIdAsync(Guid organizationId); Task<ICollection<Cipher>> GetManyByOrganizationIdAsync(Guid organizationId);

View File

@ -50,6 +50,20 @@ namespace Bit.Infrastructure.Dapper.Repositories
} }
} }
public async Task<ICollection<CipherOrganizationDetails>> GetManyOrganizationDetailsByOrganizationIdAsync(
Guid organizationId)
{
using (var connection = new SqlConnection(ConnectionString))
{
var results = await connection.QueryAsync<CipherOrganizationDetails>(
$"[{Schema}].[CipherOrganizationDetails_ReadByOrganizationId]",
new { OrganizationId = organizationId },
commandType: CommandType.StoredProcedure);
return results.ToList();
}
}
public async Task<bool> GetCanEditByIdAsync(Guid userId, Guid cipherId) public async Task<bool> GetCanEditByIdAsync(Guid userId, Guid cipherId)
{ {
using (var connection = new SqlConnection(ConnectionString)) using (var connection = new SqlConnection(ConnectionString))

View File

@ -259,6 +259,18 @@ namespace Bit.Infrastructure.EntityFramework.Repositories
} }
} }
public async Task<ICollection<CipherOrganizationDetails>> GetManyOrganizationDetailsByOrganizationIdAsync(
Guid organizationId)
{
using (var scope = ServiceScopeFactory.CreateScope())
{
var dbContext = GetDatabaseContext(scope);
var query = new CipherOrganizationDetailsReadByIdQuery(organizationId);
var data = await query.Run(dbContext).ToListAsync();
return data;
}
}
public async Task<bool> GetCanEditByIdAsync(Guid userId, Guid cipherId) public async Task<bool> GetCanEditByIdAsync(Guid userId, Guid cipherId)
{ {
using (var scope = ServiceScopeFactory.CreateScope()) using (var scope = ServiceScopeFactory.CreateScope())

View File

@ -0,0 +1,40 @@
using System;
using System.Linq;
using Core.Models.Data;
namespace Bit.Infrastructure.EntityFramework.Repositories.Queries
{
public class CipherOrganizationDetailsReadByOrgizationIdQuery : IQuery<CipherOrganizationDetails>
{
private readonly Guid _organizationId;
public CipherOrganizationDetailsReadByOrgizationIdQuery(Guid organizationId)
{
_organizationId = organizationId;
}
public virtual IQueryable<CipherOrganizationDetails> Run(DatabaseContext dbContext)
{
var query = from c in dbContext.Ciphers
join o in dbContext.Organizations
on c.OrganizationId equals o.Id into o_g
from o in o_g.DefaultIfEmpty()
where c.OrganizationId == _organizationId
select new CipherOrganizationDetails
{
Id = c.Id,
UserId = c.UserId,
OrganizationId = c.OrganizationId,
Type = c.Type,
Data = c.Data,
Favorites = c.Favorites,
Folders = c.Folders,
Attachments = c.Attachments,
CreationDate = c.CreationDate,
RevisionDate = c.RevisionDate,
DeletedDate = c.DeletedDate,
OrganizationUseTotp = o.UseTotp,
};
return query;
}
}
}

View File

@ -390,5 +390,6 @@
<Build Include="dbo\Stored Procedures\OrganizationConnection_ReadByOrganizationIdType.sql" /> <Build Include="dbo\Stored Procedures\OrganizationConnection_ReadByOrganizationIdType.sql" />
<Build Include="dbo\Views\OrganizationApiKeyView.sql" /> <Build Include="dbo\Views\OrganizationApiKeyView.sql" />
<Build Include="dbo\Views\OrganizationConnectionView.sql" /> <Build Include="dbo\Views\OrganizationConnectionView.sql" />
<Build Include="dbo\Stored Procedures\CipherOrganizationDetails_ReadByOrganizationId.sql" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -0,0 +1,19 @@
CREATE PROCEDURE [dbo].[CipherOrganizationDetails_ReadByOrganizationId]
@OrganizationId UNIQUEIDENTIFIER
AS
BEGIN
SET NOCOUNT ON
SELECT
C.*,
CASE
WHEN O.[UseTotp] = 1 THEN 1
ELSE 0
END [OrganizationUseTotp]
FROM
[dbo].[CipherView] C
LEFT JOIN
[dbo].[OrganizationView] O ON O.[Id] = C.[OrganizationId]
WHERE
C.[OrganizationId] = @OrganizationId
END

View File

@ -0,0 +1,27 @@
--CipherOrganizationDetails_ReadByOrganizationId
IF OBJECT_ID('[dbo].[CipherOrganizationDetails_ReadByOrganizationId]') IS NOT NULL
BEGIN
DROP PROCEDURE [dbo].[CipherOrganizationDetails_ReadByOrganizationId]
END
GO
CREATE PROCEDURE [dbo].[CipherOrganizationDetails_ReadByOrganizationId]
@OrganizationId UNIQUEIDENTIFIER
AS
BEGIN
SET NOCOUNT ON
SELECT
C.*,
CASE
WHEN O.[UseTotp] = 1 THEN 1
ELSE 0
END [OrganizationUseTotp]
FROM
[dbo].[CipherView] C
LEFT JOIN
[dbo].[OrganizationView] O ON O.[Id] = C.[OrganizationId]
WHERE
C.[OrganizationId] = @OrganizationId
END
GO