diff --git a/jslib b/jslib
index ed93fa9ea3..a600c4a539 160000
--- a/jslib
+++ b/jslib
@@ -1 +1 @@
-Subproject commit ed93fa9ea3c486d78ba2591b3057245ead147a15
+Subproject commit a600c4a5398f8893d4cfea298fcfb66f90c3d975
diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts
index d3a9d77ced..c2b67cbb5d 100644
--- a/src/app/app-routing.module.ts
+++ b/src/app/app-routing.module.ts
@@ -15,6 +15,7 @@ import { RegisterComponent } from './accounts/register.component';
import { TwoFactorComponent } from './accounts/two-factor.component';
import { ExportComponent as OrgExportComponent } from './organizations/tools/export.component';
+import { ImportComponent as OrgImportComponent } from './organizations/tools/import.component';
import { ToolsComponent as OrgToolsComponent } from './organizations/tools/tools.component';
import { VaultComponent as OrgVaultComponent } from './organizations/vault/vault.component';
@@ -122,7 +123,7 @@ const routes: Routes = [
data: { allowedTypes: [OrganizationUserType.Owner, OrganizationUserType.Admin] },
children: [
{ path: '', pathMatch: 'full', redirectTo: 'export' },
- // { path: 'import', component: ImportComponent, data: { titleId: 'importData' } },
+ { path: 'import', component: OrgImportComponent, data: { titleId: 'importData' } },
{ path: 'export', component: OrgExportComponent, data: { titleId: 'exportVault' } },
],
},
diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index 51c28cb4bc..7676a10a0b 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -33,6 +33,7 @@ import { TwoFactorOptionsComponent } from './accounts/two-factor-options.compone
import { TwoFactorComponent } from './accounts/two-factor.component';
import { ExportComponent as OrgExportComponent } from './organizations/tools/export.component';
+import { ImportComponent as OrgImportComponent } from './organizations/tools/import.component';
import { ToolsComponent as OrgToolsComponent } from './organizations/tools/tools.component';
import { AddEditComponent as OrgAddEditComponent } from './organizations/vault/add-edit.component';
@@ -163,6 +164,7 @@ import { SearchCiphersPipe } from 'jslib/angular/pipes/search-ciphers.pipe';
OrgCiphersComponent,
OrgCollectionsComponent,
OrgExportComponent,
+ OrgImportComponent,
OrgGroupingsComponent,
OrgToolsComponent,
OrganizationsComponent,
diff --git a/src/app/organizations/tools/import.component.ts b/src/app/organizations/tools/import.component.ts
new file mode 100644
index 0000000000..1b8e800c63
--- /dev/null
+++ b/src/app/organizations/tools/import.component.ts
@@ -0,0 +1,86 @@
+import { Component } from '@angular/core';
+import {
+ ActivatedRoute,
+ Router,
+} from '@angular/router';
+
+import { ToasterService } from 'angular2-toaster';
+import { Angulartics2 } from 'angulartics2';
+
+import { ApiService } from 'jslib/abstractions/api.service';
+import { CipherService } from 'jslib/abstractions/cipher.service';
+import { CollectionService } from 'jslib/abstractions/collection.service';
+import { FolderService } from 'jslib/abstractions/folder.service';
+import { I18nService } from 'jslib/abstractions/i18n.service';
+
+import { Importer } from 'jslib/importers/importer';
+
+import { CipherRequest } from 'jslib/models/request/cipherRequest';
+import { CollectionRequest } from 'jslib/models/request/collectionRequest';
+import { ImportOrganizationCiphersRequest } from 'jslib/models/request/importOrganizationCiphersRequest';
+import { KvpRequest } from 'jslib/models/request/kvpRequest';
+
+import { ImportResult } from 'jslib/models/domain/importResult';
+
+import { ImportComponent as BaseImportComponent } from '../../tools/import.component';
+
+@Component({
+ selector: 'app-org-import',
+ templateUrl: '../../tools/import.component.html',
+})
+export class ImportComponent extends BaseImportComponent {
+ organizationId: string;
+
+ constructor(i18nService: I18nService, analytics: Angulartics2,
+ toasterService: ToasterService, cipherService: CipherService,
+ folderService: FolderService, apiService: ApiService,
+ router: Router, private collectionService: CollectionService,
+ private route: ActivatedRoute) {
+ super(i18nService, analytics, toasterService, cipherService, folderService, apiService, router);
+ }
+
+ ngOnInit() {
+ this.route.parent.parent.params.subscribe(async (params) => {
+ this.organizationId = params.organizationId;
+ super.ngOnInit();
+ });
+ }
+
+ protected async postImport(importResult: ImportResult) {
+ const request = new ImportOrganizationCiphersRequest();
+ for (let i = 0; i < importResult.ciphers.length; i++) {
+ importResult.ciphers[i].organizationId = this.organizationId;
+ const c = await this.cipherService.encrypt(importResult.ciphers[i]);
+ request.ciphers.push(new CipherRequest(c));
+ }
+ if (importResult.collections != null) {
+ for (let i = 0; i < importResult.collections.length; i++) {
+ importResult.collections[i].organizationId = this.organizationId;
+ const c = await this.collectionService.encrypt(importResult.collections[i]);
+ request.collections.push(new CollectionRequest(c));
+ }
+ }
+ if (importResult.collectionRelationships != null) {
+ importResult.collectionRelationships.forEach((v: number, k: number) =>
+ request.collectionRelationships.push(new KvpRequest(k, v)));
+ }
+ return await this.apiService.postImportOrganizationCiphers(this.organizationId, request);
+ }
+
+ protected setImportOptions() {
+ this.featuredImportOptions = [
+ { id: null, name: '-- ' + this.i18nService.t('select') + ' --' },
+ { id: 'bitwardencsv', name: 'Bitwarden (csv)' },
+ { id: 'lastpasscsv', name: 'LastPass (csv)' },
+ ];
+ this.importOptions = [];
+ }
+
+ protected getImporter(): Importer {
+ const importer = super.getImporter();
+ if (importer != null) {
+ importer.organization = true;
+ }
+ return importer;
+ }
+}
diff --git a/src/app/tools/import.component.html b/src/app/tools/import.component.html
index 7f30505912..b50fc50cd2 100644
--- a/src/app/tools/import.component.html
+++ b/src/app/tools/import.component.html
@@ -8,8 +8,10 @@
diff --git a/src/app/tools/import.component.ts b/src/app/tools/import.component.ts
index def085f1d9..d011998ead 100644
--- a/src/app/tools/import.component.ts
+++ b/src/app/tools/import.component.ts
@@ -1,5 +1,6 @@
import {
Component,
+ OnInit,
} from '@angular/core';
import { Router } from '@angular/router';
@@ -11,6 +12,8 @@ import { CipherService } from 'jslib/abstractions/cipher.service';
import { FolderService } from 'jslib/abstractions/folder.service';
import { I18nService } from 'jslib/abstractions/i18n.service';
+import { ImportResult } from 'jslib/models/domain/importResult';
+
import { CipherRequest } from 'jslib/models/request/cipherRequest';
import { FolderRequest } from 'jslib/models/request/folderRequest';
import { ImportCiphersRequest } from 'jslib/models/request/importCiphersRequest';
@@ -28,57 +31,22 @@ import { CipherView } from 'jslib/models/view';
selector: 'app-import',
templateUrl: 'import.component.html',
})
-export class ImportComponent {
+export class ImportComponent implements OnInit {
featuredImportOptions: any[];
importOptions: any[];
format: string = null;
fileContents: string;
-
formPromise: Promise;
- constructor(private i18nService: I18nService, private analytics: Angulartics2,
- private toasterService: ToasterService, private cipherService: CipherService,
- private folderService: FolderService, private apiService: ApiService,
- private router: Router) {
- this.featuredImportOptions = [
- { id: null, name: '-- ' + i18nService.t('select') + ' --' },
- { id: 'bitwardencsv', name: 'Bitwarden (csv)' },
- { id: 'lastpasscsv', name: 'LastPass (csv)' },
- { id: 'chromecsv', name: 'Chrome (csv)' },
- { id: 'firefoxcsv', name: 'Firefox (csv)' },
- { id: 'keepass2xml', name: 'KeePass 2 (xml)' },
- { id: '1password1pif', name: '1Password (1pif)' },
- { id: 'dashlanecsv', name: 'Dashlane (csv)' },
- ];
+ constructor(protected i18nService: I18nService, protected analytics: Angulartics2,
+ protected toasterService: ToasterService, protected cipherService: CipherService,
+ protected folderService: FolderService, protected apiService: ApiService,
+ protected router: Router) {
+ }
- this.importOptions = [
- { id: 'keepassxcsv', name: 'KeePassX (csv)' },
- { id: '1password6wincsv', name: '1Password 6 Windows (csv)' },
- { id: 'roboformcsv', name: 'RoboForm (csv)' },
- { id: 'keepercsv', name: 'Keeper (csv)' },
- { id: 'enpasscsv', name: 'Enpass (csv)' },
- { id: 'safeincloudxml', name: 'SafeInCloud (xml)' },
- { id: 'pwsafexml', name: 'Password Safe (xml)' },
- { id: 'stickypasswordxml', name: 'Sticky Password (xml)' },
- { id: 'msecurecsv', name: 'mSecure (csv)' },
- { id: 'truekeycsv', name: 'True Key (csv)' },
- { id: 'passwordbossjson', name: 'Password Boss (json)' },
- { id: 'zohovaultcsv', name: 'Zoho Vault (csv)' },
- { id: 'splashidcsv', name: 'SplashID (csv)' },
- { id: 'passworddragonxml', name: 'Password Dragon (xml)' },
- { id: 'padlockcsv', name: 'Padlock (csv)' },
- { id: 'clipperzhtml', name: 'Clipperz (html)' },
- { id: 'aviracsv', name: 'Avira (csv)' },
- { id: 'saferpasscsv', name: 'SaferPass (csv)' },
- { id: 'upmcsv', name: 'Universal Password Manager (csv)' },
- { id: 'ascendocsv', name: 'Ascendo DataVault (csv)' },
- { id: 'meldiumcsv', name: 'Meldium (csv)' },
- { id: 'passkeepcsv', name: 'PassKeep (csv)' },
- { id: 'operacsv', name: 'Opera (csv)' },
- { id: 'vivaldicsv', name: 'Vivaldi (csv)' },
- { id: 'gnomejson', name: 'GNOME Passwords and Keys/Seahorse (json)' },
- { id: 'blurcsv', name: 'Blur (csv)' },
- ].sort((a, b) => {
+ ngOnInit() {
+ this.setImportOptions();
+ this.importOptions.sort((a, b) => {
if (a.name == null && b.name != null) {
return -1;
}
@@ -141,20 +109,8 @@ export class ImportComponent {
}
}
- const request = new ImportCiphersRequest();
- for (let i = 0; i < importResult.ciphers.length; i++) {
- const c = await this.cipherService.encrypt(importResult.ciphers[i]);
- request.ciphers.push(new CipherRequest(c));
- }
- for (let i = 0; i < importResult.folders.length; i++) {
- const f = await this.folderService.encrypt(importResult.folders[i]);
- request.folders.push(new FolderRequest(f));
- }
- importResult.folderRelationships.forEach((v: number, k: number) =>
- request.folderRelationships.push(new KvpRequest(k, v)));
-
try {
- this.formPromise = this.apiService.postImportCiphers(request);
+ this.formPromise = this.postImport(importResult);
await this.formPromise;
this.analytics.eventTrack.next({
action: 'Imported Data',
@@ -180,6 +136,88 @@ export class ImportComponent {
return null;
}
+ protected async postImport(importResult: ImportResult) {
+ const request = new ImportCiphersRequest();
+ for (let i = 0; i < importResult.ciphers.length; i++) {
+ const c = await this.cipherService.encrypt(importResult.ciphers[i]);
+ request.ciphers.push(new CipherRequest(c));
+ }
+ if (importResult.folders != null) {
+ for (let i = 0; i < importResult.folders.length; i++) {
+ const f = await this.folderService.encrypt(importResult.folders[i]);
+ request.folders.push(new FolderRequest(f));
+ }
+ }
+ if (importResult.folderRelationships != null) {
+ importResult.folderRelationships.forEach((v: number, k: number) =>
+ request.folderRelationships.push(new KvpRequest(k, v)));
+ }
+ return await this.apiService.postImportCiphers(request);
+ }
+
+ protected setImportOptions() {
+ this.featuredImportOptions = [
+ { id: null, name: '-- ' + this.i18nService.t('select') + ' --' },
+ { id: 'bitwardencsv', name: 'Bitwarden (csv)' },
+ { id: 'lastpasscsv', name: 'LastPass (csv)' },
+ { id: 'chromecsv', name: 'Chrome (csv)' },
+ { id: 'firefoxcsv', name: 'Firefox (csv)' },
+ { id: 'keepass2xml', name: 'KeePass 2 (xml)' },
+ { id: '1password1pif', name: '1Password (1pif)' },
+ { id: 'dashlanecsv', name: 'Dashlane (csv)' },
+ ];
+
+ this.importOptions = [
+ { id: 'keepassxcsv', name: 'KeePassX (csv)' },
+ { id: '1password6wincsv', name: '1Password 6 Windows (csv)' },
+ { id: 'roboformcsv', name: 'RoboForm (csv)' },
+ { id: 'keepercsv', name: 'Keeper (csv)' },
+ { id: 'enpasscsv', name: 'Enpass (csv)' },
+ { id: 'safeincloudxml', name: 'SafeInCloud (xml)' },
+ { id: 'pwsafexml', name: 'Password Safe (xml)' },
+ { id: 'stickypasswordxml', name: 'Sticky Password (xml)' },
+ { id: 'msecurecsv', name: 'mSecure (csv)' },
+ { id: 'truekeycsv', name: 'True Key (csv)' },
+ { id: 'passwordbossjson', name: 'Password Boss (json)' },
+ { id: 'zohovaultcsv', name: 'Zoho Vault (csv)' },
+ { id: 'splashidcsv', name: 'SplashID (csv)' },
+ { id: 'passworddragonxml', name: 'Password Dragon (xml)' },
+ { id: 'padlockcsv', name: 'Padlock (csv)' },
+ { id: 'clipperzhtml', name: 'Clipperz (html)' },
+ { id: 'aviracsv', name: 'Avira (csv)' },
+ { id: 'saferpasscsv', name: 'SaferPass (csv)' },
+ { id: 'upmcsv', name: 'Universal Password Manager (csv)' },
+ { id: 'ascendocsv', name: 'Ascendo DataVault (csv)' },
+ { id: 'meldiumcsv', name: 'Meldium (csv)' },
+ { id: 'passkeepcsv', name: 'PassKeep (csv)' },
+ { id: 'operacsv', name: 'Opera (csv)' },
+ { id: 'vivaldicsv', name: 'Vivaldi (csv)' },
+ { id: 'gnomejson', name: 'GNOME Passwords and Keys/Seahorse (json)' },
+ { id: 'blurcsv', name: 'Blur (csv)' },
+ ];
+ }
+
+ protected getImporter(): Importer {
+ if (this.format == null || this.format === '') {
+ return null;
+ }
+
+ switch (this.format) {
+ case 'bitwardencsv':
+ return new BitwardenCsvImporter();
+ case 'lastpasscsv':
+ return new LastPassCsvImporter();
+ case 'keepassxcsv':
+ return new KeePassXCsvImporter();
+ case 'aviracsv':
+ return new AviraCsvImporter();
+ case 'blurcsv':
+ return new BlurCsvImporter();
+ default:
+ return null;
+ }
+ }
+
private error(errorMessage: string) {
this.analytics.eventTrack.next({
action: 'Import Data Failed',
@@ -213,27 +251,6 @@ export class ImportComponent {
});
}
- private getImporter(): Importer {
- if (this.format == null || this.format === '') {
- return null;
- }
-
- switch (this.format) {
- case 'bitwardencsv':
- return new BitwardenCsvImporter();
- case 'lastpasscsv':
- return new LastPassCsvImporter();
- case 'keepassxcsv':
- return new KeePassXCsvImporter();
- case 'aviracsv':
- return new AviraCsvImporter();
- case 'blurcsv':
- return new BlurCsvImporter();
- default:
- return null;
- }
- }
-
private badData(c: CipherView) {
return (c.name == null || c.name === '--') &&
(c.login != null && (c.login.password == null || c.login.password === ''));