1
0
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:
Will Martin
2024-11-12 17:46:52 -05:00
committed by GitHub
22 changed files with 226 additions and 72 deletions

View File

@@ -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": {

View File

@@ -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"
},

View File

@@ -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();

View File

@@ -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;

View File

@@ -1,2 +1,2 @@
export * from "./group/group.service";
export * from "./group/group-api.service";
export * from "./user-admin.service";

View File

@@ -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[];
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -1,3 +1,4 @@
export * from "./group.view";
export * from "./group-details.view";
export * from "./organization-user.view";
export * from "./organization-user-admin-view";

View File

@@ -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

View File

@@ -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)),
),
]),
),

View File

@@ -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,

View File

@@ -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,

View File

@@ -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,

View File

@@ -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,

View File

@@ -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,

View File

@@ -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;

View File

@@ -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`;

View 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]);
});
});

View File

@@ -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
View File

@@ -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",

View File

@@ -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",