Browse Source

purge org vault

pull/368/head
Kyle Spearrin 7 years ago
parent
commit
7164f378fc
  1. 16
      src/Api/Controllers/CiphersController.cs
  2. 3
      src/Core/Enums/EventType.cs
  3. 1
      src/Core/Repositories/ICipherRepository.cs
  4. 11
      src/Core/Repositories/SqlServer/CipherRepository.cs
  5. 1
      src/Core/Services/ICipherService.cs
  6. 11
      src/Core/Services/Implementations/CipherService.cs
  7. 1
      src/Sql/Sql.sqlproj
  8. 49
      src/Sql/dbo/Stored Procedures/Cipher_DeleteByOrganizationId.sql
  9. 56
      util/Setup/DbScripts/2018-09-25_00_OrgPurge.sql
  10. 4
      util/Setup/Setup.csproj

16
src/Api/Controllers/CiphersController.cs

@ -376,7 +376,7 @@ namespace Bit.Api.Controllers @@ -376,7 +376,7 @@ namespace Bit.Api.Controllers
}
[HttpPost("purge")]
public async Task PostPurge([FromBody]CipherPurgeRequestModel model)
public async Task PostPurge([FromBody]CipherPurgeRequestModel model, string organizationId = null)
{
var user = await _userService.GetUserByPrincipalAsync(User);
if(user == null)
@ -391,7 +391,19 @@ namespace Bit.Api.Controllers @@ -391,7 +391,19 @@ namespace Bit.Api.Controllers
throw new BadRequestException(ModelState);
}
await _cipherRepository.DeleteByUserIdAsync(user.Id);
if(string.IsNullOrWhiteSpace(organizationId))
{
await _cipherRepository.DeleteByUserIdAsync(user.Id);
}
else
{
var orgId = new Guid(organizationId);
if(!_currentContext.OrganizationAdmin(orgId))
{
throw new NotFoundException();
}
await _cipherService.PurgeAsync(orgId);
}
}
[HttpPost("{id}/attachment")]

3
src/Core/Enums/EventType.cs

@ -32,6 +32,7 @@ @@ -32,6 +32,7 @@
OrganizationUser_Removed = 1503,
OrganizationUser_UpdatedGroups = 1504,
Organization_Updated = 1600
Organization_Updated = 1600,
Organization_PurgedVault = 1601,
}
}

1
src/Core/Repositories/ICipherRepository.cs

@ -24,6 +24,7 @@ namespace Bit.Core.Repositories @@ -24,6 +24,7 @@ namespace Bit.Core.Repositories
Task DeleteAsync(IEnumerable<Guid> ids, Guid userId);
Task MoveAsync(IEnumerable<Guid> ids, Guid? folderId, Guid userId);
Task DeleteByUserIdAsync(Guid userId);
Task DeleteByOrganizationIdAsync(Guid organizationId);
Task UpdateUserKeysAndCiphersAsync(User user, IEnumerable<Cipher> ciphers, IEnumerable<Folder> folders);
Task UpdateCiphersAsync(Guid userId, IEnumerable<Cipher> ciphers);
Task CreateAsync(IEnumerable<Cipher> ciphers, IEnumerable<Folder> folders);

11
src/Core/Repositories/SqlServer/CipherRepository.cs

@ -217,6 +217,17 @@ namespace Bit.Core.Repositories.SqlServer @@ -217,6 +217,17 @@ namespace Bit.Core.Repositories.SqlServer
}
}
public async Task DeleteByOrganizationIdAsync(Guid organizationId)
{
using(var connection = new SqlConnection(ConnectionString))
{
var results = await connection.ExecuteAsync(
$"[{Schema}].[Cipher_DeleteByOrganizationId]",
new { OrganizationId = organizationId },
commandType: CommandType.StoredProcedure);
}
}
public Task UpdateUserKeysAndCiphersAsync(User user, IEnumerable<Cipher> ciphers, IEnumerable<Folder> folders)
{
using(var connection = new SqlConnection(ConnectionString))

1
src/Core/Services/ICipherService.cs

@ -18,6 +18,7 @@ namespace Bit.Core.Services @@ -18,6 +18,7 @@ namespace Bit.Core.Services
Task DeleteAsync(Cipher cipher, Guid deletingUserId, bool orgAdmin = false);
Task DeleteManyAsync(IEnumerable<Guid> cipherIds, Guid deletingUserId);
Task DeleteAttachmentAsync(Cipher cipher, string attachmentId, Guid deletingUserId, bool orgAdmin = false);
Task PurgeAsync(Guid organizationId);
Task MoveManyAsync(IEnumerable<Guid> cipherIds, Guid? destinationFolderId, Guid movingUserId);
Task SaveFolderAsync(Folder folder);
Task DeleteFolderAsync(Folder folder);

11
src/Core/Services/Implementations/CipherService.cs

@ -285,6 +285,17 @@ namespace Bit.Core.Services @@ -285,6 +285,17 @@ namespace Bit.Core.Services
await _pushService.PushSyncCipherUpdateAsync(cipher, null);
}
public async Task PurgeAsync(Guid organizationId)
{
var org = await _organizationRepository.GetByIdAsync(organizationId);
if(org == null)
{
throw new NotFoundException();
}
await _cipherRepository.DeleteByOrganizationIdAsync(organizationId);
await _eventService.LogOrganizationEventAsync(org, Enums.EventType.Organization_PurgedVault);
}
public async Task MoveManyAsync(IEnumerable<Guid> cipherIds, Guid? destinationFolderId, Guid movingUserId)
{
if(destinationFolderId.HasValue)

1
src/Sql/Sql.sqlproj

@ -231,5 +231,6 @@ @@ -231,5 +231,6 @@
<Build Include="dbo\Stored Procedures\Grant_DeleteExpired.sql" />
<Build Include="dbo\Stored Procedures\U2f_DeleteOld.sql" />
<Build Include="dbo\Stored Procedures\User_ReadKdfByEmail.sql" />
<Build Include="dbo\Stored Procedures\Cipher_DeleteByOrganizationId.sql" />
</ItemGroup>
</Project>

49
src/Sql/dbo/Stored Procedures/Cipher_DeleteByOrganizationId.sql

@ -0,0 +1,49 @@ @@ -0,0 +1,49 @@
CREATE PROCEDURE [dbo].[Cipher_DeleteByOrganizationId]
@OrganizationId AS UNIQUEIDENTIFIER
AS
BEGIN
SET NOCOUNT ON
DECLARE @BatchSize INT = 100
-- Delete collection ciphers
WHILE @BatchSize > 0
BEGIN
BEGIN TRANSACTION Cipher_DeleteByOrganizationId_CC
DELETE TOP(@BatchSize) CC
FROM
[dbo].[CollectionCipher] CC
INNER JOIN
[dbo].[Collection] C ON C.[Id] = CC.[CollectionId]
WHERE
C.[OrganizationId] = @OrganizationId
SET @BatchSize = @@ROWCOUNT
COMMIT TRANSACTION Cipher_DeleteByOrganizationId_CC
END
-- Reset batch size
SET @BatchSize = 100
-- Delete ciphers
WHILE @BatchSize > 0
BEGIN
BEGIN TRANSACTION Cipher_DeleteByOrganizationId
DELETE TOP(@BatchSize)
FROM
[dbo].[Cipher]
WHERE
[OrganizationId] = @OrganizationId
SET @BatchSize = @@ROWCOUNT
COMMIT TRANSACTION Cipher_DeleteByOrganizationId
END
-- Cleanup organization
EXEC [dbo].[Organization_UpdateStorage] @OrganizationId
EXEC [dbo].[User_BumpAccountRevisionDateByOrganizationId] @OrganizationId
END

56
util/Setup/DbScripts/2018-09-25_00_OrgPurge.sql

@ -0,0 +1,56 @@ @@ -0,0 +1,56 @@
IF OBJECT_ID('[dbo].[Cipher_DeleteByOrganizationId]') IS NOT NULL
BEGIN
DROP PROCEDURE [dbo].[Cipher_DeleteByOrganizationId]
END
GO
CREATE PROCEDURE [dbo].[Cipher_DeleteByOrganizationId]
@OrganizationId AS UNIQUEIDENTIFIER
AS
BEGIN
SET NOCOUNT ON
DECLARE @BatchSize INT = 100
-- Delete collection ciphers
WHILE @BatchSize > 0
BEGIN
BEGIN TRANSACTION Cipher_DeleteByOrganizationId_CC
DELETE TOP(@BatchSize) CC
FROM
[dbo].[CollectionCipher] CC
INNER JOIN
[dbo].[Collection] C ON C.[Id] = CC.[CollectionId]
WHERE
C.[OrganizationId] = @OrganizationId
SET @BatchSize = @@ROWCOUNT
COMMIT TRANSACTION Cipher_DeleteByOrganizationId_CC
END
-- Reset batch size
SET @BatchSize = 100
-- Delete ciphers
WHILE @BatchSize > 0
BEGIN
BEGIN TRANSACTION Cipher_DeleteByOrganizationId
DELETE TOP(@BatchSize)
FROM
[dbo].[Cipher]
WHERE
[OrganizationId] = @OrganizationId
SET @BatchSize = @@ROWCOUNT
COMMIT TRANSACTION Cipher_DeleteByOrganizationId
END
-- Cleanup organization
EXEC [dbo].[Organization_UpdateStorage] @OrganizationId
EXEC [dbo].[User_BumpAccountRevisionDateByOrganizationId] @OrganizationId
END
GO

4
util/Setup/Setup.csproj

@ -12,6 +12,10 @@ @@ -12,6 +12,10 @@
<EmbeddedResource Include="Templates\**\*.hbs" />
</ItemGroup>
<ItemGroup>
<None Remove="DbScripts\2018-09-25_00_OrgPurge.sql" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Handlebars.Net" Version="1.9.5" />
<PackageReference Include="System.Data.SqlClient" Version="4.5.1" />

Loading…
Cancel
Save