mirror of
https://github.com/bitwarden/browser.git
synced 2024-11-23 11:56:00 +01:00
org imports
This commit is contained in:
parent
6193bf431d
commit
6f75e0bba0
2
jslib
2
jslib
@ -1 +1 @@
|
|||||||
Subproject commit ed93fa9ea3c486d78ba2591b3057245ead147a15
|
Subproject commit a600c4a5398f8893d4cfea298fcfb66f90c3d975
|
@ -15,6 +15,7 @@ import { RegisterComponent } from './accounts/register.component';
|
|||||||
import { TwoFactorComponent } from './accounts/two-factor.component';
|
import { TwoFactorComponent } from './accounts/two-factor.component';
|
||||||
|
|
||||||
import { ExportComponent as OrgExportComponent } from './organizations/tools/export.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 { ToolsComponent as OrgToolsComponent } from './organizations/tools/tools.component';
|
||||||
|
|
||||||
import { VaultComponent as OrgVaultComponent } from './organizations/vault/vault.component';
|
import { VaultComponent as OrgVaultComponent } from './organizations/vault/vault.component';
|
||||||
@ -122,7 +123,7 @@ const routes: Routes = [
|
|||||||
data: { allowedTypes: [OrganizationUserType.Owner, OrganizationUserType.Admin] },
|
data: { allowedTypes: [OrganizationUserType.Owner, OrganizationUserType.Admin] },
|
||||||
children: [
|
children: [
|
||||||
{ path: '', pathMatch: 'full', redirectTo: 'export' },
|
{ 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' } },
|
{ path: 'export', component: OrgExportComponent, data: { titleId: 'exportVault' } },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -33,6 +33,7 @@ import { TwoFactorOptionsComponent } from './accounts/two-factor-options.compone
|
|||||||
import { TwoFactorComponent } from './accounts/two-factor.component';
|
import { TwoFactorComponent } from './accounts/two-factor.component';
|
||||||
|
|
||||||
import { ExportComponent as OrgExportComponent } from './organizations/tools/export.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 { ToolsComponent as OrgToolsComponent } from './organizations/tools/tools.component';
|
||||||
|
|
||||||
import { AddEditComponent as OrgAddEditComponent } from './organizations/vault/add-edit.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,
|
OrgCiphersComponent,
|
||||||
OrgCollectionsComponent,
|
OrgCollectionsComponent,
|
||||||
OrgExportComponent,
|
OrgExportComponent,
|
||||||
|
OrgImportComponent,
|
||||||
OrgGroupingsComponent,
|
OrgGroupingsComponent,
|
||||||
OrgToolsComponent,
|
OrgToolsComponent,
|
||||||
OrganizationsComponent,
|
OrganizationsComponent,
|
||||||
|
86
src/app/organizations/tools/import.component.ts
Normal file
86
src/app/organizations/tools/import.component.ts
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -8,8 +8,10 @@
|
|||||||
<label for="type">1. {{'selectFormat' | i18n}}</label>
|
<label for="type">1. {{'selectFormat' | i18n}}</label>
|
||||||
<select id="type" name="Format" [(ngModel)]="format" class="form-control" required>
|
<select id="type" name="Format" [(ngModel)]="format" class="form-control" required>
|
||||||
<option *ngFor="let o of featuredImportOptions" [ngValue]="o.id">{{o.name}}</option>
|
<option *ngFor="let o of featuredImportOptions" [ngValue]="o.id">{{o.name}}</option>
|
||||||
<option value="-" disabled></option>
|
<ng-container *ngIf="importOptions && importOptions.length">
|
||||||
<option *ngFor="let o of importOptions" [ngValue]="o.id">{{o.name}}</option>
|
<option value="-" disabled></option>
|
||||||
|
<option *ngFor="let o of importOptions" [ngValue]="o.id">{{o.name}}</option>
|
||||||
|
</ng-container>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import {
|
import {
|
||||||
Component,
|
Component,
|
||||||
|
OnInit,
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
|
|
||||||
@ -11,6 +12,8 @@ import { CipherService } from 'jslib/abstractions/cipher.service';
|
|||||||
import { FolderService } from 'jslib/abstractions/folder.service';
|
import { FolderService } from 'jslib/abstractions/folder.service';
|
||||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||||
|
|
||||||
|
import { ImportResult } from 'jslib/models/domain/importResult';
|
||||||
|
|
||||||
import { CipherRequest } from 'jslib/models/request/cipherRequest';
|
import { CipherRequest } from 'jslib/models/request/cipherRequest';
|
||||||
import { FolderRequest } from 'jslib/models/request/folderRequest';
|
import { FolderRequest } from 'jslib/models/request/folderRequest';
|
||||||
import { ImportCiphersRequest } from 'jslib/models/request/importCiphersRequest';
|
import { ImportCiphersRequest } from 'jslib/models/request/importCiphersRequest';
|
||||||
@ -28,57 +31,22 @@ import { CipherView } from 'jslib/models/view';
|
|||||||
selector: 'app-import',
|
selector: 'app-import',
|
||||||
templateUrl: 'import.component.html',
|
templateUrl: 'import.component.html',
|
||||||
})
|
})
|
||||||
export class ImportComponent {
|
export class ImportComponent implements OnInit {
|
||||||
featuredImportOptions: any[];
|
featuredImportOptions: any[];
|
||||||
importOptions: any[];
|
importOptions: any[];
|
||||||
format: string = null;
|
format: string = null;
|
||||||
fileContents: string;
|
fileContents: string;
|
||||||
|
|
||||||
formPromise: Promise<any>;
|
formPromise: Promise<any>;
|
||||||
|
|
||||||
constructor(private i18nService: I18nService, private analytics: Angulartics2,
|
constructor(protected i18nService: I18nService, protected analytics: Angulartics2,
|
||||||
private toasterService: ToasterService, private cipherService: CipherService,
|
protected toasterService: ToasterService, protected cipherService: CipherService,
|
||||||
private folderService: FolderService, private apiService: ApiService,
|
protected folderService: FolderService, protected apiService: ApiService,
|
||||||
private router: Router) {
|
protected 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)' },
|
|
||||||
];
|
|
||||||
|
|
||||||
this.importOptions = [
|
ngOnInit() {
|
||||||
{ id: 'keepassxcsv', name: 'KeePassX (csv)' },
|
this.setImportOptions();
|
||||||
{ id: '1password6wincsv', name: '1Password 6 Windows (csv)' },
|
this.importOptions.sort((a, b) => {
|
||||||
{ 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) => {
|
|
||||||
if (a.name == null && b.name != null) {
|
if (a.name == null && b.name != null) {
|
||||||
return -1;
|
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 {
|
try {
|
||||||
this.formPromise = this.apiService.postImportCiphers(request);
|
this.formPromise = this.postImport(importResult);
|
||||||
await this.formPromise;
|
await this.formPromise;
|
||||||
this.analytics.eventTrack.next({
|
this.analytics.eventTrack.next({
|
||||||
action: 'Imported Data',
|
action: 'Imported Data',
|
||||||
@ -180,6 +136,88 @@ export class ImportComponent {
|
|||||||
return null;
|
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) {
|
private error(errorMessage: string) {
|
||||||
this.analytics.eventTrack.next({
|
this.analytics.eventTrack.next({
|
||||||
action: 'Import Data Failed',
|
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) {
|
private badData(c: CipherView) {
|
||||||
return (c.name == null || c.name === '--') &&
|
return (c.name == null || c.name === '--') &&
|
||||||
(c.login != null && (c.login.password == null || c.login.password === ''));
|
(c.login != null && (c.login.password == null || c.login.password === ''));
|
||||||
|
Loading…
Reference in New Issue
Block a user