diff --git a/src/Api/Tools/Controllers/ImportCiphersController.cs b/src/Api/Tools/Controllers/ImportCiphersController.cs index 88028420b7bb..8b3ec5e26c77 100644 --- a/src/Api/Tools/Controllers/ImportCiphersController.cs +++ b/src/Api/Tools/Controllers/ImportCiphersController.cs @@ -74,10 +74,14 @@ public async Task PostImportOrganization([FromQuery] string organizationId, throw new BadRequestException("You cannot import this much data at once."); } + if (model.Ciphers.Any(c => c.ArchivedDate.HasValue)) + { + throw new BadRequestException("You cannot import archived items into an organization."); + } + var orgId = new Guid(organizationId); var collections = model.Collections.Select(c => c.ToCollection(orgId)).ToList(); - //An User is allowed to import if CanCreate Collections or has AccessToImportExport var authorized = await CheckOrgImportPermission(collections, orgId); if (!authorized) @@ -156,7 +160,7 @@ private async Task CheckOrgImportPermission(List collections, if (existingCollections.Any() && (await _authorizationService.AuthorizeAsync(User, existingCollections, BulkCollectionOperations.ImportCiphers)).Succeeded) { return true; - }; + } return false; } diff --git a/src/Infrastructure.Dapper/AdminConsole/Helpers/BulkResourceCreationService.cs b/src/Infrastructure.Dapper/AdminConsole/Helpers/BulkResourceCreationService.cs index 5a743ba02880..2be33e88461c 100644 --- a/src/Infrastructure.Dapper/AdminConsole/Helpers/BulkResourceCreationService.cs +++ b/src/Infrastructure.Dapper/AdminConsole/Helpers/BulkResourceCreationService.cs @@ -218,6 +218,8 @@ private static DataTable BuildCiphersTable(SqlBulkCopy bulkCopy, IEnumerable x.Ciphers, fixture.Build() .With(c => c.OrganizationId, Guid.NewGuid().ToString()) .With(c => c.FolderId, Guid.NewGuid().ToString()) + .With(c => c.ArchivedDate, (DateTime?)null) .CreateMany(1).ToArray()) .Create(); @@ -92,6 +93,37 @@ await sutProvider.GetDependency() ); } + [Theory, BitAutoData] + public async Task PostImportIndividual_WithArchivedDate_SavesArchivedDate(User user, + IFixture fixture, SutProvider sutProvider) + { + var archivedDate = DateTime.UtcNow; + sutProvider.GetDependency() + .SelfHosted = false; + + sutProvider.GetDependency() + .GetProperUserId(Arg.Any()) + .Returns(user.Id); + + var request = fixture.Build() + .With(x => x.Ciphers, fixture.Build() + .With(c => c.ArchivedDate, archivedDate) + .With(c => c.FolderId, (string)null) + .CreateMany(1).ToArray()) + .Create(); + + await sutProvider.Sut.PostImport(request); + + await sutProvider.GetDependency() + .Received() + .ImportIntoIndividualVaultAsync( + Arg.Any>(), + Arg.Is>(ciphers => ciphers.First().ArchivedDate == archivedDate), + Arg.Any>>(), + user.Id + ); + } + /**************************** * PostImport - Organization ****************************/ @@ -156,6 +188,7 @@ public async Task PostImportOrganization_ImportOrganizationCiphersRequestModel_S .With(x => x.Ciphers, fixture.Build() .With(c => c.OrganizationId, Guid.NewGuid().ToString()) .With(c => c.FolderId, Guid.NewGuid().ToString()) + .With(c => c.ArchivedDate, (DateTime?)null) .CreateMany(1).ToArray()) .With(y => y.Collections, fixture.Build() .With(c => c.Id, orgIdGuid) @@ -227,6 +260,7 @@ public async Task PostImportOrganization_WithAccessImportExport_Succeeds( .With(x => x.Ciphers, fixture.Build() .With(c => c.OrganizationId, Guid.NewGuid().ToString()) .With(c => c.FolderId, Guid.NewGuid().ToString()) + .With(c => c.ArchivedDate, (DateTime?)null) .CreateMany(1).ToArray()) .With(y => y.Collections, fixture.Build() .With(c => c.Id, orgIdGuid) @@ -291,6 +325,7 @@ public async Task PostImportOrganization_WithExistingCollectionsAndWithoutImport .With(x => x.Ciphers, fixture.Build() .With(c => c.OrganizationId, Guid.NewGuid().ToString()) .With(c => c.FolderId, Guid.NewGuid().ToString()) + .With(c => c.ArchivedDate, (DateTime?)null) .CreateMany(1).ToArray()) .With(y => y.Collections, fixture.Build() .With(c => c.Id, orgIdGuid) @@ -354,6 +389,7 @@ public async Task PostImportOrganization_WithoutCreatePermissions_ThrowsExceptio .With(x => x.Ciphers, fixture.Build() .With(c => c.OrganizationId, Guid.NewGuid().ToString()) .With(c => c.FolderId, Guid.NewGuid().ToString()) + .With(c => c.ArchivedDate, (DateTime?)null) .CreateMany(1).ToArray()) .With(y => y.Collections, fixture.Build() .With(c => c.Id, orgIdGuid) @@ -423,6 +459,7 @@ public async Task PostImportOrganization_CanCreateChildCollectionsWithCreateAndI Ciphers = fixture.Build() .With(_ => _.OrganizationId, orgId.ToString()) .With(_ => _.FolderId, Guid.NewGuid().ToString()) + .With(_ => _.ArchivedDate, (DateTime?)null) .CreateMany(2).ToArray(), CollectionRelationships = new List>().ToArray(), }; @@ -499,6 +536,7 @@ public async Task PostImportOrganization_CannotCreateChildCollectionsWithoutCrea Ciphers = fixture.Build() .With(_ => _.OrganizationId, orgId.ToString()) .With(_ => _.FolderId, Guid.NewGuid().ToString()) + .With(_ => _.ArchivedDate, (DateTime?)null) .CreateMany(2).ToArray(), CollectionRelationships = new List>().ToArray(), }; @@ -578,6 +616,7 @@ public async Task PostImportOrganization_ImportIntoNewCollectionWithCreatePermis Ciphers = fixture.Build() .With(_ => _.OrganizationId, orgId.ToString()) .With(_ => _.FolderId, Guid.NewGuid().ToString()) + .With(_ => _.ArchivedDate, (DateTime?)null) .CreateMany(2).ToArray(), CollectionRelationships = new List>().ToArray(), }; @@ -651,6 +690,7 @@ public async Task PostImportOrganization_ImportIntoExistingCollectionWithImportP Ciphers = fixture.Build() .With(_ => _.OrganizationId, orgId.ToString()) .With(_ => _.FolderId, Guid.NewGuid().ToString()) + .With(_ => _.ArchivedDate, (DateTime?)null) .CreateMany(2).ToArray(), CollectionRelationships = new List>().ToArray(), }; @@ -720,6 +760,7 @@ public async Task PostImportOrganization_ImportWithNoCollectionsWithCreatePermis Ciphers = fixture.Build() .With(_ => _.OrganizationId, orgId.ToString()) .With(_ => _.FolderId, Guid.NewGuid().ToString()) + .With(_ => _.ArchivedDate, (DateTime?)null) .CreateMany(2).ToArray(), CollectionRelationships = new List>().ToArray(), }; @@ -765,6 +806,63 @@ await sutProvider.GetDependency() Arg.Any()); } + [Theory, BitAutoData] + public async Task PostImportOrganization_ThrowsException_WhenAnyCipherIsArchived( + SutProvider sutProvider, + IFixture fixture, + User user + ) + { + var orgId = Guid.NewGuid(); + + sutProvider.GetDependency() + .SelfHosted = false; + sutProvider.GetDependency() + .ImportCiphersLimitation = _organizationCiphersLimitations; + + SetupUserService(sutProvider, user); + + var ciphers = fixture.Build() + .With(_ => _.ArchivedDate, DateTime.UtcNow) + .CreateMany(2).ToArray(); + + var request = new ImportOrganizationCiphersRequestModel + { + Collections = new List().ToArray(), + Ciphers = ciphers, + CollectionRelationships = new List>().ToArray(), + }; + + sutProvider.GetDependency() + .AccessImportExport(Arg.Any()) + .Returns(false); + + sutProvider.GetDependency() + .AuthorizeAsync(Arg.Any(), + Arg.Any>(), + Arg.Is>(reqs => + reqs.Contains(BulkCollectionOperations.ImportCiphers))) + .Returns(AuthorizationResult.Failed()); + + sutProvider.GetDependency() + .AuthorizeAsync(Arg.Any(), + Arg.Any>(), + Arg.Is>(reqs => + reqs.Contains(BulkCollectionOperations.Create))) + .Returns(AuthorizationResult.Success()); + + sutProvider.GetDependency() + .GetManyByOrganizationIdAsync(orgId) + .Returns(new List()); + + var exception = await Assert.ThrowsAsync(async () => + { + await sutProvider.Sut.PostImportOrganization(orgId.ToString(), request); + }); + + Assert.Equal("You cannot import archived items into an organization.", exception.Message); + } + private static void SetupUserService(SutProvider sutProvider, User user) { // This is a workaround for the NSubstitute issue with ambiguous arguments