mirror of
https://github.com/bitwarden/browser
synced 2026-02-12 14:34:02 +00:00
Merge branch 'main' into ps/extension-refresh
This commit is contained in:
@@ -18,7 +18,7 @@
|
||||
"yargs": "17.7.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "20.17.1",
|
||||
"@types/node": "22.9.0",
|
||||
"@types/node-ipc": "9.2.3",
|
||||
"typescript": "4.7.4"
|
||||
}
|
||||
@@ -106,12 +106,12 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "20.17.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.1.tgz",
|
||||
"integrity": "sha512-j2VlPv1NnwPJbaCNv69FO/1z4lId0QmGvpT41YxitRtWlg96g/j8qcv2RKsLKe2F6OJgyXhupN1Xo17b2m139Q==",
|
||||
"version": "22.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.9.0.tgz",
|
||||
"integrity": "sha512-vuyHg81vvWA1Z1ELfvLko2c8f34gyA0zaic0+Rllc5lbCnbSyuvb2Oxpm6TAUAC/2xZN3QGqxBNggD1nNR2AfQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~6.19.2"
|
||||
"undici-types": "~6.19.8"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node-ipc": {
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
"yargs": "17.7.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "20.17.1",
|
||||
"@types/node": "22.9.0",
|
||||
"@types/node-ipc": "9.2.3",
|
||||
"typescript": "4.7.4"
|
||||
},
|
||||
|
||||
@@ -428,7 +428,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
return;
|
||||
}
|
||||
|
||||
this.addType = type;
|
||||
this.addType = type || this.activeFilter.cipherType;
|
||||
this.action = "add";
|
||||
this.cipherId = null;
|
||||
this.prefillNewCipherFromFilter();
|
||||
|
||||
@@ -6,8 +6,10 @@ import { ListResponse } from "@bitwarden/common/models/response/list.response";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
|
||||
import { CoreOrganizationModule } from "../../core-organization.module";
|
||||
import { GroupDetailsView } from "../../views/group-details.view";
|
||||
import { GroupView } from "../../views/group.view";
|
||||
|
||||
import { AddEditGroupDetail } from "./../../views/add-edit-group-detail";
|
||||
import { GroupRequest } from "./requests/group.request";
|
||||
import { OrganizationGroupBulkRequest } from "./requests/organization-group-bulk.request";
|
||||
import { GroupDetailsResponse, GroupResponse } from "./responses/group.response";
|
||||
@@ -15,13 +17,13 @@ import { GroupDetailsResponse, GroupResponse } from "./responses/group.response"
|
||||
@Injectable({
|
||||
providedIn: "root",
|
||||
})
|
||||
export class GroupService {
|
||||
export class GroupApiService {
|
||||
constructor(
|
||||
protected apiService: ApiService,
|
||||
protected configService: ConfigService,
|
||||
) {}
|
||||
|
||||
async get(orgId: string, groupId: string): Promise<GroupView> {
|
||||
async get(orgId: string, groupId: string): Promise<GroupDetailsView> {
|
||||
const r = await this.apiService.send(
|
||||
"GET",
|
||||
"/organizations/" + orgId + "/groups/" + groupId + "/details",
|
||||
@@ -30,7 +32,7 @@ export class GroupService {
|
||||
true,
|
||||
);
|
||||
|
||||
return GroupView.fromResponse(new GroupDetailsResponse(r));
|
||||
return GroupDetailsView.fromResponse(new GroupDetailsResponse(r));
|
||||
}
|
||||
|
||||
async getAll(orgId: string): Promise<GroupView[]> {
|
||||
@@ -44,12 +46,26 @@ export class GroupService {
|
||||
|
||||
const listResponse = new ListResponse(r, GroupDetailsResponse);
|
||||
|
||||
return Promise.all(listResponse.data?.map((gr) => GroupView.fromResponse(gr))) ?? [];
|
||||
return listResponse.data.map((gr) => GroupView.fromResponse(gr));
|
||||
}
|
||||
|
||||
async getAllDetails(orgId: string): Promise<GroupDetailsView[]> {
|
||||
const r = await this.apiService.send(
|
||||
"GET",
|
||||
"/organizations/" + orgId + "/groups/details",
|
||||
null,
|
||||
true,
|
||||
true,
|
||||
);
|
||||
|
||||
const listResponse = new ListResponse(r, GroupDetailsResponse);
|
||||
|
||||
return listResponse.data.map((gr) => GroupDetailsView.fromResponse(gr));
|
||||
}
|
||||
}
|
||||
|
||||
@Injectable({ providedIn: CoreOrganizationModule })
|
||||
export class InternalGroupService extends GroupService {
|
||||
export class InternalGroupApiService extends GroupApiService {
|
||||
constructor(
|
||||
protected apiService: ApiService,
|
||||
protected configService: ConfigService,
|
||||
@@ -77,7 +93,7 @@ export class InternalGroupService extends GroupService {
|
||||
);
|
||||
}
|
||||
|
||||
async save(group: GroupView): Promise<GroupView> {
|
||||
async save(group: AddEditGroupDetail): Promise<GroupView> {
|
||||
const request = new GroupRequest();
|
||||
request.name = group.name;
|
||||
request.users = group.members;
|
||||
@@ -1,2 +1,2 @@
|
||||
export * from "./group/group.service";
|
||||
export * from "./group/group-api.service";
|
||||
export * from "./user-admin.service";
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
import { CollectionAccessSelectionView } from "@bitwarden/admin-console/common";
|
||||
|
||||
export interface AddEditGroupDetail {
|
||||
id: string;
|
||||
organizationId: string;
|
||||
name: string;
|
||||
externalId: string;
|
||||
collections: CollectionAccessSelectionView[];
|
||||
members: string[];
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import { CollectionAccessSelectionView } from "@bitwarden/admin-console/common";
|
||||
import { View } from "@bitwarden/common/models/view/view";
|
||||
|
||||
import { GroupDetailsResponse } from "../services/group/responses/group.response";
|
||||
|
||||
export class GroupDetailsView implements View {
|
||||
id: string;
|
||||
organizationId: string;
|
||||
name: string;
|
||||
externalId: string;
|
||||
collections: CollectionAccessSelectionView[] = [];
|
||||
|
||||
static fromResponse(response: GroupDetailsResponse): GroupDetailsView {
|
||||
const view: GroupDetailsView = Object.assign(new GroupDetailsView(), response);
|
||||
|
||||
view.collections = response.collections.map((c) => new CollectionAccessSelectionView(c));
|
||||
|
||||
return view;
|
||||
}
|
||||
}
|
||||
@@ -1,23 +1,14 @@
|
||||
import { CollectionAccessSelectionView } from "@bitwarden/admin-console/common";
|
||||
import { View } from "@bitwarden/common/models/view/view";
|
||||
|
||||
import { GroupDetailsResponse, GroupResponse } from "../services/group/responses/group.response";
|
||||
import { GroupResponse } from "../services/group/responses/group.response";
|
||||
|
||||
export class GroupView implements View {
|
||||
id: string;
|
||||
organizationId: string;
|
||||
name: string;
|
||||
externalId: string;
|
||||
collections: CollectionAccessSelectionView[] = [];
|
||||
members: string[] = [];
|
||||
|
||||
static fromResponse(response: GroupResponse): GroupView {
|
||||
const view: GroupView = Object.assign(new GroupView(), response) as GroupView;
|
||||
|
||||
if (response instanceof GroupDetailsResponse && response.collections != undefined) {
|
||||
view.collections = response.collections.map((c) => new CollectionAccessSelectionView(c));
|
||||
}
|
||||
|
||||
return view;
|
||||
return Object.assign(new GroupView(), response);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from "./group.view";
|
||||
export * from "./group-details.view";
|
||||
export * from "./organization-user.view";
|
||||
export * from "./organization-user-admin-view";
|
||||
|
||||
@@ -30,7 +30,7 @@ import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/pl
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
import { DialogService, ToastService } from "@bitwarden/components";
|
||||
|
||||
import { InternalGroupService as GroupService, GroupView } from "../core";
|
||||
import { InternalGroupApiService as GroupService } from "../core";
|
||||
import {
|
||||
AccessItemType,
|
||||
AccessItemValue,
|
||||
@@ -40,6 +40,8 @@ import {
|
||||
PermissionMode,
|
||||
} from "../shared/components/access-selector";
|
||||
|
||||
import { AddEditGroupDetail } from "./../core/views/add-edit-group-detail";
|
||||
|
||||
/**
|
||||
* Indices for the available tabs in the dialog
|
||||
*/
|
||||
@@ -105,7 +107,7 @@ export class GroupAddEditComponent implements OnInit, OnDestroy {
|
||||
title: string;
|
||||
collections: AccessItemView[] = [];
|
||||
members: Array<AccessItemView & { userId: UserId }> = [];
|
||||
group: GroupView;
|
||||
group: AddEditGroupDetail;
|
||||
|
||||
groupForm = this.formBuilder.group({
|
||||
name: ["", [Validators.required, Validators.maxLength(100)]],
|
||||
@@ -149,7 +151,7 @@ export class GroupAddEditComponent implements OnInit, OnDestroy {
|
||||
);
|
||||
}
|
||||
|
||||
private groupDetails$: Observable<GroupView | undefined> = of(this.editMode).pipe(
|
||||
private groupDetails$: Observable<AddEditGroupDetail | undefined> = of(this.editMode).pipe(
|
||||
concatMap((editMode) => {
|
||||
if (!editMode) {
|
||||
return of(undefined);
|
||||
@@ -159,9 +161,11 @@ export class GroupAddEditComponent implements OnInit, OnDestroy {
|
||||
this.groupService.get(this.organizationId, this.groupId),
|
||||
this.apiService.getGroupUsers(this.organizationId, this.groupId),
|
||||
]).pipe(
|
||||
map(([groupView, users]) => {
|
||||
groupView.members = users;
|
||||
return groupView;
|
||||
map(([groupView, users]): AddEditGroupDetail => {
|
||||
return {
|
||||
...groupView,
|
||||
members: users,
|
||||
};
|
||||
}),
|
||||
catchError((e: unknown) => {
|
||||
if (e instanceof ErrorResponse) {
|
||||
@@ -295,14 +299,16 @@ export class GroupAddEditComponent implements OnInit, OnDestroy {
|
||||
return;
|
||||
}
|
||||
|
||||
const groupView = new GroupView();
|
||||
groupView.id = this.groupId;
|
||||
groupView.organizationId = this.organizationId;
|
||||
|
||||
const formValue = this.groupForm.value;
|
||||
groupView.name = formValue.name;
|
||||
groupView.members = formValue.members?.map((m) => m.id) ?? [];
|
||||
groupView.collections = formValue.collections.map((c) => convertToSelectionView(c));
|
||||
|
||||
const groupView: AddEditGroupDetail = {
|
||||
id: this.groupId,
|
||||
organizationId: this.organizationId,
|
||||
name: formValue.name,
|
||||
members: formValue.members?.map((m) => m.id) ?? [],
|
||||
collections: formValue.collections.map((c) => convertToSelectionView(c)),
|
||||
externalId: formValue.externalId,
|
||||
};
|
||||
|
||||
await this.groupService.save(groupView);
|
||||
|
||||
@@ -346,7 +352,10 @@ export class GroupAddEditComponent implements OnInit, OnDestroy {
|
||||
/**
|
||||
* Maps the group's current collection access to AccessItemValues to populate the access-selector's FormControl
|
||||
*/
|
||||
function mapToAccessSelections(group: GroupView, items: AccessItemView[]): AccessItemValue[] {
|
||||
function mapToAccessSelections(
|
||||
group: AddEditGroupDetail,
|
||||
items: AccessItemView[],
|
||||
): AccessItemValue[] {
|
||||
return (
|
||||
group.collections
|
||||
// The FormControl value only represents editable collection access - exclude readonly access selections
|
||||
@@ -365,7 +374,7 @@ function mapToAccessSelections(group: GroupView, items: AccessItemView[]): Acces
|
||||
function mapToAccessItemViews(
|
||||
collections: CollectionAdminView[],
|
||||
organization: Organization,
|
||||
group?: GroupView,
|
||||
group?: AddEditGroupDetail,
|
||||
): AccessItemView[] {
|
||||
return (
|
||||
collections
|
||||
|
||||
@@ -28,7 +28,7 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { DialogService, TableDataSource, ToastService } from "@bitwarden/components";
|
||||
|
||||
import { InternalGroupService as GroupService, GroupView } from "../core";
|
||||
import { GroupDetailsView, InternalGroupApiService as GroupService } from "../core";
|
||||
|
||||
import {
|
||||
GroupAddEditDialogResultType,
|
||||
@@ -40,7 +40,7 @@ type GroupDetailsRow = {
|
||||
/**
|
||||
* Details used for displaying group information
|
||||
*/
|
||||
details: GroupView;
|
||||
details: GroupDetailsView;
|
||||
|
||||
/**
|
||||
* True if the group is selected in the table
|
||||
@@ -108,7 +108,7 @@ export class GroupsComponent {
|
||||
),
|
||||
// groups
|
||||
this.refreshGroups$.pipe(
|
||||
switchMap(() => this.groupService.getAll(this.organizationId)),
|
||||
switchMap(() => this.groupService.getAllDetails(this.organizationId)),
|
||||
),
|
||||
]),
|
||||
),
|
||||
|
||||
@@ -35,8 +35,8 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic
|
||||
import { DialogService, ToastService } from "@bitwarden/components";
|
||||
|
||||
import {
|
||||
GroupService,
|
||||
GroupView,
|
||||
GroupApiService,
|
||||
GroupDetailsView,
|
||||
OrganizationUserAdminView,
|
||||
UserAdminService,
|
||||
} from "../../../core";
|
||||
@@ -144,7 +144,7 @@ export class MemberDialogComponent implements OnDestroy {
|
||||
private formBuilder: FormBuilder,
|
||||
// TODO: We should really look into consolidating naming conventions for these services
|
||||
private collectionAdminService: CollectionAdminService,
|
||||
private groupService: GroupService,
|
||||
private groupService: GroupApiService,
|
||||
private userService: UserAdminService,
|
||||
private organizationUserApiService: OrganizationUserApiService,
|
||||
private dialogService: DialogService,
|
||||
@@ -171,8 +171,8 @@ export class MemberDialogComponent implements OnDestroy {
|
||||
const groups$ = this.organization$.pipe(
|
||||
switchMap((organization) =>
|
||||
organization.useGroups
|
||||
? this.groupService.getAll(this.params.organizationId)
|
||||
: of([] as GroupView[]),
|
||||
? this.groupService.getAllDetails(this.params.organizationId)
|
||||
: of([] as GroupDetailsView[]),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -278,7 +278,7 @@ export class MemberDialogComponent implements OnDestroy {
|
||||
|
||||
private loadOrganizationUser(
|
||||
userDetails: OrganizationUserAdminView,
|
||||
groups: GroupView[],
|
||||
groups: GroupDetailsView[],
|
||||
collections: CollectionAdminView[],
|
||||
organization: Organization,
|
||||
) {
|
||||
@@ -635,7 +635,7 @@ function mapCollectionToAccessItemView(
|
||||
collection: CollectionAdminView,
|
||||
organization: Organization,
|
||||
accessSelection?: CollectionAccessSelectionView,
|
||||
group?: GroupView,
|
||||
group?: GroupDetailsView,
|
||||
): AccessItemView {
|
||||
return {
|
||||
type: AccessItemType.Collection,
|
||||
@@ -648,7 +648,7 @@ function mapCollectionToAccessItemView(
|
||||
};
|
||||
}
|
||||
|
||||
function mapGroupToAccessItemView(group: GroupView): AccessItemView {
|
||||
function mapGroupToAccessItemView(group: GroupDetailsView): AccessItemView {
|
||||
return {
|
||||
type: AccessItemType.Group,
|
||||
id: group.id,
|
||||
|
||||
@@ -56,7 +56,7 @@ import {
|
||||
} from "../../../billing/organizations/change-plan-dialog.component";
|
||||
import { BaseMembersComponent } from "../../common/base-members.component";
|
||||
import { PeopleTableDataSource } from "../../common/people-table-data-source";
|
||||
import { GroupService } from "../core";
|
||||
import { GroupApiService } from "../core";
|
||||
import { OrganizationUserView } from "../core/views/organization-user.view";
|
||||
import { openEntityEventsDialog } from "../manage/entity-events.component";
|
||||
|
||||
@@ -129,7 +129,7 @@ export class MembersComponent extends BaseMembersComponent<OrganizationUserView>
|
||||
private organizationApiService: OrganizationApiServiceAbstraction,
|
||||
private organizationUserApiService: OrganizationUserApiService,
|
||||
private router: Router,
|
||||
private groupService: GroupService,
|
||||
private groupService: GroupApiService,
|
||||
private collectionService: CollectionService,
|
||||
private billingApiService: BillingApiServiceAbstraction,
|
||||
private modalService: ModalService,
|
||||
|
||||
@@ -29,7 +29,7 @@ import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/pl
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { BitValidators, DialogService } from "@bitwarden/components";
|
||||
|
||||
import { GroupService, GroupView } from "../../../admin-console/organizations/core";
|
||||
import { GroupApiService, GroupView } from "../../../admin-console/organizations/core";
|
||||
import { PermissionMode } from "../../../admin-console/organizations/shared/components/access-selector/access-selector.component";
|
||||
import {
|
||||
AccessItemType,
|
||||
@@ -101,7 +101,7 @@ export class CollectionDialogComponent implements OnInit, OnDestroy {
|
||||
private formBuilder: FormBuilder,
|
||||
private dialogRef: DialogRef<CollectionDialogResult>,
|
||||
private organizationService: OrganizationService,
|
||||
private groupService: GroupService,
|
||||
private groupService: GroupApiService,
|
||||
private collectionAdminService: CollectionAdminService,
|
||||
private i18nService: I18nService,
|
||||
private platformUtilsService: PlatformUtilsService,
|
||||
|
||||
@@ -14,7 +14,7 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { DialogService } from "@bitwarden/components";
|
||||
|
||||
import { GroupService, GroupView } from "../../../admin-console/organizations/core";
|
||||
import { GroupApiService, GroupView } from "../../../admin-console/organizations/core";
|
||||
import {
|
||||
AccessItemType,
|
||||
AccessItemValue,
|
||||
@@ -61,7 +61,7 @@ export class BulkCollectionsDialogComponent implements OnDestroy {
|
||||
private dialogRef: DialogRef<BulkCollectionsDialogResult>,
|
||||
private formBuilder: FormBuilder,
|
||||
private organizationService: OrganizationService,
|
||||
private groupService: GroupService,
|
||||
private groupService: GroupApiService,
|
||||
private organizationUserApiService: OrganizationUserApiService,
|
||||
private platformUtilsService: PlatformUtilsService,
|
||||
private i18nService: I18nService,
|
||||
|
||||
@@ -81,7 +81,7 @@ import {
|
||||
PasswordRepromptService,
|
||||
} from "@bitwarden/vault";
|
||||
|
||||
import { GroupService, GroupView } from "../../admin-console/organizations/core";
|
||||
import { GroupApiService, GroupView } from "../../admin-console/organizations/core";
|
||||
import { openEntityEventsDialog } from "../../admin-console/organizations/manage/entity-events.component";
|
||||
import { TrialFlowService } from "../../billing/services/trial-flow.service";
|
||||
import { FreeTrial } from "../../core/types/free-trial";
|
||||
@@ -234,7 +234,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
private collectionAdminService: CollectionAdminService,
|
||||
private searchService: SearchService,
|
||||
private searchPipe: SearchPipe,
|
||||
private groupService: GroupService,
|
||||
private groupService: GroupApiService,
|
||||
private logService: LogService,
|
||||
private eventCollectionService: EventCollectionService,
|
||||
private totpService: TotpService,
|
||||
|
||||
@@ -40,6 +40,8 @@ export enum FeatureFlag {
|
||||
CriticalApps = "pm-14466-risk-insights-critical-application",
|
||||
TrialPaymentOptional = "PM-8163-trial-payment",
|
||||
SecurityTasks = "security-tasks",
|
||||
NewDeviceVerificationTemporaryDismiss = "new-device-temporary-dismiss",
|
||||
NewDeviceVerificationPermanentDismiss = "new-device-permanent-dismiss",
|
||||
}
|
||||
|
||||
export type AllowedFeatureFlagTypes = boolean | number | string;
|
||||
@@ -90,6 +92,8 @@ export const DefaultFeatureFlagValue = {
|
||||
[FeatureFlag.CriticalApps]: FALSE,
|
||||
[FeatureFlag.TrialPaymentOptional]: FALSE,
|
||||
[FeatureFlag.SecurityTasks]: FALSE,
|
||||
[FeatureFlag.NewDeviceVerificationTemporaryDismiss]: FALSE,
|
||||
[FeatureFlag.NewDeviceVerificationPermanentDismiss]: FALSE,
|
||||
} satisfies Record<FeatureFlag, AllowedFeatureFlagTypes>;
|
||||
|
||||
export type DefaultFeatureFlagValueType = typeof DefaultFeatureFlagValue;
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
export const data = `"Password Name","Description","Password URL","SecretData","Notes","CustomData","Tags","Classification","Favorite","login_totp","Folder Name"
|
||||
XYZ Test,,https://abc.xyz.de:5001/#/login,"SecretType:Web Account
|
||||
User Name:email@domain.de
|
||||
Password:PcY_IQEXIjKGj8YW
|
||||
",,"",,E,0,otpauth://totp?secret=PI2XO5TW0DF0SHTYOVZXOOBVHFEWM6JU&algorithm=SHA1&period=30&digits=6,folderName`;
|
||||
88
libs/importer/spec/zohovault-csv-importer.spec.ts
Normal file
88
libs/importer/spec/zohovault-csv-importer.spec.ts
Normal file
@@ -0,0 +1,88 @@
|
||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||
import { LoginUriView } from "@bitwarden/common/vault/models/view/login-uri.view";
|
||||
import { LoginView } from "@bitwarden/common/vault/models/view/login.view";
|
||||
|
||||
import { ZohoVaultCsvImporter } from "../src/importers";
|
||||
|
||||
import { data as samplezohovaultcsvdata } from "./test-data/zohovault/sample-zohovault-data.csv";
|
||||
|
||||
const CipherData = [
|
||||
{
|
||||
title: "should parse Zoho Vault CSV format",
|
||||
csv: samplezohovaultcsvdata,
|
||||
expected: Object.assign(new CipherView(), {
|
||||
id: null,
|
||||
organizationId: null,
|
||||
folderId: null,
|
||||
name: "XYZ Test",
|
||||
login: Object.assign(new LoginView(), {
|
||||
username: "email@domain.de",
|
||||
password: "PcY_IQEXIjKGj8YW",
|
||||
uris: [
|
||||
Object.assign(new LoginUriView(), {
|
||||
uri: "https://abc.xyz.de:5001/#/login",
|
||||
}),
|
||||
],
|
||||
totp: "otpauth://totp?secret=PI2XO5TW0DF0SHTYOVZXOOBVHFEWM6JU&algorithm=SHA1&period=30&digits=6",
|
||||
}),
|
||||
type: 1,
|
||||
favorite: false,
|
||||
}),
|
||||
},
|
||||
];
|
||||
|
||||
describe("Zoho Vault CSV Importer", () => {
|
||||
it("should not succeed given no data", async () => {
|
||||
const importer = new ZohoVaultCsvImporter();
|
||||
const result = await importer.parse("");
|
||||
expect(result != null).toBe(true);
|
||||
expect(result.success).toBe(false);
|
||||
});
|
||||
|
||||
CipherData.forEach((data) => {
|
||||
it(data.title, async () => {
|
||||
const importer = new ZohoVaultCsvImporter();
|
||||
const result = await importer.parse(data.csv);
|
||||
expect(result != null).toBe(true);
|
||||
expect(result.ciphers.length).toBeGreaterThan(0);
|
||||
|
||||
const cipher = result.ciphers.shift();
|
||||
let property: keyof typeof data.expected;
|
||||
for (property in data.expected) {
|
||||
// eslint-disable-next-line
|
||||
if (data.expected.hasOwnProperty(property)) {
|
||||
// eslint-disable-next-line
|
||||
expect(cipher.hasOwnProperty(property)).toBe(true);
|
||||
expect(cipher[property]).toEqual(data.expected[property]);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it("should create folder and assign ciphers", async () => {
|
||||
const importer = new ZohoVaultCsvImporter();
|
||||
const result = await importer.parse(samplezohovaultcsvdata);
|
||||
expect(result != null).toBe(true);
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.ciphers.length).toBeGreaterThan(0);
|
||||
|
||||
const folder = result.folders.shift();
|
||||
expect(folder.name).toBe("folderName");
|
||||
|
||||
expect(result.folderRelationships[0]).toEqual([0, 0]);
|
||||
});
|
||||
|
||||
it("should create collection and assign ciphers when importing into an organization", async () => {
|
||||
const importer = new ZohoVaultCsvImporter();
|
||||
importer.organizationId = "someOrgId";
|
||||
const result = await importer.parse(samplezohovaultcsvdata);
|
||||
expect(result != null).toBe(true);
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.ciphers.length).toBeGreaterThan(0);
|
||||
|
||||
const collection = result.collections.shift();
|
||||
expect(collection.name).toBe("folderName");
|
||||
|
||||
expect(result.collectionRelationships[0]).toEqual([0, 0]);
|
||||
});
|
||||
});
|
||||
@@ -13,7 +13,6 @@ export class ZohoVaultCsvImporter extends BaseImporter implements Importer {
|
||||
result.success = false;
|
||||
return Promise.resolve(result);
|
||||
}
|
||||
|
||||
results.forEach((value) => {
|
||||
if (
|
||||
this.isNullOrWhitespace(value["Password Name"]) &&
|
||||
@@ -21,7 +20,7 @@ export class ZohoVaultCsvImporter extends BaseImporter implements Importer {
|
||||
) {
|
||||
return;
|
||||
}
|
||||
this.processFolder(result, this.getValueOrDefault(value.ChamberName));
|
||||
this.processFolder(result, this.getValueOrDefault(value["Folder Name"]));
|
||||
const cipher = this.initLoginCipher();
|
||||
cipher.favorite = this.getValueOrDefault(value.Favorite, "0") === "1";
|
||||
cipher.notes = this.getValueOrDefault(value.Notes);
|
||||
@@ -32,6 +31,7 @@ export class ZohoVaultCsvImporter extends BaseImporter implements Importer {
|
||||
cipher.login.uris = this.makeUriArray(
|
||||
this.getValueOrDefault(value["Password URL"], this.getValueOrDefault(value["Secret URL"])),
|
||||
);
|
||||
cipher.login.totp = this.getValueOrDefault(value["login_totp"]);
|
||||
this.parseData(cipher, value.SecretData);
|
||||
this.parseData(cipher, value.CustomData);
|
||||
this.convertToNoteIfNeeded(cipher);
|
||||
|
||||
28
package-lock.json
generated
28
package-lock.json
generated
@@ -111,7 +111,7 @@
|
||||
"@types/koa-json": "2.0.23",
|
||||
"@types/lowdb": "1.0.15",
|
||||
"@types/lunr": "2.3.7",
|
||||
"@types/node": "20.17.1",
|
||||
"@types/node": "22.9.0",
|
||||
"@types/node-fetch": "2.6.4",
|
||||
"@types/node-forge": "1.3.11",
|
||||
"@types/node-ipc": "9.2.3",
|
||||
@@ -128,7 +128,7 @@
|
||||
"base64-loader": "1.0.0",
|
||||
"browserslist": "4.23.2",
|
||||
"chromatic": "11.10.2",
|
||||
"concurrently": "9.0.1",
|
||||
"concurrently": "9.1.0",
|
||||
"copy-webpack-plugin": "12.0.2",
|
||||
"cross-env": "7.0.3",
|
||||
"css-loader": "7.1.2",
|
||||
@@ -9770,13 +9770,13 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "20.17.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.1.tgz",
|
||||
"integrity": "sha512-j2VlPv1NnwPJbaCNv69FO/1z4lId0QmGvpT41YxitRtWlg96g/j8qcv2RKsLKe2F6OJgyXhupN1Xo17b2m139Q==",
|
||||
"version": "22.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.9.0.tgz",
|
||||
"integrity": "sha512-vuyHg81vvWA1Z1ELfvLko2c8f34gyA0zaic0+Rllc5lbCnbSyuvb2Oxpm6TAUAC/2xZN3QGqxBNggD1nNR2AfQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~6.19.2"
|
||||
"undici-types": "~6.19.8"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node-fetch": {
|
||||
@@ -14538,9 +14538,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/concurrently": {
|
||||
"version": "9.0.1",
|
||||
"resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.0.1.tgz",
|
||||
"integrity": "sha512-wYKvCd/f54sTXJMSfV6Ln/B8UrfLBKOYa+lzc6CHay3Qek+LorVSBdMVfyewFhRbH0Rbabsk4D+3PL/VjQ5gzg==",
|
||||
"version": "9.1.0",
|
||||
"resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.1.0.tgz",
|
||||
"integrity": "sha512-VxkzwMAn4LP7WyMnJNbHN5mKV9L2IbyDjpzemKr99sXNR3GqRNMMHdm7prV1ws9wg7ETj6WUkNOigZVsptwbgg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -16588,6 +16588,16 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/electron/node_modules/@types/node": {
|
||||
"version": "20.17.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.6.tgz",
|
||||
"integrity": "sha512-VEI7OdvK2wP7XHnsuXbAJnEpEkF6NjSN45QJlL4VGqZSXsnicpesdTWsg9RISeSdYd3yeRj/y3k5KGjUXYnFwQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~6.19.2"
|
||||
}
|
||||
},
|
||||
"node_modules/emitter-component": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/emitter-component/-/emitter-component-1.1.2.tgz",
|
||||
|
||||
@@ -72,7 +72,7 @@
|
||||
"@types/koa-json": "2.0.23",
|
||||
"@types/lowdb": "1.0.15",
|
||||
"@types/lunr": "2.3.7",
|
||||
"@types/node": "20.17.1",
|
||||
"@types/node": "22.9.0",
|
||||
"@types/node-fetch": "2.6.4",
|
||||
"@types/node-forge": "1.3.11",
|
||||
"@types/node-ipc": "9.2.3",
|
||||
@@ -89,7 +89,7 @@
|
||||
"base64-loader": "1.0.0",
|
||||
"browserslist": "4.23.2",
|
||||
"chromatic": "11.10.2",
|
||||
"concurrently": "9.0.1",
|
||||
"concurrently": "9.1.0",
|
||||
"copy-webpack-plugin": "12.0.2",
|
||||
"cross-env": "7.0.3",
|
||||
"css-loader": "7.1.2",
|
||||
|
||||
Reference in New Issue
Block a user