diff --git a/.github/renovate.json5 b/.github/renovate.json5 index c1045739506..e5cd47077fb 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -312,6 +312,7 @@ "@angular/platform-browser", "@angular/platform", "@angular/router", + "axe-playwright", "@compodoc/compodoc", "@ng-select/ng-select", "@storybook/addon-a11y", @@ -320,6 +321,7 @@ "@storybook/addon-essentials", "@storybook/addon-interactions", "@storybook/addon-links", + "@storybook/test-runner", "@storybook/addon-themes", "@storybook/angular", "@storybook/manager-api", diff --git a/.storybook/preview.tsx b/.storybook/preview.tsx index 6bd28cfe809..a948fce0428 100644 --- a/.storybook/preview.tsx +++ b/.storybook/preview.tsx @@ -26,6 +26,9 @@ const preview: Preview = { wrapperDecorator, ], parameters: { + a11y: { + element: "#storybook-root", + }, controls: { matchers: { color: /(background|color)$/i, diff --git a/.storybook/test-runner.ts b/.storybook/test-runner.ts new file mode 100644 index 00000000000..208adf96214 --- /dev/null +++ b/.storybook/test-runner.ts @@ -0,0 +1,47 @@ +import { type TestRunnerConfig } from "@storybook/test-runner"; +import { injectAxe, checkA11y } from "axe-playwright"; + +const testRunnerConfig: TestRunnerConfig = { + setup() {}, + + async preVisit(page, context) { + return await injectAxe(page); + }, + + async postVisit(page, context) { + await page.waitForSelector("#storybook-root"); + // https://github.com/abhinaba-ghosh/axe-playwright#parameters-on-checka11y-axerun + await checkA11y( + // Playwright page instance. + page, + + // context + "#storybook-root", + + // axeOptions, see https://www.deque.com/axe/core-documentation/api-documentation/#parameters-axerun + { + detailedReport: true, + detailedReportOptions: { + // Includes the full html for invalid nodes + html: true, + }, + verbose: false, + }, + + // skipFailures + false, + + // reporter "v2" is terminal reporter, "html" writes results to file + "v2", + + // axeHtmlReporterOptions + // NOTE: set reporter param (above) to "html" to activate these options + { + outputDir: "reports/a11y", + reportFileName: `${context.id}.html`, + }, + ); + }, +}; + +export default testRunnerConfig; diff --git a/apps/browser/src/_locales/en/messages.json b/apps/browser/src/_locales/en/messages.json index 57a0e78fd1b..dcdfe7df4d6 100644 --- a/apps/browser/src/_locales/en/messages.json +++ b/apps/browser/src/_locales/en/messages.json @@ -1088,22 +1088,13 @@ } } }, - "loginSaveConfirmation": { - "message": "$ITEMNAME$ saved to Bitwarden.", - "placeholders": { - "itemName": { - "content": "$1" - } - }, + "notificationLoginSaveConfirmation": { + "message": "saved to Bitwarden.", + "description": "Shown to user after item is saved." }, - "loginUpdatedConfirmation": { - "message": "$ITEMNAME$ updated in Bitwarden.", - "placeholders": { - "itemName": { - "content": "$1" - } - }, + "notificationLoginUpdatedConfirmation": { + "message": "updated in Bitwarden.", "description": "Shown to user after item is updated." }, "saveAsNewLoginAction": { @@ -5267,6 +5258,9 @@ "secureDevicesBody": { "message": "Save unlimited passwords across unlimited devices with Bitwarden mobile, browser, and desktop apps." }, + "nudgeBadgeAria": { + "message": "1 notification" + }, "emptyVaultNudgeTitle": { "message": "Import existing passwords" }, @@ -5330,5 +5324,8 @@ "message": "Learn more about SSH agent", "description": "Two part message", "example": "Store your keys and connect with the SSH agent for fast, encrypted authentication. Learn more about SSH agent" + }, + "noPermissionsViewPage": { + "message": "You do not have permissions to view this page. Try logging in with a different account." } } diff --git a/apps/browser/src/autofill/background/notification.background.spec.ts b/apps/browser/src/autofill/background/notification.background.spec.ts index 63ae1193737..009efd7ff36 100644 --- a/apps/browser/src/autofill/background/notification.background.spec.ts +++ b/apps/browser/src/autofill/background/notification.background.spec.ts @@ -17,6 +17,7 @@ import { MessagingService } from "@bitwarden/common/platform/abstractions/messag import { SelfHostedEnvironment } from "@bitwarden/common/platform/services/default-environment.service"; import { ThemeStateService } from "@bitwarden/common/platform/theming/theme-state.service"; import { UserId } from "@bitwarden/common/types/guid"; +import { CipherRepromptType } from "@bitwarden/common/vault/enums/cipher-reprompt-type"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; import { FolderView } from "@bitwarden/common/vault/models/view/folder.view"; import { CipherService } from "@bitwarden/common/vault/services/cipher.service"; @@ -828,6 +829,7 @@ describe("NotificationBackground", () => { id: "testId", name: "testItemName", login: { username: "testUser" }, + reprompt: CipherRepromptType.None, }); getDecryptedCipherByIdSpy.mockResolvedValueOnce(cipherView); @@ -842,6 +844,7 @@ describe("NotificationBackground", () => { message.edit, sender.tab, "testId", + false, ); expect(updateWithServerSpy).toHaveBeenCalled(); expect(tabSendMessageDataSpy).toHaveBeenCalledWith( @@ -855,6 +858,55 @@ describe("NotificationBackground", () => { ); }); + it("prompts the user for master password entry if the notification message type is for ChangePassword and the cipher reprompt is enabled", async () => { + const tab = createChromeTabMock({ id: 1, url: "https://example.com" }); + const sender = mock({ tab }); + const message: NotificationBackgroundExtensionMessage = { + command: "bgSaveCipher", + edit: false, + folder: "folder-id", + }; + const queueMessage = mock({ + type: NotificationQueueMessageType.ChangePassword, + tab, + domain: "example.com", + newPassword: "newPassword", + }); + notificationBackground["notificationQueue"] = [queueMessage]; + const cipherView = mock({ + id: "testId", + name: "testItemName", + login: { username: "testUser" }, + reprompt: CipherRepromptType.Password, + }); + getDecryptedCipherByIdSpy.mockResolvedValueOnce(cipherView); + + sendMockExtensionMessage(message, sender); + await flushPromises(); + + expect(editItemSpy).not.toHaveBeenCalled(); + expect(autofillService.isPasswordRepromptRequired).toHaveBeenCalled(); + expect(createWithServerSpy).not.toHaveBeenCalled(); + expect(updatePasswordSpy).toHaveBeenCalledWith( + cipherView, + queueMessage.newPassword, + message.edit, + sender.tab, + "testId", + false, + ); + expect(updateWithServerSpy).not.toHaveBeenCalled(); + expect(tabSendMessageDataSpy).not.toHaveBeenCalledWith( + sender.tab, + "saveCipherAttemptCompleted", + { + itemName: "testItemName", + cipherId: cipherView.id, + task: undefined, + }, + ); + }); + it("completes password update notification with a security task notice if any are present for the cipher, and dismisses tasks for the updated cipher", async () => { const mockCipherId = "testId"; const mockOrgId = "testOrgId"; @@ -905,6 +957,7 @@ describe("NotificationBackground", () => { id: mockCipherId, organizationId: mockOrgId, name: "Test Item", + reprompt: CipherRepromptType.None, }); getDecryptedCipherByIdSpy.mockResolvedValueOnce(cipherView); @@ -919,6 +972,7 @@ describe("NotificationBackground", () => { message.edit, sender.tab, mockCipherId, + false, ); expect(updateWithServerSpy).toHaveBeenCalled(); expect(tabSendMessageDataSpy).toHaveBeenCalledWith( @@ -1000,6 +1054,7 @@ describe("NotificationBackground", () => { message.edit, sender.tab, "testId", + false, ); expect(editItemSpy).toHaveBeenCalled(); expect(updateWithServerSpy).not.toHaveBeenCalled(); @@ -1170,7 +1225,7 @@ describe("NotificationBackground", () => { newPassword: "newPassword", }); notificationBackground["notificationQueue"] = [queueMessage]; - const cipherView = mock(); + const cipherView = mock({ reprompt: CipherRepromptType.None }); getDecryptedCipherByIdSpy.mockResolvedValueOnce(cipherView); const errorMessage = "fetch error"; updateWithServerSpy.mockImplementation(() => { diff --git a/apps/browser/src/autofill/background/notification.background.ts b/apps/browser/src/autofill/background/notification.background.ts index 5dd15274677..52920ec67a8 100644 --- a/apps/browser/src/autofill/background/notification.background.ts +++ b/apps/browser/src/autofill/background/notification.background.ts @@ -14,6 +14,7 @@ import { ExtensionCommand, ExtensionCommandType, NOTIFICATION_BAR_LIFESPAN_MS, + UPDATE_PASSWORD, } from "@bitwarden/common/autofill/constants"; import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service"; import { UserNotificationSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/user-notification-settings.service"; @@ -104,6 +105,8 @@ export default class NotificationBackground { this.removeTabFromNotificationQueue(sender.tab), bgReopenUnlockPopout: ({ sender }) => this.openUnlockPopout(sender.tab), bgSaveCipher: ({ message, sender }) => this.handleSaveCipherMessage(message, sender), + bgHandleReprompt: ({ message, sender }: any) => + this.handleCipherUpdateRepromptResponse(message), bgUnlockPopoutOpened: ({ message, sender }) => this.unlockVault(message, sender.tab), checkNotificationQueue: ({ sender }) => this.checkNotificationQueue(sender.tab), collectPageDetailsResponse: ({ message }) => @@ -631,6 +634,17 @@ export default class NotificationBackground { await this.saveOrUpdateCredentials(sender.tab, message.edit, message.folder); } + async handleCipherUpdateRepromptResponse(message: NotificationBackgroundExtensionMessage) { + if (message.success) { + await this.saveOrUpdateCredentials(message.tab, false, undefined, true); + } else { + await BrowserApi.tabSendMessageData(message.tab, "saveCipherAttemptCompleted", { + error: "Password reprompt failed", + }); + return; + } + } + /** * Saves or updates credentials based on the message within the * notification queue that is associated with the specified tab. @@ -639,7 +653,12 @@ export default class NotificationBackground { * @param edit - Identifies if the credentials should be edited or simply added * @param folderId - The folder to add the cipher to */ - private async saveOrUpdateCredentials(tab: chrome.tabs.Tab, edit: boolean, folderId?: string) { + private async saveOrUpdateCredentials( + tab: chrome.tabs.Tab, + edit: boolean, + folderId?: string, + skipReprompt: boolean = false, + ) { for (let i = this.notificationQueue.length - 1; i >= 0; i--) { const queueMessage = this.notificationQueue[i]; if ( @@ -654,18 +673,26 @@ export default class NotificationBackground { continue; } - this.notificationQueue.splice(i, 1); - const activeUserId = await firstValueFrom( this.accountService.activeAccount$.pipe(getOptionalUserId), ); if (queueMessage.type === NotificationQueueMessageType.ChangePassword) { const cipherView = await this.getDecryptedCipherById(queueMessage.cipherId, activeUserId); - await this.updatePassword(cipherView, queueMessage.newPassword, edit, tab, activeUserId); + + await this.updatePassword( + cipherView, + queueMessage.newPassword, + edit, + tab, + activeUserId, + skipReprompt, + ); return; } + this.notificationQueue.splice(i, 1); + // If the vault was locked, check if a cipher needs updating instead of creating a new one if (queueMessage.wasVaultLocked) { const allCiphers = await this.cipherService.getAllDecryptedForUrl( @@ -725,6 +752,7 @@ export default class NotificationBackground { edit: boolean, tab: chrome.tabs.Tab, userId: UserId, + skipReprompt: boolean = false, ) { cipherView.login.password = newPassword; @@ -758,6 +786,12 @@ export default class NotificationBackground { } : undefined; + if (cipherView.reprompt && !skipReprompt) { + await this.autofillService.isPasswordRepromptRequired(cipherView, tab, UPDATE_PASSWORD); + + return; + } + await this.cipherService.updateWithServer(cipher); await BrowserApi.tabSendMessageData(tab, "saveCipherAttemptCompleted", { diff --git a/apps/browser/src/autofill/content/components/lit-stories/mock-data.ts b/apps/browser/src/autofill/content/components/lit-stories/mock-data.ts index b8e35813c6c..d134db3ca6f 100644 --- a/apps/browser/src/autofill/content/components/lit-stories/mock-data.ts +++ b/apps/browser/src/autofill/content/components/lit-stories/mock-data.ts @@ -107,9 +107,9 @@ export const mockI18n = { collection: "Collection", folder: "Folder", loginSaveSuccess: "Login saved", - loginSaveConfirmation: "$ITEMNAME$ saved to Bitwarden.", + notificationLoginSaveConfirmation: "saved to Bitwarden.", loginUpdateSuccess: "Login updated", - loginUpdatedConfirmation: "$ITEMNAME$ updated in Bitwarden.", + notificationLoginUpdatedConfirmation: "updated in Bitwarden.", loginUpdateTaskSuccess: "Great job! You took the steps to make you and $ORGANIZATION$ more secure.", loginUpdateTaskSuccessAdditional: diff --git a/apps/browser/src/autofill/content/components/notification/confirmation/container.ts b/apps/browser/src/autofill/content/components/notification/confirmation/container.ts index 7ad6b4542ec..d4d66c7a7be 100644 --- a/apps/browser/src/autofill/content/components/notification/confirmation/container.ts +++ b/apps/browser/src/autofill/content/components/notification/confirmation/container.ts @@ -113,9 +113,14 @@ function getConfirmationMessage(i18n: I18n, type?: NotificationType, error?: str if (error) { return i18n.saveFailureDetails; } + + /* @TODO This partial string return and later concatenation with the cipher name is needed + * to handle cipher name overflow cases, but is risky for i18n concerns. Fix concatenation + * with cipher name overflow when a tag replacement solution is available. + */ return type === NotificationTypes.Add - ? i18n.loginSaveConfirmation - : i18n.loginUpdatedConfirmation; + ? i18n.notificationLoginSaveConfirmation + : i18n.notificationLoginUpdatedConfirmation; } function getHeaderMessage(i18n: I18n, type?: NotificationType, error?: string) { diff --git a/apps/browser/src/autofill/content/components/notification/confirmation/message.ts b/apps/browser/src/autofill/content/components/notification/confirmation/message.ts index 527119aed15..2bf8caecfff 100644 --- a/apps/browser/src/autofill/content/components/notification/confirmation/message.ts +++ b/apps/browser/src/autofill/content/components/notification/confirmation/message.ts @@ -28,28 +28,31 @@ export function NotificationConfirmationMessage({
${message || buttonText ? html` - ${itemName} - - ${message || nothing} - ${buttonText - ? html` - handleButtonKeyDown(e, () => handleClick(e))} - aria-label=${buttonAria} - tabindex="0" - role="button" - > - ${buttonText} - - ` - : nothing} - +
+ ${itemName} + + ${message || nothing} + ${buttonText + ? html` + + handleButtonKeyDown(e, () => handleClick(e))} + aria-label=${buttonAria} + tabindex="0" + role="button" + > + ${buttonText} + + ` + : nothing} + +
` : nothing} ${messageDetails @@ -61,12 +64,17 @@ export function NotificationConfirmationMessage({ const containerStyles = css` display: flex; - flex-wrap: wrap; - align-items: center; + flex-direction: column; gap: ${spacing[1]}; width: 100%; `; +const singleLineWrapperStyles = css` + display: inline; + white-space: normal; + word-break: break-word; +`; + const baseTextStyles = css` overflow-x: hidden; text-align: left; @@ -81,6 +89,9 @@ const notificationConfirmationMessageStyles = (theme: Theme) => css` color: ${themes[theme].text.main}; font-weight: 400; + white-space: normal; + word-break: break-word; + display: inline; `; const itemNameStyles = (theme: Theme) => css` @@ -90,6 +101,10 @@ const itemNameStyles = (theme: Theme) => css` font-weight: 400; white-space: nowrap; max-width: 300px; + overflow: hidden; + text-overflow: ellipsis; + display: inline-block; + vertical-align: bottom; `; const notificationConfirmationButtonTextStyles = (theme: Theme) => css` diff --git a/apps/browser/src/autofill/content/components/notification/container.ts b/apps/browser/src/autofill/content/components/notification/container.ts index c7c7ae16cde..1a78854f5dc 100644 --- a/apps/browser/src/autofill/content/components/notification/container.ts +++ b/apps/browser/src/autofill/content/components/notification/container.ts @@ -94,7 +94,7 @@ const notificationContainerStyles = (theme: Theme) => css` } [class*="${notificationBodyClassPrefix}-"] { - margin: ${spacing["3"]} 0 ${spacing["1.5"]} ${spacing["3"]}; + margin: ${spacing["3"]} 0 0 ${spacing["3"]}; padding-right: ${spacing["3"]}; } `; diff --git a/apps/browser/src/autofill/content/components/notification/footer.ts b/apps/browser/src/autofill/content/components/notification/footer.ts index 73fe9084595..03d0d475e85 100644 --- a/apps/browser/src/autofill/content/components/notification/footer.ts +++ b/apps/browser/src/autofill/content/components/notification/footer.ts @@ -8,7 +8,7 @@ import { NotificationTypes, } from "../../../notification/abstractions/notification-bar"; import { OrgView, FolderView, I18n, CollectionView } from "../common-types"; -import { spacing, themes } from "../constants/styles"; +import { spacing } from "../constants/styles"; import { NotificationButtonRow } from "./button-row"; @@ -37,7 +37,7 @@ export function NotificationFooter({ const primaryButtonText = i18n.saveAction; return html` -
+
${!isChangeNotification ? NotificationButtonRow({ collections, @@ -56,13 +56,16 @@ export function NotificationFooter({ `; } -const notificationFooterStyles = ({ theme }: { theme: Theme }) => css` +const notificationFooterStyles = ({ + isChangeNotification, +}: { + isChangeNotification: boolean; +}) => css` display: flex; - background-color: ${themes[theme].background.alt}; - padding: 0 ${spacing[3]} ${spacing[3]} ${spacing[3]}; + padding: ${spacing[2]} ${spacing[4]} ${isChangeNotification ? spacing[1] : spacing[4]} + ${spacing[4]}; :last-child { border-radius: 0 0 ${spacing["4"]} ${spacing["4"]}; - padding-bottom: ${spacing[4]}; } `; diff --git a/apps/browser/src/autofill/content/components/rows/button-row.ts b/apps/browser/src/autofill/content/components/rows/button-row.ts index 3527d050b81..7e81d846cb7 100644 --- a/apps/browser/src/autofill/content/components/rows/button-row.ts +++ b/apps/browser/src/autofill/content/components/rows/button-row.ts @@ -62,7 +62,7 @@ const buttonRowStyles = css` > button { max-width: min-content; - flex: 1 1 50%; + flex: 1 1 25%; } > div { diff --git a/apps/browser/src/autofill/enums/autofill-overlay.enum.ts b/apps/browser/src/autofill/enums/autofill-overlay.enum.ts index 9cc457f3c1a..d0b970671a8 100644 --- a/apps/browser/src/autofill/enums/autofill-overlay.enum.ts +++ b/apps/browser/src/autofill/enums/autofill-overlay.enum.ts @@ -21,6 +21,8 @@ export const RedirectFocusDirection = { Next: "next", } as const; +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum InlineMenuFillType { AccountCreationUsername = 5, PasswordGeneration = 6, diff --git a/apps/browser/src/autofill/fido2/content/messaging/message.ts b/apps/browser/src/autofill/fido2/content/messaging/message.ts index 5815be9eb60..640af22ab9a 100644 --- a/apps/browser/src/autofill/fido2/content/messaging/message.ts +++ b/apps/browser/src/autofill/fido2/content/messaging/message.ts @@ -5,6 +5,8 @@ import { AssertCredentialResult, } from "@bitwarden/common/platform/abstractions/fido2/fido2-client.service.abstraction"; +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum MessageType { CredentialCreationRequest, CredentialCreationResponse, diff --git a/apps/browser/src/autofill/notification/bar.ts b/apps/browser/src/autofill/notification/bar.ts index 3fd6016eb33..52cbdcd47d3 100644 --- a/apps/browser/src/autofill/notification/bar.ts +++ b/apps/browser/src/autofill/notification/bar.ts @@ -59,9 +59,7 @@ function getI18n() { collection: chrome.i18n.getMessage("collection"), folder: chrome.i18n.getMessage("folder"), loginSaveSuccess: chrome.i18n.getMessage("loginSaveSuccess"), - loginSaveConfirmation: chrome.i18n.getMessage("loginSaveConfirmation"), loginUpdateSuccess: chrome.i18n.getMessage("loginUpdateSuccess"), - loginUpdatedConfirmation: chrome.i18n.getMessage("loginUpdatedConfirmation"), loginUpdateTaskSuccess: chrome.i18n.getMessage("loginUpdateTaskSuccess"), loginUpdateTaskSuccessAdditional: chrome.i18n.getMessage("loginUpdateTaskSuccessAdditional"), nextSecurityTaskAction: chrome.i18n.getMessage("nextSecurityTaskAction"), @@ -74,6 +72,10 @@ function getI18n() { notificationUpdate: chrome.i18n.getMessage("notificationChangeSave"), notificationEdit: chrome.i18n.getMessage("edit"), notificationEditTooltip: chrome.i18n.getMessage("notificationEditTooltip"), + notificationLoginSaveConfirmation: chrome.i18n.getMessage("notificationLoginSaveConfirmation"), + notificationLoginUpdatedConfirmation: chrome.i18n.getMessage( + "notificationLoginUpdatedConfirmation", + ), notificationUnlock: chrome.i18n.getMessage("notificationUnlock"), notificationUnlockDesc: chrome.i18n.getMessage("notificationUnlockDesc"), notificationViewAria: chrome.i18n.getMessage("notificationViewAria"), diff --git a/apps/browser/src/autofill/overlay/notifications/abstractions/overlay-notifications-content.service.ts b/apps/browser/src/autofill/overlay/notifications/abstractions/overlay-notifications-content.service.ts index 82c03cacadf..42d7666e8a7 100644 --- a/apps/browser/src/autofill/overlay/notifications/abstractions/overlay-notifications-content.service.ts +++ b/apps/browser/src/autofill/overlay/notifications/abstractions/overlay-notifications-content.service.ts @@ -15,6 +15,7 @@ export type NotificationsExtensionMessage = { typeData?: NotificationTypeData; height?: number; error?: string; + closedByUser?: boolean; fadeOutNotification?: boolean; }; }; diff --git a/apps/browser/src/autofill/overlay/notifications/content/overlay-notifications-content.service.ts b/apps/browser/src/autofill/overlay/notifications/content/overlay-notifications-content.service.ts index 519521feaa9..c21aaa37dd4 100644 --- a/apps/browser/src/autofill/overlay/notifications/content/overlay-notifications-content.service.ts +++ b/apps/browser/src/autofill/overlay/notifications/content/overlay-notifications-content.service.ts @@ -106,13 +106,15 @@ export class OverlayNotificationsContentService * @param message - The message containing the data for closing the notification bar. */ private handleCloseNotificationBarMessage(message: NotificationsExtensionMessage) { + const closedByUser = + typeof message.data?.closedByUser === "boolean" ? message.data.closedByUser : true; if (message.data?.fadeOutNotification) { setElementStyles(this.notificationBarIframeElement, { opacity: "0" }, true); - globalThis.setTimeout(() => this.closeNotificationBar(true), 150); + globalThis.setTimeout(() => this.closeNotificationBar(closedByUser), 150); return; } - this.closeNotificationBar(true); + this.closeNotificationBar(closedByUser); } /** diff --git a/apps/browser/src/autofill/services/abstractions/autofill.service.ts b/apps/browser/src/autofill/services/abstractions/autofill.service.ts index 5b1b4b3b8bb..daafd871789 100644 --- a/apps/browser/src/autofill/services/abstractions/autofill.service.ts +++ b/apps/browser/src/autofill/services/abstractions/autofill.service.ts @@ -87,5 +87,9 @@ export abstract class AutofillService { cipherType?: CipherType, ) => Promise; setAutoFillOnPageLoadOrgPolicy: () => Promise; - isPasswordRepromptRequired: (cipher: CipherView, tab: chrome.tabs.Tab) => Promise; + isPasswordRepromptRequired: ( + cipher: CipherView, + tab: chrome.tabs.Tab, + action?: string, + ) => Promise; } diff --git a/apps/browser/src/autofill/services/autofill.service.ts b/apps/browser/src/autofill/services/autofill.service.ts index da46ceb0864..525010bacc1 100644 --- a/apps/browser/src/autofill/services/autofill.service.ts +++ b/apps/browser/src/autofill/services/autofill.service.ts @@ -593,15 +593,20 @@ export default class AutofillService implements AutofillServiceInterface { * * @param cipher - The cipher to autofill * @param tab - The tab to autofill + * @param action - override for default action once reprompt is completed successfully */ - async isPasswordRepromptRequired(cipher: CipherView, tab: chrome.tabs.Tab): Promise { + async isPasswordRepromptRequired( + cipher: CipherView, + tab: chrome.tabs.Tab, + action?: string, + ): Promise { const userHasMasterPasswordAndKeyHash = await this.userVerificationService.hasMasterPasswordAndMasterKeyHash(); if (cipher.reprompt === CipherRepromptType.Password && userHasMasterPasswordAndKeyHash) { if (!this.isDebouncingPasswordRepromptPopout()) { await this.openVaultItemPasswordRepromptPopout(tab, { cipherId: cipher.id, - action: "autofill", + action: action ?? "autofill", }); } diff --git a/apps/browser/src/platform/browser/browser-api.ts b/apps/browser/src/platform/browser/browser-api.ts index b27e8ca7c96..4ef72fa0077 100644 --- a/apps/browser/src/platform/browser/browser-api.ts +++ b/apps/browser/src/platform/browser/browser-api.ts @@ -664,6 +664,10 @@ export class BrowserApi { * Identifies if the browser autofill settings are overridden by the extension. */ static async browserAutofillSettingsOverridden(): Promise { + if (!(await BrowserApi.permissionsGranted(["privacy"]))) { + return false; + } + const checkOverrideStatus = (details: chrome.types.ChromeSettingGetResult) => details.levelOfControl === "controlled_by_this_extension" && !details.value; diff --git a/apps/browser/src/platform/popup/layout/popup-size.service.ts b/apps/browser/src/platform/popup/layout/popup-size.service.ts index 3ae9a633cab..69d3102d24e 100644 --- a/apps/browser/src/platform/popup/layout/popup-size.service.ts +++ b/apps/browser/src/platform/popup/layout/popup-size.service.ts @@ -50,17 +50,40 @@ export class PopupSizeService { PopupSizeService.setStyle(width); localStorage.setItem(PopupSizeService.LocalStorageKey, width); }); + } + async setHeight() { const isInChromeTab = await BrowserPopupUtils.isInTab(); + /** + * To support both browser default zoom and system default zoom, we need to take into account + * the full screen height. When system default zoom is >100%, window.innerHeight still outputs + * a height equivalent to what it would be at 100%, which can cause the extension window to + * render as too tall. So if the screen height is smaller than the max possible extension height, + * we should use that to set our extension height. Otherwise, we want to use the window.innerHeight + * to support browser zoom. + * + * This is basically a workaround for what we consider a bug with browsers reporting the wrong + * available innerHeight when system zoom is turned on. If that gets fixed, we can remove the code + * checking the screen height. + */ + const MAX_EXT_HEIGHT = 600; + const extensionInnerHeight = window.innerHeight; + // Use a 100px offset when calculating screen height to account for browser container elements + const screenAvailHeight = window.screen.availHeight - 100; + const availHeight = + screenAvailHeight < MAX_EXT_HEIGHT ? screenAvailHeight : extensionInnerHeight; + if (!BrowserPopupUtils.inPopup(window) || isInChromeTab) { - window.document.body.classList.add("body-full"); - } else if (window.innerHeight < 400) { - window.document.body.classList.add("body-xxs"); - } else if (window.innerHeight < 500) { - window.document.body.classList.add("body-xs"); - } else if (window.innerHeight < 600) { - window.document.body.classList.add("body-sm"); + window.document.documentElement.classList.add("body-full"); + } else if (availHeight < 300) { + window.document.documentElement.classList.add("body-3xs"); + } else if (availHeight < 400) { + window.document.documentElement.classList.add("body-xxs"); + } else if (availHeight < 500) { + window.document.documentElement.classList.add("body-xs"); + } else if (availHeight < 600) { + window.document.documentElement.classList.add("body-sm"); } } diff --git a/apps/browser/src/platform/popup/view-cache/popup-view-cache.service.ts b/apps/browser/src/platform/popup/view-cache/popup-view-cache.service.ts index ff63b52ab3f..2a946982990 100644 --- a/apps/browser/src/platform/popup/view-cache/popup-view-cache.service.ts +++ b/apps/browser/src/platform/popup/view-cache/popup-view-cache.service.ts @@ -19,7 +19,7 @@ import { FormCacheOptions, SignalCacheOptions, ViewCacheService, -} from "@bitwarden/angular/platform/abstractions/view-cache.service"; +} from "@bitwarden/angular/platform/view-cache"; import { MessageSender } from "@bitwarden/common/platform/messaging"; import { GlobalStateProvider } from "@bitwarden/common/platform/state"; diff --git a/apps/browser/src/popup/app.component.ts b/apps/browser/src/popup/app.component.ts index 49579f889b3..a480e1d6ba3 100644 --- a/apps/browser/src/popup/app.component.ts +++ b/apps/browser/src/popup/app.component.ts @@ -26,6 +26,7 @@ import { import { BiometricsService, BiometricStateService } from "@bitwarden/key-management"; import { PopupCompactModeService } from "../platform/popup/layout/popup-compact-mode.service"; +import { PopupSizeService } from "../platform/popup/layout/popup-size.service"; import { initPopupClosedListener } from "../platform/services/popup-view-cache-background.service"; import { VaultBrowserStateService } from "../vault/services/vault-browser-state.service"; @@ -71,6 +72,7 @@ export class AppComponent implements OnInit, OnDestroy { private biometricStateService: BiometricStateService, private biometricsService: BiometricsService, private deviceTrustToastService: DeviceTrustToastService, + private popupSizeService: PopupSizeService, ) { this.deviceTrustToastService.setupListeners$.pipe(takeUntilDestroyed()).subscribe(); } @@ -79,6 +81,7 @@ export class AppComponent implements OnInit, OnDestroy { initPopupClosedListener(); this.compactModeService.init(); + await this.popupSizeService.setHeight(); // Component states must not persist between closing and reopening the popup, otherwise they become dead objects // Clear them aggressively to make sure this doesn't occur diff --git a/apps/browser/src/popup/scss/base.scss b/apps/browser/src/popup/scss/base.scss index 59893b5050d..80ada61f868 100644 --- a/apps/browser/src/popup/scss/base.scss +++ b/apps/browser/src/popup/scss/base.scss @@ -8,6 +8,34 @@ html { overflow: hidden; + min-height: 600px; + height: 100%; + + &.body-sm { + min-height: 500px; + } + + &.body-xs { + min-height: 400px; + } + + &.body-xxs { + min-height: 300px; + } + + &.body-3xs { + min-height: 240px; + } + + &.body-full { + min-height: unset; + width: 100%; + height: 100%; + + & body { + width: 100%; + } + } } html, @@ -20,9 +48,9 @@ body { body { width: 380px; - height: 600px; + height: 100%; position: relative; - min-height: 100vh; + min-height: inherit; overflow: hidden; color: $text-color; background-color: $background-color; @@ -31,23 +59,6 @@ body { color: themed("textColor"); background-color: themed("backgroundColor"); } - - &.body-sm { - height: 500px; - } - - &.body-xs { - height: 400px; - } - - &.body-xxs { - height: 300px; - } - - &.body-full { - width: 100%; - height: 100%; - } } h1, diff --git a/apps/browser/src/popup/services/services.module.ts b/apps/browser/src/popup/services/services.module.ts index 00b8ae81cf9..6ede88dfc13 100644 --- a/apps/browser/src/popup/services/services.module.ts +++ b/apps/browser/src/popup/services/services.module.ts @@ -5,9 +5,9 @@ import { Router } from "@angular/router"; import { merge, of, Subject } from "rxjs"; import { CollectionService } from "@bitwarden/admin-console/common"; -import { ViewCacheService } from "@bitwarden/angular/platform/abstractions/view-cache.service"; import { AngularThemingService } from "@bitwarden/angular/platform/services/theming/angular-theming.service"; import { SafeProvider, safeProvider } from "@bitwarden/angular/platform/utils/safe-provider"; +import { ViewCacheService } from "@bitwarden/angular/platform/view-cache"; import { CLIENT_TYPE, DEFAULT_VAULT_TIMEOUT, diff --git a/apps/browser/src/tools/popup/send-v2/send-v2.component.ts b/apps/browser/src/tools/popup/send-v2/send-v2.component.ts index 49804abda5d..def425a51a5 100644 --- a/apps/browser/src/tools/popup/send-v2/send-v2.component.ts +++ b/apps/browser/src/tools/popup/send-v2/send-v2.component.ts @@ -26,6 +26,8 @@ import { PopOutComponent } from "../../../platform/popup/components/pop-out.comp import { PopupHeaderComponent } from "../../../platform/popup/layout/popup-header.component"; import { PopupPageComponent } from "../../../platform/popup/layout/popup-page.component"; +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum SendState { Empty, NoResults, diff --git a/apps/browser/src/tools/popup/settings/settings-v2.component.html b/apps/browser/src/tools/popup/settings/settings-v2.component.html index 22e2d9a28d0..8d31ccf8371 100644 --- a/apps/browser/src/tools/popup/settings/settings-v2.component.html +++ b/apps/browser/src/tools/popup/settings/settings-v2.component.html @@ -23,6 +23,7 @@ *ngIf="!isBrowserAutofillSettingOverridden && (showAutofillBadge$ | async)" bitBadge variant="notification" + [attr.aria-label]="'nudgeBadgeAria' | i18n" >1
@@ -53,6 +54,7 @@ *ngIf="!(showVaultBadge$ | async)?.hasBadgeDismissed" bitBadge variant="notification" + [attr.aria-label]="'nudgeBadgeAria' | i18n" >1
@@ -83,6 +85,7 @@ *ngIf="(downloadBitwardenNudgeStatus$ | async)?.hasBadgeDismissed === false" bitBadge variant="notification" + [attr.aria-label]="'nudgeBadgeAria' | i18n" >1
diff --git a/apps/browser/src/vault/guards/at-risk-passwords.guard.ts b/apps/browser/src/vault/guards/at-risk-passwords.guard.ts index 6bcdddfde81..fc302dd6c36 100644 --- a/apps/browser/src/vault/guards/at-risk-passwords.guard.ts +++ b/apps/browser/src/vault/guards/at-risk-passwords.guard.ts @@ -1,6 +1,6 @@ import { inject } from "@angular/core"; -import { CanActivateFn } from "@angular/router"; -import { switchMap, tap } from "rxjs"; +import { CanActivateFn, Router } from "@angular/router"; +import { map, switchMap } from "rxjs"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; @@ -13,18 +13,22 @@ export const canAccessAtRiskPasswords: CanActivateFn = () => { const taskService = inject(TaskService); const toastService = inject(ToastService); const i18nService = inject(I18nService); + const router = inject(Router); return accountService.activeAccount$.pipe( filterOutNullish(), switchMap((user) => taskService.tasksEnabled$(user.id)), - tap((tasksEnabled) => { + map((tasksEnabled) => { if (!tasksEnabled) { toastService.showToast({ variant: "error", title: "", - message: i18nService.t("accessDenied"), + message: i18nService.t("noPermissionsViewPage"), }); + + return router.createUrlTree(["/tabs/vault"]); } + return true; }), ); }; diff --git a/apps/browser/src/vault/popup/components/at-risk-carousel-dialog/at-risk-carousel-dialog.component.ts b/apps/browser/src/vault/popup/components/at-risk-carousel-dialog/at-risk-carousel-dialog.component.ts index fcca125c2b6..0133bccd25c 100644 --- a/apps/browser/src/vault/popup/components/at-risk-carousel-dialog/at-risk-carousel-dialog.component.ts +++ b/apps/browser/src/vault/popup/components/at-risk-carousel-dialog/at-risk-carousel-dialog.component.ts @@ -10,6 +10,8 @@ import { import { I18nPipe } from "@bitwarden/ui-common"; import { DarkImageSourceDirective, VaultCarouselModule } from "@bitwarden/vault"; +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum AtRiskCarouselDialogResult { Dismissed = "dismissed", } diff --git a/apps/browser/src/vault/popup/components/vault-v2/vault-generator-dialog/vault-generator-dialog.component.ts b/apps/browser/src/vault/popup/components/vault-v2/vault-generator-dialog/vault-generator-dialog.component.ts index 137f2a9dac3..4daffa6a9b8 100644 --- a/apps/browser/src/vault/popup/components/vault-v2/vault-generator-dialog/vault-generator-dialog.component.ts +++ b/apps/browser/src/vault/popup/components/vault-v2/vault-generator-dialog/vault-generator-dialog.component.ts @@ -30,6 +30,8 @@ export interface GeneratorDialogResult { generatedValue?: string; } +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum GeneratorDialogAction { Selected = "selected", Canceled = "canceled", diff --git a/apps/browser/src/vault/popup/components/vault-v2/vault-v2.component.ts b/apps/browser/src/vault/popup/components/vault-v2/vault-v2.component.ts index 64805a02394..4a8625f982c 100644 --- a/apps/browser/src/vault/popup/components/vault-v2/vault-v2.component.ts +++ b/apps/browser/src/vault/popup/components/vault-v2/vault-v2.component.ts @@ -55,6 +55,8 @@ import { VaultPageService } from "./vault-page.service"; import { AutofillVaultListItemsComponent, VaultListItemsContainerComponent } from "."; +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums enum VaultState { Empty, NoResults, diff --git a/apps/browser/src/vault/popup/components/vault-v2/view-v2/view-v2.component.ts b/apps/browser/src/vault/popup/components/vault-v2/view-v2/view-v2.component.ts index 56db47619b0..a834314560b 100644 --- a/apps/browser/src/vault/popup/components/vault-v2/view-v2/view-v2.component.ts +++ b/apps/browser/src/vault/popup/components/vault-v2/view-v2/view-v2.component.ts @@ -19,6 +19,7 @@ import { COPY_USERNAME_ID, COPY_VERIFICATION_CODE_ID, SHOW_AUTOFILL_BUTTON, + UPDATE_PASSWORD, } from "@bitwarden/common/autofill/constants"; import { EventType } from "@bitwarden/common/enums"; import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; @@ -49,6 +50,7 @@ import { PasswordRepromptService, } from "@bitwarden/vault"; +import { sendExtensionMessage } from "../../../../../autofill/utils/index"; import { BrowserApi } from "../../../../../platform/browser/browser-api"; import BrowserPopupUtils from "../../../../../platform/popup/browser-popup-utils"; import { PopOutComponent } from "../../../../../platform/popup/components/pop-out.component"; @@ -72,7 +74,8 @@ type LoadAction = | typeof SHOW_AUTOFILL_BUTTON | typeof COPY_USERNAME_ID | typeof COPY_PASSWORD_ID - | typeof COPY_VERIFICATION_CODE_ID; + | typeof COPY_VERIFICATION_CODE_ID + | typeof UPDATE_PASSWORD; @Component({ selector: "app-view-v2", @@ -294,7 +297,7 @@ export class ViewV2Component { // Both vaultPopupAutofillService and copyCipherFieldService will perform password re-prompting internally. switch (loadAction) { - case "show-autofill-button": + case SHOW_AUTOFILL_BUTTON: // This action simply shows the cipher view, no need to do anything. if ( this.cipher.reprompt !== CipherRepromptType.None && @@ -303,30 +306,42 @@ export class ViewV2Component { await closeViewVaultItemPopout(`${VaultPopoutType.viewVaultItem}_${this.cipher.id}`); } return; - case "autofill": + case AUTOFILL_ID: actionSuccess = await this.vaultPopupAutofillService.doAutofill(this.cipher, false); break; - case "copy-username": + case COPY_USERNAME_ID: actionSuccess = await this.copyCipherFieldService.copy( this.cipher.login.username, "username", this.cipher, ); break; - case "copy-password": + case COPY_PASSWORD_ID: actionSuccess = await this.copyCipherFieldService.copy( this.cipher.login.password, "password", this.cipher, ); break; - case "copy-totp": + case COPY_VERIFICATION_CODE_ID: actionSuccess = await this.copyCipherFieldService.copy( this.cipher.login.totp, "totp", this.cipher, ); break; + case UPDATE_PASSWORD: { + const repromptSuccess = await this.passwordRepromptService.showPasswordPrompt(); + + await sendExtensionMessage("bgHandleReprompt", { + tab: await chrome.tabs.get(senderTabId), + success: repromptSuccess, + }); + + await closeViewVaultItemPopout(`${VaultPopoutType.viewVaultItem}_${this.cipher.id}`); + + break; + } } if (BrowserPopupUtils.inPopout(window)) { diff --git a/apps/browser/src/vault/popup/services/vault-popup-list-filters.service.spec.ts b/apps/browser/src/vault/popup/services/vault-popup-list-filters.service.spec.ts index 9498d953808..621ec795157 100644 --- a/apps/browser/src/vault/popup/services/vault-popup-list-filters.service.spec.ts +++ b/apps/browser/src/vault/popup/services/vault-popup-list-filters.service.spec.ts @@ -4,6 +4,7 @@ import { FormBuilder } from "@angular/forms"; import { BehaviorSubject, skipWhile } from "rxjs"; import { CollectionService, CollectionView } from "@bitwarden/admin-console/common"; +import { ViewCacheService } from "@bitwarden/angular/platform/view-cache"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { PolicyType } from "@bitwarden/common/admin-console/enums"; @@ -20,8 +21,6 @@ import { CipherType } from "@bitwarden/common/vault/enums"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; import { FolderView } from "@bitwarden/common/vault/models/view/folder.view"; -import { PopupViewCacheService } from "../../../platform/popup/view-cache/popup-view-cache.service"; - import { CachedFilterState, MY_VAULT_ID, @@ -123,7 +122,7 @@ describe("VaultPopupListFiltersService", () => { useValue: accountService, }, { - provide: PopupViewCacheService, + provide: ViewCacheService, useValue: viewCacheService, }, ], diff --git a/apps/browser/src/vault/popup/services/vault-popup-list-filters.service.ts b/apps/browser/src/vault/popup/services/vault-popup-list-filters.service.ts index c726678c973..db4cfeefe9f 100644 --- a/apps/browser/src/vault/popup/services/vault-popup-list-filters.service.ts +++ b/apps/browser/src/vault/popup/services/vault-popup-list-filters.service.ts @@ -15,6 +15,7 @@ import { } from "rxjs"; import { CollectionService, CollectionView } from "@bitwarden/admin-console/common"; +import { ViewCacheService } from "@bitwarden/angular/platform/view-cache"; import { DynamicTreeNode } from "@bitwarden/angular/vault/vault-filter/models/dynamic-tree-node.model"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; @@ -40,8 +41,6 @@ import { FolderView } from "@bitwarden/common/vault/models/view/folder.view"; import { ServiceUtils } from "@bitwarden/common/vault/service-utils"; import { ChipSelectOption } from "@bitwarden/components"; -import { PopupViewCacheService } from "../../../platform/popup/view-cache/popup-view-cache.service"; - const FILTER_VISIBILITY_KEY = new KeyDefinition(VAULT_SETTINGS_DISK, "filterVisibility", { deserializer: (obj) => obj, }); @@ -178,7 +177,7 @@ export class VaultPopupListFiltersService { private policyService: PolicyService, private stateProvider: StateProvider, private accountService: AccountService, - private viewCacheService: PopupViewCacheService, + private viewCacheService: ViewCacheService, ) { this.filterForm.controls.organization.valueChanges .pipe(takeUntilDestroyed()) diff --git a/apps/cli/package.json b/apps/cli/package.json index 79d4786a23c..b01c96b23d1 100644 --- a/apps/cli/package.json +++ b/apps/cli/package.json @@ -64,13 +64,14 @@ ] }, "dependencies": { - "@koa/multer": "3.0.2", + "@koa/multer": "3.1.0", "@koa/router": "13.1.0", "argon2": "0.41.1", "big-integer": "1.6.52", "browser-hrtime": "1.1.8", "chalk": "4.1.2", "commander": "11.1.0", + "core-js": "3.40.0", "form-data": "4.0.1", "https-proxy-agent": "7.0.6", "inquirer": "8.2.6", @@ -81,7 +82,7 @@ "koa-json": "2.0.2", "lowdb": "1.0.0", "lunr": "2.3.9", - "multer": "1.4.5-lts.1", + "multer": "1.4.5-lts.2", "node-fetch": "2.6.12", "node-forge": "1.3.1", "open": "8.4.2", diff --git a/apps/cli/src/auth/commands/login.command.ts b/apps/cli/src/auth/commands/login.command.ts index 3ad71c62e66..cd5c8ef9bcd 100644 --- a/apps/cli/src/auth/commands/login.command.ts +++ b/apps/cli/src/auth/commands/login.command.ts @@ -106,6 +106,8 @@ export class LoginCommand { return Response.badRequest("client_secret is required."); } } else if (options.sso != null && this.canInteract) { + // If the optional Org SSO Identifier isn't provided, the option value is `true`. + const orgSsoIdentifier = options.sso === true ? null : options.sso; const passwordOptions: any = { type: "password", length: 64, @@ -119,7 +121,7 @@ export class LoginCommand { const codeVerifierHash = await this.cryptoFunctionService.hash(ssoCodeVerifier, "sha256"); const codeChallenge = Utils.fromBufferToUrlB64(codeVerifierHash); try { - const ssoParams = await this.openSsoPrompt(codeChallenge, state); + const ssoParams = await this.openSsoPrompt(codeChallenge, state, orgSsoIdentifier); ssoCode = ssoParams.ssoCode; orgIdentifier = ssoParams.orgIdentifier; } catch { @@ -664,6 +666,7 @@ export class LoginCommand { private async openSsoPrompt( codeChallenge: string, state: string, + orgSsoIdentifier: string, ): Promise<{ ssoCode: string; orgIdentifier: string }> { const env = await firstValueFrom(this.environmentService.environment$); @@ -712,6 +715,8 @@ export class LoginCommand { this.ssoRedirectUri, state, codeChallenge, + null, + orgSsoIdentifier, ); this.platformUtilsService.launchUri(webAppSsoUrl); }); diff --git a/apps/cli/src/program.ts b/apps/cli/src/program.ts index dca4effcdc9..d85f1b366e6 100644 --- a/apps/cli/src/program.ts +++ b/apps/cli/src/program.ts @@ -118,7 +118,10 @@ export class Program extends BaseProgram { .description("Log into a user account.") .option("--method ", "Two-step login method.") .option("--code ", "Two-step login code.") - .option("--sso", "Log in with Single-Sign On.") + .option( + "--sso [identifier]", + "Log in with Single-Sign On with optional organization identifier.", + ) .option("--apikey", "Log in with an Api Key.") .option("--passwordenv ", "Environment variable storing your password") .option( diff --git a/apps/desktop/native-messaging-test-runner/src/ipc.service.ts b/apps/desktop/native-messaging-test-runner/src/ipc.service.ts index b02ff1a4225..d8616e9757a 100644 --- a/apps/desktop/native-messaging-test-runner/src/ipc.service.ts +++ b/apps/desktop/native-messaging-test-runner/src/ipc.service.ts @@ -15,6 +15,8 @@ const DEFAULT_MESSAGE_TIMEOUT = 10 * 1000; // 10 seconds export type MessageHandler = (MessageCommon) => void; +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum IPCConnectionState { Disconnected = "disconnected", Connecting = "connecting", diff --git a/apps/desktop/src/app/tools/send/send.component.ts b/apps/desktop/src/app/tools/send/send.component.ts index cc3007ae133..6c2c3ed53c6 100644 --- a/apps/desktop/src/app/tools/send/send.component.ts +++ b/apps/desktop/src/app/tools/send/send.component.ts @@ -25,6 +25,8 @@ import { SearchBarService } from "../../layout/search/search-bar.service"; import { AddEditComponent } from "./add-edit.component"; +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums enum Action { None = "", Add = "add", diff --git a/apps/desktop/src/autofill/models/ssh-agent-setting.ts b/apps/desktop/src/autofill/models/ssh-agent-setting.ts index f332cc93ee1..1775cf35588 100644 --- a/apps/desktop/src/autofill/models/ssh-agent-setting.ts +++ b/apps/desktop/src/autofill/models/ssh-agent-setting.ts @@ -1,3 +1,5 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum SshAgentPromptType { Always = "always", Never = "never", diff --git a/apps/desktop/src/types/biometric-message.ts b/apps/desktop/src/types/biometric-message.ts index f7a7ef0c507..7616b265005 100644 --- a/apps/desktop/src/types/biometric-message.ts +++ b/apps/desktop/src/types/biometric-message.ts @@ -1,3 +1,5 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum BiometricAction { Authenticate = "authenticate", GetStatus = "status", diff --git a/apps/desktop/src/vault/app/vault/credential-generator-dialog.component.ts b/apps/desktop/src/vault/app/vault/credential-generator-dialog.component.ts index 2858d7330e5..204615443ba 100644 --- a/apps/desktop/src/vault/app/vault/credential-generator-dialog.component.ts +++ b/apps/desktop/src/vault/app/vault/credential-generator-dialog.component.ts @@ -31,6 +31,8 @@ export interface CredentialGeneratorDialogResult { generatedValue?: string; } +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum CredentialGeneratorDialogAction { Selected = "selected", Canceled = "canceled", diff --git a/apps/web/src/app/admin-console/organizations/collections/bulk-collections-dialog/bulk-collections-dialog.component.ts b/apps/web/src/app/admin-console/organizations/collections/bulk-collections-dialog/bulk-collections-dialog.component.ts index dd19c66f21e..147340e6a00 100644 --- a/apps/web/src/app/admin-console/organizations/collections/bulk-collections-dialog/bulk-collections-dialog.component.ts +++ b/apps/web/src/app/admin-console/organizations/collections/bulk-collections-dialog/bulk-collections-dialog.component.ts @@ -43,6 +43,8 @@ export interface BulkCollectionsDialogParams { collections: CollectionView[]; } +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum BulkCollectionsDialogResult { Saved = "saved", Canceled = "canceled", diff --git a/apps/web/src/app/admin-console/organizations/collections/vault.component.ts b/apps/web/src/app/admin-console/organizations/collections/vault.component.ts index 687aef9b671..96c00faceb2 100644 --- a/apps/web/src/app/admin-console/organizations/collections/vault.component.ts +++ b/apps/web/src/app/admin-console/organizations/collections/vault.component.ts @@ -132,6 +132,8 @@ import { VaultHeaderComponent } from "./vault-header/vault-header.component"; const BroadcasterSubscriptionId = "OrgVaultComponent"; const SearchTextDebounceInterval = 200; +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums enum AddAccessStatusType { All = 0, AddAccess = 1, diff --git a/apps/web/src/app/admin-console/organizations/manage/group-add-edit.component.ts b/apps/web/src/app/admin-console/organizations/manage/group-add-edit.component.ts index 2a5af32ecc2..f29b4b642cb 100644 --- a/apps/web/src/app/admin-console/organizations/manage/group-add-edit.component.ts +++ b/apps/web/src/app/admin-console/organizations/manage/group-add-edit.component.ts @@ -58,6 +58,8 @@ import { AddEditGroupDetail } from "./../core/views/add-edit-group-detail"; /** * Indices for the available tabs in the dialog */ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum GroupAddEditTabType { Info = 0, Members = 1, @@ -82,6 +84,8 @@ export interface GroupAddEditDialogParams { initialTab?: GroupAddEditTabType; } +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum GroupAddEditDialogResultType { Saved = "saved", Canceled = "canceled", diff --git a/apps/web/src/app/admin-console/organizations/members/components/member-dialog/member-dialog.component.ts b/apps/web/src/app/admin-console/organizations/members/components/member-dialog/member-dialog.component.ts index c90a2a657e7..8349b44c735 100644 --- a/apps/web/src/app/admin-console/organizations/members/components/member-dialog/member-dialog.component.ts +++ b/apps/web/src/app/admin-console/organizations/members/components/member-dialog/member-dialog.component.ts @@ -64,6 +64,8 @@ import { commaSeparatedEmails } from "./validators/comma-separated-emails.valida import { inputEmailLimitValidator } from "./validators/input-email-limit.validator"; import { orgSeatLimitReachedValidator } from "./validators/org-seat-limit-reached.validator"; +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum MemberDialogTab { Role = 0, Groups = 1, @@ -92,6 +94,8 @@ export interface EditMemberDialogParams extends CommonMemberDialogParams { export type MemberDialogParams = EditMemberDialogParams | AddMemberDialogParams; +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum MemberDialogResult { Saved = "saved", Canceled = "canceled", diff --git a/apps/web/src/app/admin-console/organizations/members/components/reset-password.component.ts b/apps/web/src/app/admin-console/organizations/members/components/reset-password.component.ts index f08cb0b7d7c..4e78d4dc91f 100644 --- a/apps/web/src/app/admin-console/organizations/members/components/reset-password.component.ts +++ b/apps/web/src/app/admin-console/organizations/members/components/reset-password.component.ts @@ -50,6 +50,8 @@ export type ResetPasswordDialogData = { organizationId: string; }; +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum ResetPasswordDialogResult { Ok = "ok", } diff --git a/apps/web/src/app/admin-console/organizations/members/services/organization-user-reset-password/organization-user-reset-password.service.ts b/apps/web/src/app/admin-console/organizations/members/services/organization-user-reset-password/organization-user-reset-password.service.ts index 78d2d8fd165..ecf4d26eb52 100644 --- a/apps/web/src/app/admin-console/organizations/members/services/organization-user-reset-password/organization-user-reset-password.service.ts +++ b/apps/web/src/app/admin-console/organizations/members/services/organization-user-reset-password/organization-user-reset-password.service.ts @@ -112,7 +112,7 @@ export class OrganizationUserResetPasswordService if (orgSymKey == null) { throw new Error("No org key found"); } - const decPrivateKey = await this.encryptService.decryptToBytes( + const decPrivateKey = await this.encryptService.unwrapDecapsulationKey( new EncString(response.encryptedPrivateKey), orgSymKey, ); diff --git a/apps/web/src/app/admin-console/organizations/policies/policy-edit.component.ts b/apps/web/src/app/admin-console/organizations/policies/policy-edit.component.ts index 49f4d15a100..4d722840e23 100644 --- a/apps/web/src/app/admin-console/organizations/policies/policy-edit.component.ts +++ b/apps/web/src/app/admin-console/organizations/policies/policy-edit.component.ts @@ -41,6 +41,8 @@ export type PolicyEditDialogData = { organizationId: string; }; +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum PolicyEditDialogResult { Saved = "saved", UpgradePlan = "upgrade-plan", diff --git a/apps/web/src/app/admin-console/organizations/settings/components/delete-organization-dialog.component.ts b/apps/web/src/app/admin-console/organizations/settings/components/delete-organization-dialog.component.ts index c23dcf2c8f2..e942eecbd37 100644 --- a/apps/web/src/app/admin-console/organizations/settings/components/delete-organization-dialog.component.ts +++ b/apps/web/src/app/admin-console/organizations/settings/components/delete-organization-dialog.component.ts @@ -71,6 +71,8 @@ export interface DeleteOrganizationDialogParams { requestType: "InvalidFamiliesForEnterprise" | "RegularDelete"; } +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum DeleteOrganizationDialogResult { Deleted = "deleted", Canceled = "canceled", diff --git a/apps/web/src/app/admin-console/organizations/shared/components/access-selector/access-selector.component.ts b/apps/web/src/app/admin-console/organizations/shared/components/access-selector/access-selector.component.ts index edd0bfcaada..1db1fc8a06e 100644 --- a/apps/web/src/app/admin-console/organizations/shared/components/access-selector/access-selector.component.ts +++ b/apps/web/src/app/admin-console/organizations/shared/components/access-selector/access-selector.component.ts @@ -26,6 +26,8 @@ import { Permission, } from "./access-selector.models"; +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum PermissionMode { /** * No permission controls or column present. No permission values are emitted. diff --git a/apps/web/src/app/admin-console/organizations/shared/components/access-selector/access-selector.models.ts b/apps/web/src/app/admin-console/organizations/shared/components/access-selector/access-selector.models.ts index 8702c0f7a6c..884483d32b0 100644 --- a/apps/web/src/app/admin-console/organizations/shared/components/access-selector/access-selector.models.ts +++ b/apps/web/src/app/admin-console/organizations/shared/components/access-selector/access-selector.models.ts @@ -15,6 +15,8 @@ import { GroupView } from "../../../core"; /** * Permission options that replace/correspond with manage, readOnly, and hidePassword server fields. */ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum CollectionPermission { View = "view", ViewExceptPass = "viewExceptPass", @@ -23,6 +25,8 @@ export enum CollectionPermission { Manage = "manage", } +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum AccessItemType { Collection, Group, diff --git a/apps/web/src/app/admin-console/organizations/shared/components/collection-dialog/collection-dialog.component.ts b/apps/web/src/app/admin-console/organizations/shared/components/collection-dialog/collection-dialog.component.ts index 37d0ebbd195..07bff3aba64 100644 --- a/apps/web/src/app/admin-console/organizations/shared/components/collection-dialog/collection-dialog.component.ts +++ b/apps/web/src/app/admin-console/organizations/shared/components/collection-dialog/collection-dialog.component.ts @@ -65,6 +65,8 @@ import { } from "../access-selector/access-selector.models"; import { AccessSelectorModule } from "../access-selector/access-selector.module"; +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum CollectionDialogTabType { Info = 0, Access = 1, @@ -76,6 +78,8 @@ export enum CollectionDialogTabType { * @readonly * @enum {string} */ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums enum ButtonType { /** Displayed when the user has reached the maximum number of collections allowed for the organization. */ Upgrade = "upgrade", @@ -103,6 +107,8 @@ export interface CollectionDialogResult { collection: CollectionResponse | CollectionView; } +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum CollectionDialogAction { Saved = "saved", Canceled = "canceled", diff --git a/apps/web/src/app/auth/core/enums/webauthn-login-credential-prf-status.enum.ts b/apps/web/src/app/auth/core/enums/webauthn-login-credential-prf-status.enum.ts index 7dc8217fde5..3073917e57b 100644 --- a/apps/web/src/app/auth/core/enums/webauthn-login-credential-prf-status.enum.ts +++ b/apps/web/src/app/auth/core/enums/webauthn-login-credential-prf-status.enum.ts @@ -1,3 +1,5 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum WebauthnLoginCredentialPrfStatus { Enabled = 0, Supported = 1, diff --git a/apps/web/src/app/auth/emergency-access/enums/emergency-access-status-type.ts b/apps/web/src/app/auth/emergency-access/enums/emergency-access-status-type.ts index 94400f34e6e..16aa2546101 100644 --- a/apps/web/src/app/auth/emergency-access/enums/emergency-access-status-type.ts +++ b/apps/web/src/app/auth/emergency-access/enums/emergency-access-status-type.ts @@ -1,3 +1,5 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum EmergencyAccessStatusType { Invited = 0, Accepted = 1, diff --git a/apps/web/src/app/auth/emergency-access/enums/emergency-access-type.ts b/apps/web/src/app/auth/emergency-access/enums/emergency-access-type.ts index 61a366c433e..ecb0c5a3d07 100644 --- a/apps/web/src/app/auth/emergency-access/enums/emergency-access-type.ts +++ b/apps/web/src/app/auth/emergency-access/enums/emergency-access-type.ts @@ -1,3 +1,5 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum EmergencyAccessType { View = 0, Takeover = 1, diff --git a/apps/web/src/app/components/selectable-avatar.component.ts b/apps/web/src/app/auth/settings/account/selectable-avatar.component.ts similarity index 100% rename from apps/web/src/app/components/selectable-avatar.component.ts rename to apps/web/src/app/auth/settings/account/selectable-avatar.component.ts diff --git a/apps/web/src/app/auth/settings/emergency-access/confirm/emergency-access-confirm.component.ts b/apps/web/src/app/auth/settings/emergency-access/confirm/emergency-access-confirm.component.ts index f3fd19a4e8b..95afc167374 100644 --- a/apps/web/src/app/auth/settings/emergency-access/confirm/emergency-access-confirm.component.ts +++ b/apps/web/src/app/auth/settings/emergency-access/confirm/emergency-access-confirm.component.ts @@ -8,6 +8,8 @@ import { LogService } from "@bitwarden/common/platform/abstractions/log.service" import { DialogConfig, DialogRef, DIALOG_DATA, DialogService } from "@bitwarden/components"; import { KeyService } from "@bitwarden/key-management"; +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum EmergencyAccessConfirmDialogResult { Confirmed = "confirmed", } diff --git a/apps/web/src/app/auth/settings/emergency-access/emergency-access-add-edit.component.ts b/apps/web/src/app/auth/settings/emergency-access/emergency-access-add-edit.component.ts index cf52969c244..1a6510ef011 100644 --- a/apps/web/src/app/auth/settings/emergency-access/emergency-access-add-edit.component.ts +++ b/apps/web/src/app/auth/settings/emergency-access/emergency-access-add-edit.component.ts @@ -26,6 +26,8 @@ export type EmergencyAccessAddEditDialogData = { readOnly: boolean; }; +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum EmergencyAccessAddEditDialogResult { Saved = "saved", Canceled = "canceled", diff --git a/apps/web/src/app/auth/settings/emergency-access/takeover/emergency-access-takeover.component.ts b/apps/web/src/app/auth/settings/emergency-access/takeover/emergency-access-takeover.component.ts index c80f82ae126..edb85dc0f1a 100644 --- a/apps/web/src/app/auth/settings/emergency-access/takeover/emergency-access-takeover.component.ts +++ b/apps/web/src/app/auth/settings/emergency-access/takeover/emergency-access-takeover.component.ts @@ -24,6 +24,8 @@ import { KdfType, KdfConfigService, KeyService } from "@bitwarden/key-management import { EmergencyAccessService } from "../../../emergency-access"; +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum EmergencyAccessTakeoverResultType { Done = "done", } diff --git a/apps/web/src/app/auth/settings/webauthn-login-settings/create-credential-dialog/create-credential-dialog.component.ts b/apps/web/src/app/auth/settings/webauthn-login-settings/create-credential-dialog/create-credential-dialog.component.ts index 591fe3816dc..8e7e25896ab 100644 --- a/apps/web/src/app/auth/settings/webauthn-login-settings/create-credential-dialog/create-credential-dialog.component.ts +++ b/apps/web/src/app/auth/settings/webauthn-login-settings/create-credential-dialog/create-credential-dialog.component.ts @@ -19,6 +19,8 @@ import { PendingWebauthnLoginCredentialView } from "../../../core/views/pending- import { CreatePasskeyFailedIcon } from "./create-passkey-failed.icon"; import { CreatePasskeyIcon } from "./create-passkey.icon"; +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum CreateCredentialDialogResult { Success, } diff --git a/apps/web/src/app/billing/accounts/trial-initiation/trial-billing-step.component.html b/apps/web/src/app/billing/accounts/trial-initiation/trial-billing-step.component.html index d947ea96dfb..64a9781b7cf 100644 --- a/apps/web/src/app/billing/accounts/trial-initiation/trial-billing-step.component.html +++ b/apps/web/src/app/billing/accounts/trial-initiation/trial-billing-step.component.html @@ -51,8 +51,38 @@

{{ "paymentType" | i18n }}

+ + @if (trialLength === 0) { + @let priceLabel = + subscriptionProduct === SubscriptionProduct.PasswordManager + ? "passwordManagerPlanPrice" + : "secretsManagerPlanPrice"; + +
+
+ {{ priceLabel | i18n }}: {{ getPriceFor(formGroup.value.cadence) | currency: "USD $" }} +
+ {{ "estimatedTax" | i18n }}: + @if (fetchingTaxAmount) { + + } @else { + {{ taxAmount | currency: "USD $" }} + } +
+
+
+

+ {{ "total" | i18n }}: + @if (fetchingTaxAmount) { + + } @else { + {{ total | currency: "USD $" }}/{{ interval | i18n }} + } +

+
+ }
+ + + + {{ "loading" | i18n }} + diff --git a/apps/web/src/app/billing/accounts/trial-initiation/trial-billing-step.component.ts b/apps/web/src/app/billing/accounts/trial-initiation/trial-billing-step.component.ts index c6248a06a89..63c42139648 100644 --- a/apps/web/src/app/billing/accounts/trial-initiation/trial-billing-step.component.ts +++ b/apps/web/src/app/billing/accounts/trial-initiation/trial-billing-step.component.ts @@ -1,7 +1,16 @@ // FIXME: Update this file to be type safe and remove this and next line // @ts-strict-ignore -import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from "@angular/core"; +import { + Component, + EventEmitter, + Input, + OnDestroy, + OnInit, + Output, + ViewChild, +} from "@angular/core"; import { FormBuilder, Validators } from "@angular/forms"; +import { from, Subject, switchMap, takeUntil } from "rxjs"; import { ManageTaxInformationComponent } from "@bitwarden/angular/billing/components"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; @@ -12,7 +21,14 @@ import { PaymentInformation, PlanInformation, } from "@bitwarden/common/billing/abstractions/organization-billing.service"; -import { PaymentMethodType, PlanType, ProductTierType } from "@bitwarden/common/billing/enums"; +import { TaxServiceAbstraction } from "@bitwarden/common/billing/abstractions/tax.service.abstraction"; +import { + PaymentMethodType, + PlanType, + ProductTierType, + ProductType, +} from "@bitwarden/common/billing/enums"; +import { PreviewTaxAmountForOrganizationTrialRequest } from "@bitwarden/common/billing/models/request/tax"; import { PlanResponse } from "@bitwarden/common/billing/models/response/plan.response"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; @@ -34,11 +50,15 @@ export interface OrganizationCreatedEvent { planDescription: string; } +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums enum SubscriptionCadence { Annual, Monthly, } +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum SubscriptionProduct { PasswordManager, SecretsManager, @@ -50,7 +70,7 @@ export enum SubscriptionProduct { imports: [BillingSharedModule], standalone: true, }) -export class TrialBillingStepComponent implements OnInit { +export class TrialBillingStepComponent implements OnInit, OnDestroy { @ViewChild(PaymentComponent) paymentComponent: PaymentComponent; @ViewChild(ManageTaxInformationComponent) taxInfoComponent: ManageTaxInformationComponent; @Input() organizationInfo: OrganizationInfo; @@ -60,6 +80,7 @@ export class TrialBillingStepComponent implements OnInit { @Output() organizationCreated = new EventEmitter(); loading = true; + fetchingTaxAmount = false; annualCadence = SubscriptionCadence.Annual; monthlyCadence = SubscriptionCadence.Monthly; @@ -73,6 +94,12 @@ export class TrialBillingStepComponent implements OnInit { annualPlan?: PlanResponse; monthlyPlan?: PlanResponse; + taxAmount = 0; + + private destroy$ = new Subject(); + + protected readonly SubscriptionProduct = SubscriptionProduct; + constructor( private apiService: ApiService, private i18nService: I18nService, @@ -80,6 +107,7 @@ export class TrialBillingStepComponent implements OnInit { private messagingService: MessagingService, private organizationBillingService: OrganizationBillingService, private toastService: ToastService, + private taxService: TaxServiceAbstraction, ) {} async ngOnInit(): Promise { @@ -87,9 +115,26 @@ export class TrialBillingStepComponent implements OnInit { this.applicablePlans = plans.data.filter(this.isApplicable); this.annualPlan = this.findPlanFor(SubscriptionCadence.Annual); this.monthlyPlan = this.findPlanFor(SubscriptionCadence.Monthly); + + if (this.trialLength === 0) { + this.formGroup.controls.cadence.valueChanges + .pipe( + switchMap((cadence) => from(this.previewTaxAmount(cadence))), + takeUntil(this.destroy$), + ) + .subscribe((taxAmount) => { + this.taxAmount = taxAmount; + }); + } + this.loading = false; } + ngOnDestroy() { + this.destroy$.next(); + this.destroy$.complete(); + } + async submit(): Promise { if (!this.taxInfoComponent.validate()) { return; @@ -115,7 +160,11 @@ export class TrialBillingStepComponent implements OnInit { this.messagingService.send("organizationCreated", { organizationId }); } - protected changedCountry() { + async onTaxInformationChanged() { + if (this.trialLength === 0) { + this.taxAmount = await this.previewTaxAmount(this.formGroup.value.cadence); + } + this.paymentComponent.showBankAccount = this.taxInfoComponent.getTaxInformation().country === "US"; if ( @@ -170,6 +219,7 @@ export class TrialBillingStepComponent implements OnInit { const payment: PaymentInformation = { paymentMethod, billing: this.getBillingInformationFromTaxInfoComponent(), + skipTrial: this.trialLength === 0, }; const response = await this.organizationBillingService.purchaseSubscription({ @@ -250,4 +300,45 @@ export class TrialBillingStepComponent implements OnInit { const notDisabledOrLegacy = !plan.disabled && !plan.legacyYear; return hasCorrectProductType && notDisabledOrLegacy; } + + private previewTaxAmount = async (cadence: SubscriptionCadence): Promise => { + this.fetchingTaxAmount = true; + + if (!this.taxInfoComponent.validate()) { + return 0; + } + + const plan = this.findPlanFor(cadence); + + const productType = + this.subscriptionProduct === SubscriptionProduct.PasswordManager + ? ProductType.PasswordManager + : ProductType.SecretsManager; + + const taxInformation = this.taxInfoComponent.getTaxInformation(); + + const request: PreviewTaxAmountForOrganizationTrialRequest = { + planType: plan.type, + productType, + taxInformation: { + ...taxInformation, + }, + }; + + const response = await this.taxService.previewTaxAmountForOrganizationTrial(request); + this.fetchingTaxAmount = false; + return response.taxAmount; + }; + + get price() { + return this.getPriceFor(this.formGroup.value.cadence); + } + + get total() { + return this.price + this.taxAmount; + } + + get interval() { + return this.formGroup.value.cadence === SubscriptionCadence.Annual ? "year" : "month"; + } } diff --git a/apps/web/src/app/billing/members/free-bitwarden-families.component.ts b/apps/web/src/app/billing/members/free-bitwarden-families.component.ts index eb6bfdf368b..b482007e30b 100644 --- a/apps/web/src/app/billing/members/free-bitwarden-families.component.ts +++ b/apps/web/src/app/billing/members/free-bitwarden-families.component.ts @@ -179,7 +179,7 @@ export class FreeBitwardenFamiliesComponent implements OnInit { return; } - await this.apiService.deleteRevokeSponsorship(this.organizationId); + await this.organizationSponsorshipApiService.deleteRevokeSponsorship(this.organizationId, true); this.toastService.showToast({ variant: "success", diff --git a/apps/web/src/app/billing/organizations/change-plan-dialog.component.ts b/apps/web/src/app/billing/organizations/change-plan-dialog.component.ts index 8cff90edd5b..49c5bb775b1 100644 --- a/apps/web/src/app/billing/organizations/change-plan-dialog.component.ts +++ b/apps/web/src/app/billing/organizations/change-plan-dialog.component.ts @@ -74,11 +74,15 @@ type ChangePlanDialogParams = { productTierType: ProductTierType; }; +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum ChangePlanDialogResultType { Closed = "closed", Submitted = "submitted", } +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum PlanCardState { Selected = "selected", NotSelected = "not_selected", diff --git a/apps/web/src/app/billing/organizations/download-license.component.ts b/apps/web/src/app/billing/organizations/download-license.component.ts index fecb58a7a9d..66778aec50f 100644 --- a/apps/web/src/app/billing/organizations/download-license.component.ts +++ b/apps/web/src/app/billing/organizations/download-license.component.ts @@ -7,6 +7,8 @@ import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-conso import { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.service"; import { DialogConfig, DIALOG_DATA, DialogRef, DialogService } from "@bitwarden/components"; +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum DownloadLicenseDialogResult { Cancelled = "cancelled", Downloaded = "downloaded", diff --git a/apps/web/src/app/billing/organizations/organization-subscription-selfhost.component.ts b/apps/web/src/app/billing/organizations/organization-subscription-selfhost.component.ts index e6854a5216b..2189bfa830f 100644 --- a/apps/web/src/app/billing/organizations/organization-subscription-selfhost.component.ts +++ b/apps/web/src/app/billing/organizations/organization-subscription-selfhost.component.ts @@ -27,6 +27,8 @@ import { DialogService, ToastService } from "@bitwarden/components"; import { BillingSyncKeyComponent } from "./billing-sync-key.component"; +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums enum LicenseOptions { SYNC = 0, UPLOAD = 1, diff --git a/apps/web/src/app/billing/settings/sponsored-families.component.ts b/apps/web/src/app/billing/settings/sponsored-families.component.ts index cee08bae8cd..7e493168ce2 100644 --- a/apps/web/src/app/billing/settings/sponsored-families.component.ts +++ b/apps/web/src/app/billing/settings/sponsored-families.component.ts @@ -112,13 +112,15 @@ export class SponsoredFamiliesComponent implements OnInit, OnDestroy { }); } }); - this.anyOrgsAvailable$ = this.availableSponsorshipOrgs$.pipe(map((orgs) => orgs.length > 0)); this.activeSponsorshipOrgs$ = this.organizationService .organizations$(userId) - .pipe(map((orgs) => orgs.filter((o) => o.familySponsorshipFriendlyName !== null))); - + .pipe( + map((orgs) => + orgs.filter((o) => o.familySponsorshipFriendlyName !== null && !o.isAdminInitiated), + ), + ); this.anyActiveSponsorships$ = this.activeSponsorshipOrgs$.pipe(map((orgs) => orgs.length > 0)); this.loading = false; diff --git a/apps/web/src/app/billing/settings/sponsoring-org-row.component.ts b/apps/web/src/app/billing/settings/sponsoring-org-row.component.ts index 33e6334c577..39a7531082a 100644 --- a/apps/web/src/app/billing/settings/sponsoring-org-row.component.ts +++ b/apps/web/src/app/billing/settings/sponsoring-org-row.component.ts @@ -109,7 +109,7 @@ export class SponsoringOrgRowComponent implements OnInit { return; } - await this.apiService.deleteRevokeSponsorship(this.sponsoringOrg.id); + await this.organizationSponsorshipApiService.deleteRevokeSponsorship(this.sponsoringOrg.id); this.toastService.showToast({ variant: "success", title: null, diff --git a/apps/web/src/app/billing/shared/add-credit-dialog.component.ts b/apps/web/src/app/billing/shared/add-credit-dialog.component.ts index 45dab542ce8..ec6e251418b 100644 --- a/apps/web/src/app/billing/shared/add-credit-dialog.component.ts +++ b/apps/web/src/app/billing/shared/add-credit-dialog.component.ts @@ -21,6 +21,8 @@ export interface AddCreditDialogData { organizationId: string; } +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum AddCreditDialogResult { Added = "added", Cancelled = "cancelled", diff --git a/apps/web/src/app/billing/shared/adjust-payment-dialog/adjust-payment-dialog.component.ts b/apps/web/src/app/billing/shared/adjust-payment-dialog/adjust-payment-dialog.component.ts index e7b7cc78250..9d32becd1bb 100644 --- a/apps/web/src/app/billing/shared/adjust-payment-dialog/adjust-payment-dialog.component.ts +++ b/apps/web/src/app/billing/shared/adjust-payment-dialog/adjust-payment-dialog.component.ts @@ -30,6 +30,8 @@ export interface AdjustPaymentDialogParams { providerId?: string; } +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum AdjustPaymentDialogResultType { Closed = "closed", Submitted = "submitted", diff --git a/apps/web/src/app/billing/shared/adjust-storage-dialog/adjust-storage-dialog.component.ts b/apps/web/src/app/billing/shared/adjust-storage-dialog/adjust-storage-dialog.component.ts index 3acba414df4..6cd17218f02 100644 --- a/apps/web/src/app/billing/shared/adjust-storage-dialog/adjust-storage-dialog.component.ts +++ b/apps/web/src/app/billing/shared/adjust-storage-dialog/adjust-storage-dialog.component.ts @@ -22,6 +22,8 @@ export interface AdjustStorageDialogParams { organizationId?: string; } +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum AdjustStorageDialogResultType { Submitted = "submitted", Closed = "closed", diff --git a/apps/web/src/app/billing/shared/offboarding-survey.component.ts b/apps/web/src/app/billing/shared/offboarding-survey.component.ts index cecbc302f40..62213c1fe94 100644 --- a/apps/web/src/app/billing/shared/offboarding-survey.component.ts +++ b/apps/web/src/app/billing/shared/offboarding-survey.component.ts @@ -25,6 +25,8 @@ type OrganizationOffboardingParams = { export type OffboardingSurveyDialogParams = UserOffboardingParams | OrganizationOffboardingParams; +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum OffboardingSurveyDialogResultType { Closed = "closed", Submitted = "submitted", diff --git a/apps/web/src/app/billing/shared/update-license-types.ts b/apps/web/src/app/billing/shared/update-license-types.ts index 8f939ac62a9..8ba13541ba8 100644 --- a/apps/web/src/app/billing/shared/update-license-types.ts +++ b/apps/web/src/app/billing/shared/update-license-types.ts @@ -1,3 +1,5 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum UpdateLicenseDialogResult { Updated = "updated", Cancelled = "cancelled", diff --git a/apps/web/src/app/dirt/reports/reports.ts b/apps/web/src/app/dirt/reports/reports.ts index 500ae23e5cf..c47928af1e9 100644 --- a/apps/web/src/app/dirt/reports/reports.ts +++ b/apps/web/src/app/dirt/reports/reports.ts @@ -7,6 +7,8 @@ import { ReportUnsecuredWebsites } from "./icons/report-unsecured-websites.icon" import { ReportWeakPasswords } from "./icons/report-weak-passwords.icon"; import { ReportEntry } from "./shared"; +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum ReportType { ExposedPasswords = "exposedPasswords", ReusedPasswords = "reusedPasswords", diff --git a/apps/web/src/app/dirt/reports/shared/models/report-variant.ts b/apps/web/src/app/dirt/reports/shared/models/report-variant.ts index 3beba65f7d9..48b213f4cf6 100644 --- a/apps/web/src/app/dirt/reports/shared/models/report-variant.ts +++ b/apps/web/src/app/dirt/reports/shared/models/report-variant.ts @@ -1,3 +1,5 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum ReportVariant { Enabled = "Enabled", RequiresPremium = "RequiresPremium", diff --git a/apps/web/src/app/shared/loose-components.module.ts b/apps/web/src/app/shared/loose-components.module.ts index 30d1dd1af75..ab6c6cc5d72 100644 --- a/apps/web/src/app/shared/loose-components.module.ts +++ b/apps/web/src/app/shared/loose-components.module.ts @@ -22,6 +22,7 @@ import { DangerZoneComponent } from "../auth/settings/account/danger-zone.compon import { DeauthorizeSessionsComponent } from "../auth/settings/account/deauthorize-sessions.component"; import { DeleteAccountDialogComponent } from "../auth/settings/account/delete-account-dialog.component"; import { ProfileComponent } from "../auth/settings/account/profile.component"; +import { SelectableAvatarComponent } from "../auth/settings/account/selectable-avatar.component"; import { EmergencyAccessConfirmComponent } from "../auth/settings/emergency-access/confirm/emergency-access-confirm.component"; import { EmergencyAccessAddEditComponent } from "../auth/settings/emergency-access/emergency-access-add-edit.component"; import { EmergencyAccessComponent } from "../auth/settings/emergency-access/emergency-access.component"; @@ -39,7 +40,6 @@ import { VerifyRecoverDeleteComponent } from "../auth/verify-recover-delete.comp import { SponsoredFamiliesComponent } from "../billing/settings/sponsored-families.component"; import { SponsoringOrgRowComponent } from "../billing/settings/sponsoring-org-row.component"; import { DynamicAvatarComponent } from "../components/dynamic-avatar.component"; -import { SelectableAvatarComponent } from "../components/selectable-avatar.component"; import { ExposedPasswordsReportComponent as OrgExposedPasswordsReportComponent } from "../dirt/reports/pages/organizations/exposed-passwords-report.component"; import { InactiveTwoFactorReportComponent as OrgInactiveTwoFactorReportComponent } from "../dirt/reports/pages/organizations/inactive-two-factor-report.component"; import { ReusedPasswordsReportComponent as OrgReusedPasswordsReportComponent } from "../dirt/reports/pages/organizations/reused-passwords-report.component"; diff --git a/apps/web/src/app/vault/components/vault-item-dialog/vault-item-dialog.component.ts b/apps/web/src/app/vault/components/vault-item-dialog/vault-item-dialog.component.ts index 460b8d58d63..10c35f861b9 100644 --- a/apps/web/src/app/vault/components/vault-item-dialog/vault-item-dialog.component.ts +++ b/apps/web/src/app/vault/components/vault-item-dialog/vault-item-dialog.component.ts @@ -95,6 +95,8 @@ export interface VaultItemDialogParams { restore?: (c: CipherView) => Promise; } +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum VaultItemDialogResult { /** * A cipher was saved (created or updated). diff --git a/apps/web/src/app/vault/components/web-generator-dialog/web-generator-dialog.component.ts b/apps/web/src/app/vault/components/web-generator-dialog/web-generator-dialog.component.ts index 2d0aa0231f1..e20efa9dbb8 100644 --- a/apps/web/src/app/vault/components/web-generator-dialog/web-generator-dialog.component.ts +++ b/apps/web/src/app/vault/components/web-generator-dialog/web-generator-dialog.component.ts @@ -26,6 +26,8 @@ export interface WebVaultGeneratorDialogResult { generatedValue?: string; } +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum WebVaultGeneratorDialogAction { Selected = "selected", Canceled = "canceled", diff --git a/apps/web/src/app/vault/individual-vault/add-edit-v2.component.ts b/apps/web/src/app/vault/individual-vault/add-edit-v2.component.ts index 5dcbf0d4e78..621e0ec88c5 100644 --- a/apps/web/src/app/vault/individual-vault/add-edit-v2.component.ts +++ b/apps/web/src/app/vault/individual-vault/add-edit-v2.component.ts @@ -35,6 +35,8 @@ import { WebCipherFormGenerationService } from "../services/web-cipher-form-gene /** * The result of the AddEditCipherDialogV2 component. */ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum AddEditCipherDialogResult { Edited = "edited", Added = "added", diff --git a/apps/web/src/app/vault/individual-vault/bulk-action-dialogs/bulk-delete-dialog/bulk-delete-dialog.component.ts b/apps/web/src/app/vault/individual-vault/bulk-action-dialogs/bulk-delete-dialog/bulk-delete-dialog.component.ts index f8084b03e33..1650b0f371f 100644 --- a/apps/web/src/app/vault/individual-vault/bulk-action-dialogs/bulk-delete-dialog/bulk-delete-dialog.component.ts +++ b/apps/web/src/app/vault/individual-vault/bulk-action-dialogs/bulk-delete-dialog/bulk-delete-dialog.component.ts @@ -29,6 +29,8 @@ export interface BulkDeleteDialogParams { unassignedCiphers?: string[]; } +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum BulkDeleteDialogResult { Deleted = "deleted", Canceled = "canceled", diff --git a/apps/web/src/app/vault/individual-vault/bulk-action-dialogs/bulk-move-dialog/bulk-move-dialog.component.ts b/apps/web/src/app/vault/individual-vault/bulk-action-dialogs/bulk-move-dialog/bulk-move-dialog.component.ts index 8f0827e4b51..d287c430d49 100644 --- a/apps/web/src/app/vault/individual-vault/bulk-action-dialogs/bulk-move-dialog/bulk-move-dialog.component.ts +++ b/apps/web/src/app/vault/individual-vault/bulk-action-dialogs/bulk-move-dialog/bulk-move-dialog.component.ts @@ -23,6 +23,8 @@ export interface BulkMoveDialogParams { cipherIds?: string[]; } +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum BulkMoveDialogResult { Moved = "moved", Canceled = "canceled", diff --git a/apps/web/src/app/vault/individual-vault/folder-add-edit.component.ts b/apps/web/src/app/vault/individual-vault/folder-add-edit.component.ts index ad6cbfad43d..6a3c5663d93 100644 --- a/apps/web/src/app/vault/individual-vault/folder-add-edit.component.ts +++ b/apps/web/src/app/vault/individual-vault/folder-add-edit.component.ts @@ -113,6 +113,8 @@ export interface FolderAddEditDialogParams { folderId: string; } +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum FolderAddEditDialogResult { Deleted = "deleted", Canceled = "canceled", diff --git a/apps/web/src/app/vault/individual-vault/vault-banners/services/vault-banners.service.ts b/apps/web/src/app/vault/individual-vault/vault-banners/services/vault-banners.service.ts index 1fa5ae1ad8b..ca16541f88f 100644 --- a/apps/web/src/app/vault/individual-vault/vault-banners/services/vault-banners.service.ts +++ b/apps/web/src/app/vault/individual-vault/vault-banners/services/vault-banners.service.ts @@ -17,6 +17,8 @@ import { UserId } from "@bitwarden/common/types/guid"; import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction"; import { PBKDF2KdfConfig, KdfConfigService, KdfType } from "@bitwarden/key-management"; +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum VisibleVaultBanner { KDFSettings = "kdf-settings", OutdatedBrowser = "outdated-browser", diff --git a/apps/web/src/app/vault/individual-vault/vault-filter/shared/models/vault-filter-section.type.ts b/apps/web/src/app/vault/individual-vault/vault-filter/shared/models/vault-filter-section.type.ts index 0f949e17146..7566dbdc507 100644 --- a/apps/web/src/app/vault/individual-vault/vault-filter/shared/models/vault-filter-section.type.ts +++ b/apps/web/src/app/vault/individual-vault/vault-filter/shared/models/vault-filter-section.type.ts @@ -15,6 +15,8 @@ export type VaultFilterType = | FolderFilter | CollectionFilter; +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum VaultFilterLabel { OrganizationFilter = "organizationFilter", TypeFilter = "typeFilter", diff --git a/apps/web/src/app/vault/individual-vault/view.component.ts b/apps/web/src/app/vault/individual-vault/view.component.ts index e7b06cbb8d6..f52a4da3ffb 100644 --- a/apps/web/src/app/vault/individual-vault/view.component.ts +++ b/apps/web/src/app/vault/individual-vault/view.component.ts @@ -54,6 +54,8 @@ export interface ViewCipherDialogParams { disableEdit?: boolean; } +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum ViewCipherDialogResult { Edited = "edited", Deleted = "deleted", diff --git a/apps/web/src/app/vault/services/browser-extension-prompt.service.ts b/apps/web/src/app/vault/services/browser-extension-prompt.service.ts index 5617d4aef75..f928404a2a9 100644 --- a/apps/web/src/app/vault/services/browser-extension-prompt.service.ts +++ b/apps/web/src/app/vault/services/browser-extension-prompt.service.ts @@ -7,6 +7,8 @@ import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/pl import { Utils } from "@bitwarden/common/platform/misc/utils"; import { VaultMessages } from "@bitwarden/common/vault/enums/vault-messages.enum"; +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum BrowserPromptState { Loading = "loading", Error = "error", diff --git a/bitwarden_license/bit-cli/src/bw.ts b/bitwarden_license/bit-cli/src/bw.ts index ffbc186d9e0..2e4e945b9c8 100644 --- a/bitwarden_license/bit-cli/src/bw.ts +++ b/bitwarden_license/bit-cli/src/bw.ts @@ -1,3 +1,5 @@ +import "core-js/proposals/explicit-resource-management"; + import { program } from "commander"; import { registerOssPrograms } from "@bitwarden/cli/register-oss-programs"; diff --git a/bitwarden_license/bit-common/src/dirt/reports/risk-insights/models/password-health.ts b/bitwarden_license/bit-common/src/dirt/reports/risk-insights/models/password-health.ts index 723d737d5bd..b8333828693 100644 --- a/bitwarden_license/bit-common/src/dirt/reports/risk-insights/models/password-health.ts +++ b/bitwarden_license/bit-common/src/dirt/reports/risk-insights/models/password-health.ts @@ -149,6 +149,8 @@ export interface PasswordHealthReportApplicationsRequest { url: string; } +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum DrawerType { None = 0, AppAtRiskMembers = 1, diff --git a/bitwarden_license/bit-common/src/dirt/reports/risk-insights/services/risk-insights-report.service.spec.ts b/bitwarden_license/bit-common/src/dirt/reports/risk-insights/services/risk-insights-report.service.spec.ts index 705eb1231a9..f9177bf1bf7 100644 --- a/bitwarden_license/bit-common/src/dirt/reports/risk-insights/services/risk-insights-report.service.spec.ts +++ b/bitwarden_license/bit-common/src/dirt/reports/risk-insights/services/risk-insights-report.service.spec.ts @@ -50,7 +50,7 @@ describe("RiskInsightsReportService", () => { let testCase = testCaseResults[0]; expect(testCase).toBeTruthy(); expect(testCase.cipherMembers).toHaveLength(2); - expect(testCase.trimmedUris).toHaveLength(3); + expect(testCase.trimmedUris).toHaveLength(2); expect(testCase.weakPasswordDetail).toBeTruthy(); expect(testCase.exposedPasswordDetail).toBeTruthy(); expect(testCase.reusedPasswordCount).toEqual(2); @@ -69,7 +69,7 @@ describe("RiskInsightsReportService", () => { it("should generate the raw data + uri report correctly", async () => { const result = await firstValueFrom(service.generateRawDataUriReport$("orgId")); - expect(result).toHaveLength(9); + expect(result).toHaveLength(8); // Two ciphers that have google.com as their uri. There should be 2 results const googleResults = result.filter((x) => x.trimmedUri === "google.com"); @@ -88,7 +88,7 @@ describe("RiskInsightsReportService", () => { it("should generate applications health report data correctly", async () => { const result = await firstValueFrom(service.generateApplicationsReport$("orgId")); - expect(result).toHaveLength(6); + expect(result).toHaveLength(5); // Two ciphers have google.com associated with them. The first cipher // has 2 members and the second has 4. However, the 2 members in the first @@ -132,7 +132,7 @@ describe("RiskInsightsReportService", () => { expect(reportSummary.totalMemberCount).toEqual(7); expect(reportSummary.totalAtRiskMemberCount).toEqual(6); - expect(reportSummary.totalApplicationCount).toEqual(6); - expect(reportSummary.totalAtRiskApplicationCount).toEqual(5); + expect(reportSummary.totalApplicationCount).toEqual(5); + expect(reportSummary.totalAtRiskApplicationCount).toEqual(4); }); }); diff --git a/bitwarden_license/bit-common/src/dirt/reports/risk-insights/services/risk-insights-report.service.ts b/bitwarden_license/bit-common/src/dirt/reports/risk-insights/services/risk-insights-report.service.ts index 027760f678c..8a6eb5000cd 100644 --- a/bitwarden_license/bit-common/src/dirt/reports/risk-insights/services/risk-insights-report.service.ts +++ b/bitwarden_license/bit-common/src/dirt/reports/risk-insights/services/risk-insights-report.service.ts @@ -428,7 +428,7 @@ export class RiskInsightsReportService { const cipherUris: string[] = []; const uris = cipher.login?.uris ?? []; uris.map((u: { uri: string }) => { - const uri = Utils.getHostname(u.uri).replace("www.", ""); + const uri = Utils.getDomain(u.uri); if (!cipherUris.includes(uri)) { cipherUris.push(uri); } diff --git a/bitwarden_license/bit-web/src/app/admin-console/providers/manage/dialogs/add-edit-member-dialog.component.ts b/bitwarden_license/bit-web/src/app/admin-console/providers/manage/dialogs/add-edit-member-dialog.component.ts index 0213903c4d9..67f2382cf91 100644 --- a/bitwarden_license/bit-web/src/app/admin-console/providers/manage/dialogs/add-edit-member-dialog.component.ts +++ b/bitwarden_license/bit-web/src/app/admin-console/providers/manage/dialogs/add-edit-member-dialog.component.ts @@ -25,6 +25,8 @@ export type AddEditMemberDialogParams = { }; }; +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum AddEditMemberDialogResultType { Closed = "closed", Deleted = "deleted", diff --git a/bitwarden_license/bit-web/src/app/admin-console/providers/services/web-provider.service.ts b/bitwarden_license/bit-web/src/app/admin-console/providers/services/web-provider.service.ts index 844c6b779a9..418b7020ff9 100644 --- a/bitwarden_license/bit-web/src/app/admin-console/providers/services/web-provider.service.ts +++ b/bitwarden_license/bit-web/src/app/admin-console/providers/services/web-provider.service.ts @@ -74,7 +74,7 @@ export class WebProviderService { const [publicKey, encryptedPrivateKey] = await this.keyService.makeKeyPair(organizationKey); - const encryptedCollectionName = await this.encryptService.encrypt( + const encryptedCollectionName = await this.encryptService.encryptString( this.i18nService.t("defaultCollection"), organizationKey, ); diff --git a/bitwarden_license/bit-web/src/app/billing/providers/clients/add-existing-organization-dialog.component.ts b/bitwarden_license/bit-web/src/app/billing/providers/clients/add-existing-organization-dialog.component.ts index 0d1602946c7..4bb2c36ef15 100644 --- a/bitwarden_license/bit-web/src/app/billing/providers/clients/add-existing-organization-dialog.component.ts +++ b/bitwarden_license/bit-web/src/app/billing/providers/clients/add-existing-organization-dialog.component.ts @@ -18,6 +18,8 @@ export type AddExistingOrganizationDialogParams = { provider: Provider; }; +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum AddExistingOrganizationDialogResultType { Closed = "closed", Submitted = "submitted", diff --git a/bitwarden_license/bit-web/src/app/billing/providers/clients/create-client-dialog.component.ts b/bitwarden_license/bit-web/src/app/billing/providers/clients/create-client-dialog.component.ts index d3245916ad7..d71e18cd539 100644 --- a/bitwarden_license/bit-web/src/app/billing/providers/clients/create-client-dialog.component.ts +++ b/bitwarden_license/bit-web/src/app/billing/providers/clients/create-client-dialog.component.ts @@ -22,6 +22,8 @@ type CreateClientDialogParams = { plans: PlanResponse[]; }; +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum CreateClientDialogResultType { Closed = "closed", Submitted = "submitted", diff --git a/bitwarden_license/bit-web/src/app/billing/providers/clients/manage-client-name-dialog.component.ts b/bitwarden_license/bit-web/src/app/billing/providers/clients/manage-client-name-dialog.component.ts index bbcd5f7ed63..45abeab1f4a 100644 --- a/bitwarden_license/bit-web/src/app/billing/providers/clients/manage-client-name-dialog.component.ts +++ b/bitwarden_license/bit-web/src/app/billing/providers/clients/manage-client-name-dialog.component.ts @@ -23,6 +23,8 @@ type ManageClientNameDialogParams = { }; }; +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum ManageClientNameDialogResultType { Closed = "closed", Submitted = "submitted", diff --git a/bitwarden_license/bit-web/src/app/billing/providers/clients/manage-client-subscription-dialog.component.ts b/bitwarden_license/bit-web/src/app/billing/providers/clients/manage-client-subscription-dialog.component.ts index b79c887e77e..ced48bfdbea 100644 --- a/bitwarden_license/bit-web/src/app/billing/providers/clients/manage-client-subscription-dialog.component.ts +++ b/bitwarden_license/bit-web/src/app/billing/providers/clients/manage-client-subscription-dialog.component.ts @@ -18,6 +18,8 @@ type ManageClientSubscriptionDialogParams = { provider: Provider; }; +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum ManageClientSubscriptionDialogResultType { Closed = "closed", Submitted = "submitted", diff --git a/bitwarden_license/bit-web/src/app/dirt/access-intelligence/risk-insights.component.ts b/bitwarden_license/bit-web/src/app/dirt/access-intelligence/risk-insights.component.ts index ab74869bfc9..5aca124a46a 100644 --- a/bitwarden_license/bit-web/src/app/dirt/access-intelligence/risk-insights.component.ts +++ b/bitwarden_license/bit-web/src/app/dirt/access-intelligence/risk-insights.component.ts @@ -37,6 +37,8 @@ import { PasswordHealthMembersURIComponent } from "./password-health-members-uri import { PasswordHealthMembersComponent } from "./password-health-members.component"; import { PasswordHealthComponent } from "./password-health.component"; +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum RiskInsightsTabType { AllApps = 0, CriticalApps = 1, diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/projects/dialog/project-dialog.component.ts b/bitwarden_license/bit-web/src/app/secrets-manager/projects/dialog/project-dialog.component.ts index 74824de00e0..c96887cc9ac 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/projects/dialog/project-dialog.component.ts +++ b/bitwarden_license/bit-web/src/app/secrets-manager/projects/dialog/project-dialog.component.ts @@ -11,6 +11,8 @@ import { DialogRef, DIALOG_DATA, BitValidators, ToastService } from "@bitwarden/ import { ProjectView } from "../../models/view/project.view"; import { ProjectService } from "../../projects/project.service"; +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum OperationType { Add, Edit, diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/secrets/dialog/secret-dialog.component.ts b/bitwarden_license/bit-web/src/app/secrets-manager/secrets/dialog/secret-dialog.component.ts index 88b3e5e2172..09a78e02c44 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/secrets/dialog/secret-dialog.component.ts +++ b/bitwarden_license/bit-web/src/app/secrets-manager/secrets/dialog/secret-dialog.component.ts @@ -44,11 +44,15 @@ import { SecretService } from "../secret.service"; import { SecretDeleteDialogComponent, SecretDeleteOperation } from "./secret-delete.component"; +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum OperationType { Add, Edit, } +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum SecretDialogTabType { NameValuePair = 0, People = 1, diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/service-accounts/dialog/service-account-dialog.component.ts b/bitwarden_license/bit-web/src/app/secrets-manager/service-accounts/dialog/service-account-dialog.component.ts index e1cd7a77b28..241c736fb7a 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/service-accounts/dialog/service-account-dialog.component.ts +++ b/bitwarden_license/bit-web/src/app/secrets-manager/service-accounts/dialog/service-account-dialog.component.ts @@ -10,6 +10,8 @@ import { DialogRef, DIALOG_DATA, BitValidators, ToastService } from "@bitwarden/ import { ServiceAccountView } from "../../models/view/service-account.view"; import { ServiceAccountService } from "../service-account.service"; +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum OperationType { Add, Edit, diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/shared/access-policies/access-policy-selector/models/enums/ap-item.enum.ts b/bitwarden_license/bit-web/src/app/secrets-manager/shared/access-policies/access-policy-selector/models/enums/ap-item.enum.ts index 6d060ac255d..6b92fd7458a 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/shared/access-policies/access-policy-selector/models/enums/ap-item.enum.ts +++ b/bitwarden_license/bit-web/src/app/secrets-manager/shared/access-policies/access-policy-selector/models/enums/ap-item.enum.ts @@ -1,3 +1,5 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum ApItemEnum { User, Group, diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/shared/access-policies/access-policy-selector/models/enums/ap-permission.enum.ts b/bitwarden_license/bit-web/src/app/secrets-manager/shared/access-policies/access-policy-selector/models/enums/ap-permission.enum.ts index eb442b0af5d..a57f9636178 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/shared/access-policies/access-policy-selector/models/enums/ap-permission.enum.ts +++ b/bitwarden_license/bit-web/src/app/secrets-manager/shared/access-policies/access-policy-selector/models/enums/ap-permission.enum.ts @@ -1,3 +1,5 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum ApPermissionEnum { CanRead = "canRead", CanReadWrite = "canReadWrite", diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/shared/dialogs/bulk-confirmation-dialog.component.ts b/bitwarden_license/bit-web/src/app/secrets-manager/shared/dialogs/bulk-confirmation-dialog.component.ts index a43207ed75e..935ee1c8518 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/shared/dialogs/bulk-confirmation-dialog.component.ts +++ b/bitwarden_license/bit-web/src/app/secrets-manager/shared/dialogs/bulk-confirmation-dialog.component.ts @@ -15,6 +15,8 @@ export interface BulkConfirmationStatus { description: string; } +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum BulkConfirmationResult { Continue, Cancel, diff --git a/eslint.config.mjs b/eslint.config.mjs index 9d93d1118c0..7928224dc00 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -73,6 +73,7 @@ export default tseslint.config( "@angular-eslint/use-lifecycle-interface": "error", "@angular-eslint/use-pipe-transform-interface": 0, "@bitwarden/platform/required-using": "error", + "@bitwarden/platform/no-enums": "error", "@typescript-eslint/explicit-member-accessibility": ["error", { accessibility: "no-public" }], "@typescript-eslint/no-explicit-any": "off", // TODO: This should be re-enabled "@typescript-eslint/no-floating-promises": "error", diff --git a/libs/admin-console/src/common/collections/services/default-collection-admin.service.ts b/libs/admin-console/src/common/collections/services/default-collection-admin.service.ts index 890353d9039..293090ce315 100644 --- a/libs/admin-console/src/common/collections/services/default-collection-admin.service.ts +++ b/libs/admin-console/src/common/collections/services/default-collection-admin.service.ts @@ -116,7 +116,7 @@ export class DefaultCollectionAdminService implements CollectionAdminService { const promises = collections.map(async (c) => { const view = new CollectionAdminView(); view.id = c.id; - view.name = await this.encryptService.decryptToUtf8(new EncString(c.name), orgKey); + view.name = await this.encryptService.decryptString(new EncString(c.name), orgKey); view.externalId = c.externalId; view.organizationId = c.organizationId; @@ -146,7 +146,7 @@ export class DefaultCollectionAdminService implements CollectionAdminService { } const collection = new CollectionRequest(); collection.externalId = model.externalId; - collection.name = (await this.encryptService.encrypt(model.name, key)).encryptedString; + collection.name = (await this.encryptService.encryptString(model.name, key)).encryptedString; collection.groups = model.groups.map( (group) => new SelectionReadOnlyRequest(group.id, group.readOnly, group.hidePasswords, group.manage), diff --git a/libs/admin-console/src/common/collections/services/default-collection.service.spec.ts b/libs/admin-console/src/common/collections/services/default-collection.service.spec.ts index 7fe81ade4d2..c5f57f38dd3 100644 --- a/libs/admin-console/src/common/collections/services/default-collection.service.spec.ts +++ b/libs/admin-console/src/common/collections/services/default-collection.service.spec.ts @@ -120,9 +120,12 @@ const mockStateProvider = () => { const mockCryptoService = () => { const keyService = mock(); const encryptService = mock(); - encryptService.decryptToUtf8 + encryptService.decryptString .calledWith(expect.any(EncString), expect.anything()) .mockResolvedValue("DECRYPTED_STRING"); + encryptService.decryptToUtf8 + .calledWith(expect.any(EncString), expect.anything(), expect.anything()) + .mockResolvedValue("DECRYPTED_STRING"); (window as any).bitwardenContainerService = new ContainerService(keyService, encryptService); diff --git a/libs/admin-console/src/common/collections/services/default-collection.service.ts b/libs/admin-console/src/common/collections/services/default-collection.service.ts index 1ae58d3eef3..a1dd0419e2c 100644 --- a/libs/admin-console/src/common/collections/services/default-collection.service.ts +++ b/libs/admin-console/src/common/collections/services/default-collection.service.ts @@ -113,7 +113,7 @@ export class DefaultCollectionService implements CollectionService { collection.organizationId = model.organizationId; collection.readOnly = model.readOnly; collection.externalId = model.externalId; - collection.name = await this.encryptService.encrypt(model.name, key); + collection.name = await this.encryptService.encryptString(model.name, key); return collection; } diff --git a/libs/admin-console/src/common/collections/services/default-vnext-collection.service.spec.ts b/libs/admin-console/src/common/collections/services/default-vnext-collection.service.spec.ts index 9700fcb695a..d4bc026b5bd 100644 --- a/libs/admin-console/src/common/collections/services/default-vnext-collection.service.spec.ts +++ b/libs/admin-console/src/common/collections/services/default-vnext-collection.service.spec.ts @@ -46,6 +46,11 @@ describe("DefaultvNextCollectionService", () => { keyService.orgKeys$.mockReturnValue(cryptoKeys); // Set up mock decryption + encryptService.decryptString + .calledWith(expect.any(EncString), expect.any(SymmetricCryptoKey)) + .mockImplementation((encString, key) => + Promise.resolve(encString.data.replace("ENC_", "DEC_")), + ); encryptService.decryptToUtf8 .calledWith(expect.any(EncString), expect.any(SymmetricCryptoKey), expect.any(String)) .mockImplementation((encString, key) => @@ -103,6 +108,7 @@ describe("DefaultvNextCollectionService", () => { ]); // Assert that the correct org keys were used for each encrypted string + // This should be replaced with decryptString when the platform PR (https://github.com/bitwarden/clients/pull/14544) is merged expect(encryptService.decryptToUtf8).toHaveBeenCalledWith( expect.objectContaining(new EncString(collection1.name)), orgKey1, diff --git a/libs/admin-console/src/common/collections/services/default-vnext-collection.service.ts b/libs/admin-console/src/common/collections/services/default-vnext-collection.service.ts index 0ef8ae99ab3..4dcda795afe 100644 --- a/libs/admin-console/src/common/collections/services/default-vnext-collection.service.ts +++ b/libs/admin-console/src/common/collections/services/default-vnext-collection.service.ts @@ -113,7 +113,7 @@ export class DefaultvNextCollectionService implements vNextCollectionService { collection.organizationId = model.organizationId; collection.readOnly = model.readOnly; collection.externalId = model.externalId; - collection.name = await this.encryptService.encrypt(model.name, key); + collection.name = await this.encryptService.encryptString(model.name, key); return collection; } diff --git a/libs/angular/src/billing/components/add-account-credit-dialog/add-account-credit-dialog.component.ts b/libs/angular/src/billing/components/add-account-credit-dialog/add-account-credit-dialog.component.ts index 7c068c51d86..871895c2ede 100644 --- a/libs/angular/src/billing/components/add-account-credit-dialog/add-account-credit-dialog.component.ts +++ b/libs/angular/src/billing/components/add-account-credit-dialog/add-account-credit-dialog.component.ts @@ -22,6 +22,8 @@ export type AddAccountCreditDialogParams = { providerId?: string; }; +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum AddAccountCreditDialogResultType { Closed = "closed", Submitted = "submitted", diff --git a/libs/angular/src/platform/view-cache/index.ts b/libs/angular/src/platform/view-cache/index.ts new file mode 100644 index 00000000000..79deef6aa5b --- /dev/null +++ b/libs/angular/src/platform/view-cache/index.ts @@ -0,0 +1 @@ +export { ViewCacheService, FormCacheOptions, SignalCacheOptions } from "./view-cache.service"; diff --git a/libs/angular/src/platform/view-cache/internal.ts b/libs/angular/src/platform/view-cache/internal.ts new file mode 100644 index 00000000000..6e0992eecbf --- /dev/null +++ b/libs/angular/src/platform/view-cache/internal.ts @@ -0,0 +1 @@ +export { NoopViewCacheService } from "./noop-view-cache.service"; diff --git a/libs/angular/src/platform/services/noop-view-cache.service.ts b/libs/angular/src/platform/view-cache/noop-view-cache.service.ts similarity index 87% rename from libs/angular/src/platform/services/noop-view-cache.service.ts rename to libs/angular/src/platform/view-cache/noop-view-cache.service.ts index 9953e80b3b0..f83a0fc0b04 100644 --- a/libs/angular/src/platform/services/noop-view-cache.service.ts +++ b/libs/angular/src/platform/view-cache/noop-view-cache.service.ts @@ -1,11 +1,7 @@ import { Injectable, signal, WritableSignal } from "@angular/core"; import type { FormGroup } from "@angular/forms"; -import { - FormCacheOptions, - SignalCacheOptions, - ViewCacheService, -} from "../abstractions/view-cache.service"; +import { FormCacheOptions, SignalCacheOptions, ViewCacheService } from "./view-cache.service"; /** * The functionality of the {@link ViewCacheService} is only needed in the browser extension popup, diff --git a/libs/angular/src/platform/view-cache/view-cache.md b/libs/angular/src/platform/view-cache/view-cache.md new file mode 100644 index 00000000000..c1f80da5800 --- /dev/null +++ b/libs/angular/src/platform/view-cache/view-cache.md @@ -0,0 +1,130 @@ +# Extension Persistence + +By default, when the browser extension popup closes, the user's current view and any data entered +without saving is lost. This introduces friction in several workflows within our client, such as: + +- Performing actions that require email OTP entry, since the user must navigate from the popup to + get to their email inbox +- Entering information to create a new vault item from a browser tab +- And many more + +Previously, we have recommended that users "pop out" the extension into its own window to persist +the extension context, but this introduces additional user actions and may leave the extension open +(and unlocked) for longer than a user intends. + +In order to provide a better user experience, we have introduced two levels of persistence to the +Bitwarden extension client: + +- We persist the route history, allowing us to re-open the last route when the popup re-opens, and +- We offer a service for teams to use to persist component-specific form data or state to survive a + popup close/re-open cycle + +## Persistence lifetime + +Since we are persisting data, it is important that the lifetime of that data be well-understood and +well-constrained. The cache of route history and form data is cleared when any of the following +events occur: + +- The account is locked +- The account is logged out +- Account switching is used to switch the active account +- The extension popup has been closed for 2 minutes + +In addition, cached form data is cleared when a browser extension navigation event occurs (e.g. +switching between tabs in the extension). + +## Types of persistence + +### Route history persistence + +Route history is persisted on the extension automatically, with no specific implementation required +on any component. + +The persistence layer ensures that the popup will open at the same route as was active when it +closed, provided that none of the lifetime expiration events have occurred. + +:::tip Excluding a route + +If a particular route should be excluded from the history and not persisted, add +`doNotSaveUrl: true` to the `data` property on the route. + +::: + +### View data persistence + +Route persistence ensures that the user will land back on the route that they were on when the popup +closed, but it does not persist any state or form data that the user may have modified. In order to +persist that data, the component is responsible for registering that data with the +[`ViewCacheService`](./view-cache.service.ts). +This is done prescriptively to ensure that only necessary data is cached and that it is done with +intention by the component. + +The `ViewCacheService` provides an interface for caching both individual state and `FormGroup`s. + +#### Caching individual data elements + +For individual pieces of state, use the `signal()` method on the `ViewCacheService` to create a +writeable [signal](https://angular.dev/guide/signals) wrapper around the desired state. + +```typescript +const mySignal = this.viewCacheService.signal({ + key: "my-state-key" + initialValue: null +}); +``` + +If a cached value exists, the returned signal will contain the cached data. + +Setting the value should be done through the signal's `set()` method: + +```typescript +const mySignal = this.viewCacheService.signal({ + key: "my-state-key" + initialValue: null +}); +mySignal.set("value") +``` + +:::note Equality comparison + +By default, signals use `Object.is` to determine equality, and `set()` will only trigger updates if +the updated value is not equal to the current signal state. See documentation +[here](https://angular.dev/guide/signals#signal-equality-functions). + +::: + +Putting this together, the most common implementation pattern would be: + +1. **Register the signal** using `ViewCacheService.signal()` on initialization of the component or + service responsible for the state being persisted. +2. **Restore state from the signal:** If cached data exists, the signal will contain that data. The + component or service should use this data to re-create the state from prior to the popup closing. +3. **Set new state** in the cache when it changes. Ensure that any updates to the data are persisted + to the cache with `set()`, so that the cache reflects the latest state. + +#### Caching form data + +For persisting form data, the `ViewCacheService` supplies a `formGroup()` method, which manages the +persistence of any entered form data to the cache and the initialization of the form from the cached +data. You can supply the `FormGroup` in the `control` parameter of the method, and the +`ViewCacheService` will: + +- Initialize the form the a cached value, if it exists +- Save form value to cache when it changes +- Mark the form dirty if the restored value is not `undefined`. + +```typescript +this.loginDetailsForm = this.viewCacheService.formGroup({ + key: "my-form", + control: this.formBuilder.group({ + username: [""], + email: [""], + }), +}); +``` + +## What about other clients? + +The `ViewCacheService` is designed to be injected into shared, client-agnostic components. A +`NoopViewCacheService` is provided and injected for non-extension clients, preserving a single +interface for your components. diff --git a/libs/angular/src/platform/abstractions/view-cache.service.ts b/libs/angular/src/platform/view-cache/view-cache.service.ts similarity index 98% rename from libs/angular/src/platform/abstractions/view-cache.service.ts rename to libs/angular/src/platform/view-cache/view-cache.service.ts index c5ae6c77d1f..498a29aa242 100644 --- a/libs/angular/src/platform/abstractions/view-cache.service.ts +++ b/libs/angular/src/platform/view-cache/view-cache.service.ts @@ -42,6 +42,8 @@ export type FormCacheOptions = BaseCacheOptions< /** * Cache for temporary component state * + * [Read more](./view-cache.md) + * * #### Implementations * - browser extension popup: used to persist UI between popup open and close * - all other clients: noop diff --git a/libs/angular/src/services/jslib-services.module.ts b/libs/angular/src/services/jslib-services.module.ts index f083e0e3446..973a5fb5aa4 100644 --- a/libs/angular/src/services/jslib-services.module.ts +++ b/libs/angular/src/services/jslib-services.module.ts @@ -327,13 +327,14 @@ import { import { DeviceTrustToastService as DeviceTrustToastServiceAbstraction } from "../auth/services/device-trust-toast.service.abstraction"; import { DeviceTrustToastService } from "../auth/services/device-trust-toast.service.implementation"; import { FormValidationErrorsService as FormValidationErrorsServiceAbstraction } from "../platform/abstractions/form-validation-errors.service"; -import { ViewCacheService } from "../platform/abstractions/view-cache.service"; import { FormValidationErrorsService } from "../platform/services/form-validation-errors.service"; import { LoggingErrorHandler } from "../platform/services/logging-error-handler"; -import { NoopViewCacheService } from "../platform/services/noop-view-cache.service"; import { AngularThemingService } from "../platform/services/theming/angular-theming.service"; import { AbstractThemingService } from "../platform/services/theming/theming.service.abstraction"; import { safeProvider, SafeProvider } from "../platform/utils/safe-provider"; +import { ViewCacheService } from "../platform/view-cache"; +// eslint-disable-next-line no-restricted-imports -- Needed for DI +import { NoopViewCacheService } from "../platform/view-cache/internal"; import { CLIENT_TYPE, @@ -1080,7 +1081,7 @@ const safeProviders: SafeProvider[] = [ safeProvider({ provide: OrganizationSponsorshipApiServiceAbstraction, useClass: OrganizationSponsorshipApiService, - deps: [ApiServiceAbstraction], + deps: [ApiServiceAbstraction, PlatformUtilsServiceAbstraction], }), safeProvider({ provide: OrganizationBillingApiServiceAbstraction, diff --git a/libs/angular/src/tools/send/add-edit.component.ts b/libs/angular/src/tools/send/add-edit.component.ts index 7e6180e5849..0289664c365 100644 --- a/libs/angular/src/tools/send/add-edit.component.ts +++ b/libs/angular/src/tools/send/add-edit.component.ts @@ -36,6 +36,8 @@ import { SendService } from "@bitwarden/common/tools/send/services/send.service. import { DialogService, ToastService } from "@bitwarden/components"; // Value = hours +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums enum DatePreset { OneHour = 1, OneDay = 24, diff --git a/libs/auth/src/angular/input-password/input-password.component.ts b/libs/auth/src/angular/input-password/input-password.component.ts index 9d4c439cf2b..5da4b5c292e 100644 --- a/libs/auth/src/angular/input-password/input-password.component.ts +++ b/libs/auth/src/angular/input-password/input-password.component.ts @@ -53,6 +53,8 @@ import { PasswordInputResult } from "./password-input-result"; * Determines which form elements will be displayed in the UI * and which cryptographic keys will be created and emitted. */ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum InputPasswordFlow { /** * Form elements displayed: diff --git a/libs/auth/src/angular/login-decryption-options/login-decryption-options.component.ts b/libs/auth/src/angular/login-decryption-options/login-decryption-options.component.ts index 945e6bbaaf5..3ea9416b7e2 100644 --- a/libs/auth/src/angular/login-decryption-options/login-decryption-options.component.ts +++ b/libs/auth/src/angular/login-decryption-options/login-decryption-options.component.ts @@ -41,6 +41,8 @@ import { AnonLayoutWrapperDataService } from "../anon-layout/anon-layout-wrapper import { LoginDecryptionOptionsService } from "./login-decryption-options.service"; +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums enum State { NewUser, ExistingUserUntrustedDevice, diff --git a/libs/auth/src/angular/login-via-auth-request/login-via-auth-request.component.ts b/libs/auth/src/angular/login-via-auth-request/login-via-auth-request.component.ts index ab5b0c09b32..d74deb443f5 100644 --- a/libs/auth/src/angular/login-via-auth-request/login-via-auth-request.component.ts +++ b/libs/auth/src/angular/login-via-auth-request/login-via-auth-request.component.ts @@ -23,12 +23,10 @@ import { AuthRequest } from "@bitwarden/common/auth/models/request/auth.request" import { AuthRequestResponse } from "@bitwarden/common/auth/models/response/auth-request.response"; import { LoginViaAuthRequestView } from "@bitwarden/common/auth/models/view/login-via-auth-request.view"; import { ClientType, HttpStatusCode } from "@bitwarden/common/enums"; -import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; import { CryptoFunctionService } from "@bitwarden/common/key-management/crypto/abstractions/crypto-function.service"; import { DeviceTrustServiceAbstraction } from "@bitwarden/common/key-management/device-trust/abstractions/device-trust.service.abstraction"; import { ErrorResponse } from "@bitwarden/common/models/response/error.response"; import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service"; -import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; @@ -42,6 +40,8 @@ import { PasswordGenerationServiceAbstraction } from "@bitwarden/generator-legac import { AuthRequestApiService } from "../../common/abstractions/auth-request-api.service"; import { LoginViaAuthRequestCacheService } from "../../common/services/auth-request/default-login-via-auth-request-cache.service"; +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums enum Flow { StandardAuthRequest, // when user clicks "Login with device" from /login or "Approve from your other device" from /login-initiated AdminAuthRequest, // when user clicks "Request admin approval" from /login-initiated @@ -101,7 +101,6 @@ export class LoginViaAuthRequestComponent implements OnInit, OnDestroy { private validationService: ValidationService, private loginSuccessHandlerService: LoginSuccessHandlerService, private loginViaAuthRequestCacheService: LoginViaAuthRequestCacheService, - private configService: ConfigService, ) { this.clientType = this.platformUtilsService.getClientType(); @@ -132,7 +131,6 @@ export class LoginViaAuthRequestComponent implements OnInit, OnDestroy { async ngOnInit(): Promise { // Get the authStatus early because we use it in both flows this.authStatus = await firstValueFrom(this.authService.activeAccountStatus$); - await this.loginViaAuthRequestCacheService.init(); const userHasAuthenticatedViaSSO = this.authStatus === AuthenticationStatus.Locked; @@ -410,24 +408,22 @@ export class LoginViaAuthRequestComponent implements OnInit, OnDestroy { const authRequestResponse: AuthRequestResponse = await this.authRequestApiService.postAuthRequest(authRequest); - if (await this.configService.getFeatureFlag(FeatureFlag.PM9112_DeviceApprovalPersistence)) { - if (!this.authRequestKeyPair.privateKey) { - this.logService.error("No private key when trying to cache the login view."); - return; - } - - if (!this.accessCode) { - this.logService.error("No access code when trying to cache the login view."); - return; - } - - this.loginViaAuthRequestCacheService.cacheLoginView( - authRequestResponse.id, - this.authRequestKeyPair.privateKey, - this.accessCode, - ); + if (!this.authRequestKeyPair.privateKey) { + this.logService.error("No private key when trying to cache the login view."); + return; } + if (!this.accessCode) { + this.logService.error("No access code when trying to cache the login view."); + return; + } + + this.loginViaAuthRequestCacheService.cacheLoginView( + authRequestResponse.id, + this.authRequestKeyPair.privateKey, + this.accessCode, + ); + if (authRequestResponse.id) { await this.anonymousHubService.createHubConnection(authRequestResponse.id); } diff --git a/libs/auth/src/angular/login/login.component.ts b/libs/auth/src/angular/login/login.component.ts index cd226cddcec..d5180f56785 100644 --- a/libs/auth/src/angular/login/login.component.ts +++ b/libs/auth/src/angular/login/login.component.ts @@ -46,6 +46,8 @@ import { LoginComponentService, PasswordPolicies } from "./login-component.servi const BroadcasterSubscriptionId = "LoginComponent"; +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum LoginUiState { EMAIL_ENTRY = "EmailEntry", MASTER_PASSWORD_ENTRY = "MasterPasswordEntry", diff --git a/libs/auth/src/angular/registration/registration-start/registration-start.component.ts b/libs/auth/src/angular/registration/registration-start/registration-start.component.ts index e365ff09aa2..44d1d720a8d 100644 --- a/libs/auth/src/angular/registration/registration-start/registration-start.component.ts +++ b/libs/auth/src/angular/registration/registration-start/registration-start.component.ts @@ -26,6 +26,8 @@ import { RegistrationUserAddIcon } from "../../icons"; import { RegistrationCheckEmailIcon } from "../../icons/registration-check-email.icon"; import { RegistrationEnvSelectorComponent } from "../registration-env-selector/registration-env-selector.component"; +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum RegistrationStartState { USER_DATA_ENTRY = "UserDataEntry", CHECK_EMAIL = "CheckEmail", diff --git a/libs/auth/src/angular/sso/sso.component.ts b/libs/auth/src/angular/sso/sso.component.ts index a91a8ed20e9..968a05bf850 100644 --- a/libs/auth/src/angular/sso/sso.component.ts +++ b/libs/auth/src/angular/sso/sso.component.ts @@ -155,7 +155,14 @@ export class SsoComponent implements OnInit { return; } - // Detect if we have landed here but only have an SSO identifier in the URL. + // Detect if we are on the first portion of the SSO flow + // and have been sent here from another client with the info in query params. + // If so, we want to initialize the SSO flow with those values. + if (this.hasParametersFromOtherClientRedirect(qParams)) { + this.initializeFromRedirectFromOtherClient(qParams); + } + + // Detect if we have landed here with an SSO identifier in the URL. // This is used by integrations that want to "short-circuit" the login to send users // directly to their IdP to simulate IdP-initiated SSO, so we submit automatically. if (qParams.identifier != null) { @@ -165,13 +172,6 @@ export class SsoComponent implements OnInit { return; } - // Detect if we are on the first portion of the SSO flow - // and have been sent here from another client with the info in query params. - // If so, we want to initialize the SSO flow with those values. - if (this.hasParametersFromOtherClientRedirect(qParams)) { - this.initializeFromRedirectFromOtherClient(qParams); - } - // Try to determine the identifier using claimed domain or local state // persisted from the user's last login attempt. await this.initializeIdentifierFromEmailOrStorage(); diff --git a/libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-email/two-factor-auth-component-email-cache.service.spec.ts b/libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-email/two-factor-auth-component-email-cache.service.spec.ts index f3b904a4ea6..d2d86710b72 100644 --- a/libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-email/two-factor-auth-component-email-cache.service.spec.ts +++ b/libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-email/two-factor-auth-component-email-cache.service.spec.ts @@ -2,7 +2,7 @@ import { TestBed } from "@angular/core/testing"; import { mock, MockProxy } from "jest-mock-extended"; import { BehaviorSubject } from "rxjs"; -import { ViewCacheService } from "@bitwarden/angular/platform/abstractions/view-cache.service"; +import { ViewCacheService } from "@bitwarden/angular/platform/view-cache"; import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; diff --git a/libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-email/two-factor-auth-email-component-cache.service.spec.ts b/libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-email/two-factor-auth-email-component-cache.service.spec.ts index 1613c0e4af8..36d99ee56ac 100644 --- a/libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-email/two-factor-auth-email-component-cache.service.spec.ts +++ b/libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-email/two-factor-auth-email-component-cache.service.spec.ts @@ -2,7 +2,7 @@ import { TestBed } from "@angular/core/testing"; import { mock, MockProxy } from "jest-mock-extended"; import { BehaviorSubject } from "rxjs"; -import { ViewCacheService } from "@bitwarden/angular/platform/abstractions/view-cache.service"; +import { ViewCacheService } from "@bitwarden/angular/platform/view-cache"; import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; diff --git a/libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-email/two-factor-auth-email-component-cache.service.ts b/libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-email/two-factor-auth-email-component-cache.service.ts index e32b6cd1385..d274b8003d7 100644 --- a/libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-email/two-factor-auth-email-component-cache.service.ts +++ b/libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-email/two-factor-auth-email-component-cache.service.ts @@ -1,7 +1,7 @@ import { inject, Injectable, WritableSignal } from "@angular/core"; import { Jsonify } from "type-fest"; -import { ViewCacheService } from "@bitwarden/angular/platform/abstractions/view-cache.service"; +import { ViewCacheService } from "@bitwarden/angular/platform/view-cache"; import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; diff --git a/libs/auth/src/angular/two-factor-auth/two-factor-auth-component-cache.service.spec.ts b/libs/auth/src/angular/two-factor-auth/two-factor-auth-component-cache.service.spec.ts index 0993954fde1..5b5d486556b 100644 --- a/libs/auth/src/angular/two-factor-auth/two-factor-auth-component-cache.service.spec.ts +++ b/libs/auth/src/angular/two-factor-auth/two-factor-auth-component-cache.service.spec.ts @@ -2,7 +2,7 @@ import { TestBed } from "@angular/core/testing"; import { mock, MockProxy } from "jest-mock-extended"; import { BehaviorSubject } from "rxjs"; -import { ViewCacheService } from "@bitwarden/angular/platform/abstractions/view-cache.service"; +import { ViewCacheService } from "@bitwarden/angular/platform/view-cache"; import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type"; import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; diff --git a/libs/auth/src/angular/two-factor-auth/two-factor-auth-component-cache.service.ts b/libs/auth/src/angular/two-factor-auth/two-factor-auth-component-cache.service.ts index 61b44aa98dd..2d9fcaa5633 100644 --- a/libs/auth/src/angular/two-factor-auth/two-factor-auth-component-cache.service.ts +++ b/libs/auth/src/angular/two-factor-auth/two-factor-auth-component-cache.service.ts @@ -1,7 +1,7 @@ import { inject, Injectable, WritableSignal } from "@angular/core"; import { Jsonify } from "type-fest"; -import { ViewCacheService } from "@bitwarden/angular/platform/abstractions/view-cache.service"; +import { ViewCacheService } from "@bitwarden/angular/platform/view-cache"; import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type"; import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; diff --git a/libs/auth/src/angular/two-factor-auth/two-factor-auth-component.service.ts b/libs/auth/src/angular/two-factor-auth/two-factor-auth-component.service.ts index 2bb354a8cc3..c99722fb8e4 100644 --- a/libs/auth/src/angular/two-factor-auth/two-factor-auth-component.service.ts +++ b/libs/auth/src/angular/two-factor-auth/two-factor-auth-component.service.ts @@ -1,10 +1,14 @@ import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type"; +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum LegacyKeyMigrationAction { PREVENT_LOGIN_AND_SHOW_REQUIRE_MIGRATION_WARNING, NAVIGATE_TO_MIGRATION_COMPONENT, } +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum DuoLaunchAction { DIRECT_LAUNCH, SINGLE_ACTION_POPOUT, diff --git a/libs/auth/src/angular/user-verification/active-client-verification-option.enum.ts b/libs/auth/src/angular/user-verification/active-client-verification-option.enum.ts index bceccc7f965..ef2bd1855c6 100644 --- a/libs/auth/src/angular/user-verification/active-client-verification-option.enum.ts +++ b/libs/auth/src/angular/user-verification/active-client-verification-option.enum.ts @@ -1,3 +1,5 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum ActiveClientVerificationOption { MasterPassword = "masterPassword", Pin = "pin", diff --git a/libs/auth/src/angular/validators/compare-inputs.validator.ts b/libs/auth/src/angular/validators/compare-inputs.validator.ts index 24568ade0e3..79d547859a4 100644 --- a/libs/auth/src/angular/validators/compare-inputs.validator.ts +++ b/libs/auth/src/angular/validators/compare-inputs.validator.ts @@ -1,5 +1,7 @@ import { AbstractControl, FormGroup, ValidationErrors, ValidatorFn } from "@angular/forms"; +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum ValidationGoal { InputsShouldMatch, InputsShouldNotMatch, diff --git a/libs/auth/src/common/services/auth-request/default-login-via-auth-request-cache.service.spec.ts b/libs/auth/src/common/services/auth-request/default-login-via-auth-request-cache.service.spec.ts index 89b78500f1f..67ac605e611 100644 --- a/libs/auth/src/common/services/auth-request/default-login-via-auth-request-cache.service.spec.ts +++ b/libs/auth/src/common/services/auth-request/default-login-via-auth-request-cache.service.spec.ts @@ -1,9 +1,8 @@ import { signal } from "@angular/core"; import { TestBed } from "@angular/core/testing"; -import { ViewCacheService } from "@bitwarden/angular/platform/abstractions/view-cache.service"; +import { ViewCacheService } from "@bitwarden/angular/platform/view-cache"; import { LoginViaAuthRequestView } from "@bitwarden/common/auth/models/view/login-via-auth-request.view"; -import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { Utils } from "@bitwarden/common/platform/misc/utils"; import { LoginViaAuthRequestCacheService } from "./default-login-via-auth-request-cache.service"; @@ -14,74 +13,40 @@ describe("LoginViaAuthRequestCache", () => { const cacheSignal = signal(null); const getCacheSignal = jest.fn().mockReturnValue(cacheSignal); - const getFeatureFlag = jest.fn().mockResolvedValue(false); const cacheSetMock = jest.spyOn(cacheSignal, "set"); beforeEach(() => { getCacheSignal.mockClear(); - getFeatureFlag.mockClear(); cacheSetMock.mockClear(); testBed = TestBed.configureTestingModule({ providers: [ { provide: ViewCacheService, useValue: { signal: getCacheSignal } }, - { provide: ConfigService, useValue: { getFeatureFlag } }, LoginViaAuthRequestCacheService, ], }); }); - describe("feature enabled", () => { - beforeEach(() => { - getFeatureFlag.mockResolvedValue(true); - }); + it("`getCachedLoginViaAuthRequestView` returns the cached data", async () => { + cacheSignal.set({ ...buildMockState() }); + service = testBed.inject(LoginViaAuthRequestCacheService); - it("`getCachedLoginViaAuthRequestView` returns the cached data", async () => { - cacheSignal.set({ ...buildMockState() }); - service = testBed.inject(LoginViaAuthRequestCacheService); - await service.init(); - - expect(service.getCachedLoginViaAuthRequestView()).toEqual({ - ...buildMockState(), - }); - }); - - it("updates the signal value", async () => { - service = testBed.inject(LoginViaAuthRequestCacheService); - await service.init(); - - const parameters = buildAuthenticMockAuthView(); - - service.cacheLoginView(parameters.id, parameters.privateKey, parameters.accessCode); - - expect(cacheSignal.set).toHaveBeenCalledWith({ - id: parameters.id, - privateKey: Utils.fromBufferToB64(parameters.privateKey), - accessCode: parameters.accessCode, - }); + expect(service.getCachedLoginViaAuthRequestView()).toEqual({ + ...buildMockState(), }); }); - describe("feature disabled", () => { - beforeEach(async () => { - cacheSignal.set({ ...buildMockState() } as LoginViaAuthRequestView); - getFeatureFlag.mockResolvedValue(false); - cacheSetMock.mockClear(); + it("updates the signal value", async () => { + service = testBed.inject(LoginViaAuthRequestCacheService); - service = testBed.inject(LoginViaAuthRequestCacheService); - await service.init(); - }); + const parameters = buildAuthenticMockAuthView(); - it("`getCachedCipherView` returns null", () => { - expect(service.getCachedLoginViaAuthRequestView()).toBeNull(); - }); + service.cacheLoginView(parameters.id, parameters.privateKey, parameters.accessCode); - it("does not update the signal value", () => { - const params = buildAuthenticMockAuthView(); - - service.cacheLoginView(params.id, params.privateKey, params.accessCode); - - expect(cacheSignal.set).not.toHaveBeenCalled(); + expect(cacheSignal.set).toHaveBeenCalledWith({ + id: parameters.id, + privateKey: Utils.fromBufferToB64(parameters.privateKey), + accessCode: parameters.accessCode, }); }); diff --git a/libs/auth/src/common/services/auth-request/default-login-via-auth-request-cache.service.ts b/libs/auth/src/common/services/auth-request/default-login-via-auth-request-cache.service.ts index 493fea5c14b..80dbafd3159 100644 --- a/libs/auth/src/common/services/auth-request/default-login-via-auth-request-cache.service.ts +++ b/libs/auth/src/common/services/auth-request/default-login-via-auth-request-cache.service.ts @@ -1,9 +1,7 @@ import { inject, Injectable, WritableSignal } from "@angular/core"; -import { ViewCacheService } from "@bitwarden/angular/platform/abstractions/view-cache.service"; +import { ViewCacheService } from "@bitwarden/angular/platform/view-cache"; import { LoginViaAuthRequestView } from "@bitwarden/common/auth/models/view/login-via-auth-request.view"; -import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; -import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { Utils } from "@bitwarden/common/platform/misc/utils"; const LOGIN_VIA_AUTH_CACHE_KEY = "login-via-auth-request-form-cache"; @@ -17,10 +15,6 @@ const LOGIN_VIA_AUTH_CACHE_KEY = "login-via-auth-request-form-cache"; @Injectable() export class LoginViaAuthRequestCacheService { private viewCacheService: ViewCacheService = inject(ViewCacheService); - private configService: ConfigService = inject(ConfigService); - - /** True when the `PM9112_DeviceApproval` flag is enabled */ - private featureEnabled: boolean = false; private defaultLoginViaAuthRequestCache: WritableSignal = this.viewCacheService.signal({ @@ -31,23 +25,10 @@ export class LoginViaAuthRequestCacheService { constructor() {} - /** - * Must be called once before interacting with the cached data, otherwise methods will be noop. - */ - async init() { - this.featureEnabled = await this.configService.getFeatureFlag( - FeatureFlag.PM9112_DeviceApprovalPersistence, - ); - } - /** * Update the cache with the new LoginView. */ cacheLoginView(id: string, privateKey: Uint8Array, accessCode: string): void { - if (!this.featureEnabled) { - return; - } - // When the keys get stored they should be converted to a B64 string to ensure // data can be properly formed when json-ified. If not done, they are not stored properly and // will not be parsable by the cryptography library after coming out of storage. @@ -59,10 +40,6 @@ export class LoginViaAuthRequestCacheService { } clearCacheLoginView(): void { - if (!this.featureEnabled) { - return; - } - this.defaultLoginViaAuthRequestCache.set(null); } @@ -70,10 +47,6 @@ export class LoginViaAuthRequestCacheService { * Returns the cached LoginViaAuthRequestView when available. */ getCachedLoginViaAuthRequestView(): LoginViaAuthRequestView | null { - if (!this.featureEnabled) { - return null; - } - return this.defaultLoginViaAuthRequestCache(); } } diff --git a/libs/auth/src/common/services/sso-redirect/sso-url.service.spec.ts b/libs/auth/src/common/services/sso-redirect/sso-url.service.spec.ts index 074c3a1e0b1..632a2812cfe 100644 --- a/libs/auth/src/common/services/sso-redirect/sso-url.service.spec.ts +++ b/libs/auth/src/common/services/sso-redirect/sso-url.service.spec.ts @@ -92,4 +92,27 @@ describe("SsoUrlService", () => { ); expect(result).toBe(expectedUrl); }); + + it("should build CLI SSO URL with Org SSO Identifier correctly", () => { + const baseUrl = "https://web-vault.bitwarden.com"; + const clientType = ClientType.Cli; + const redirectUri = "https://localhost:1000"; + const state = "abc123"; + const codeChallenge = "xyz789"; + const email = "test@bitwarden.com"; + const orgSsoIdentifier = "test-org"; + + const expectedUrl = `${baseUrl}/#/sso?clientId=cli&redirectUri=${encodeURIComponent(redirectUri)}&state=${state}&codeChallenge=${codeChallenge}&email=${encodeURIComponent(email)}&identifier=${encodeURIComponent(orgSsoIdentifier)}`; + + const result = service.buildSsoUrl( + baseUrl, + clientType, + redirectUri, + state, + codeChallenge, + email, + orgSsoIdentifier, + ); + expect(result).toBe(expectedUrl); + }); }); diff --git a/libs/auth/src/common/services/sso-redirect/sso-url.service.ts b/libs/auth/src/common/services/sso-redirect/sso-url.service.ts index 667a27ad598..b2d6231db7c 100644 --- a/libs/auth/src/common/services/sso-redirect/sso-url.service.ts +++ b/libs/auth/src/common/services/sso-redirect/sso-url.service.ts @@ -11,6 +11,7 @@ export class SsoUrlService { * @param state A state value that will be peristed through the SSO flow * @param codeChallenge A challenge value that will be used to verify the SSO code after authentication * @param email The optional email adddress of the user initiating SSO, which will be used to look up the org SSO identifier + * @param orgSsoIdentifier The optional SSO identifier of the org that is initiating SSO * @returns The URL for redirecting users to the web app SSO component */ buildSsoUrl( @@ -20,6 +21,7 @@ export class SsoUrlService { state: string, codeChallenge: string, email?: string, + orgSsoIdentifier?: string, ): string { let url = webAppUrl + @@ -36,6 +38,10 @@ export class SsoUrlService { url += "&email=" + encodeURIComponent(email); } + if (orgSsoIdentifier) { + url += "&identifier=" + encodeURIComponent(orgSsoIdentifier); + } + return url; } } diff --git a/libs/common/src/abstractions/api.service.ts b/libs/common/src/abstractions/api.service.ts index 1e13a3064f4..e4453359015 100644 --- a/libs/common/src/abstractions/api.service.ts +++ b/libs/common/src/abstractions/api.service.ts @@ -475,7 +475,6 @@ export abstract class ApiService { getSponsorshipSyncStatus: ( sponsoredOrgId: string, ) => Promise; - deleteRevokeSponsorship: (sponsoringOrganizationId: string) => Promise; deleteRemoveSponsorship: (sponsoringOrgId: string) => Promise; postPreValidateSponsorshipToken: ( sponsorshipToken: string, diff --git a/libs/common/src/admin-console/enums/organization-api-key-type.enum.ts b/libs/common/src/admin-console/enums/organization-api-key-type.enum.ts index 44ba7f8391d..bb98ea8718b 100644 --- a/libs/common/src/admin-console/enums/organization-api-key-type.enum.ts +++ b/libs/common/src/admin-console/enums/organization-api-key-type.enum.ts @@ -1,3 +1,5 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum OrganizationApiKeyType { Default = 0, BillingSync = 1, diff --git a/libs/common/src/admin-console/enums/organization-connection-type.enum.ts b/libs/common/src/admin-console/enums/organization-connection-type.enum.ts index d2f9700a6a0..3cd11a29496 100644 --- a/libs/common/src/admin-console/enums/organization-connection-type.enum.ts +++ b/libs/common/src/admin-console/enums/organization-connection-type.enum.ts @@ -1,3 +1,5 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum OrganizationConnectionType { CloudBillingSync = 1, Scim = 2, diff --git a/libs/common/src/admin-console/enums/organization-user-status-type.enum.ts b/libs/common/src/admin-console/enums/organization-user-status-type.enum.ts index f5fa0e25c91..df9ccc8b430 100644 --- a/libs/common/src/admin-console/enums/organization-user-status-type.enum.ts +++ b/libs/common/src/admin-console/enums/organization-user-status-type.enum.ts @@ -1,3 +1,5 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum OrganizationUserStatusType { Invited = 0, Accepted = 1, diff --git a/libs/common/src/admin-console/enums/organization-user-type.enum.ts b/libs/common/src/admin-console/enums/organization-user-type.enum.ts index da50bfbdc20..098374becb4 100644 --- a/libs/common/src/admin-console/enums/organization-user-type.enum.ts +++ b/libs/common/src/admin-console/enums/organization-user-type.enum.ts @@ -1,3 +1,5 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum OrganizationUserType { Owner = 0, Admin = 1, diff --git a/libs/common/src/admin-console/enums/policy-type.enum.ts b/libs/common/src/admin-console/enums/policy-type.enum.ts index 336b834ca56..42ab798eabf 100644 --- a/libs/common/src/admin-console/enums/policy-type.enum.ts +++ b/libs/common/src/admin-console/enums/policy-type.enum.ts @@ -1,3 +1,5 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum PolicyType { TwoFactorAuthentication = 0, // Requires users to have 2fa enabled MasterPassword = 1, // Sets minimum requirements for master password complexity diff --git a/libs/common/src/admin-console/enums/provider-status-type.enum.ts b/libs/common/src/admin-console/enums/provider-status-type.enum.ts index 8da60af0eb3..32b730510e0 100644 --- a/libs/common/src/admin-console/enums/provider-status-type.enum.ts +++ b/libs/common/src/admin-console/enums/provider-status-type.enum.ts @@ -1,3 +1,5 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum ProviderStatusType { Pending = 0, Created = 1, diff --git a/libs/common/src/admin-console/enums/provider-type.enum.ts b/libs/common/src/admin-console/enums/provider-type.enum.ts index eb48e362e7d..dbb60fb3638 100644 --- a/libs/common/src/admin-console/enums/provider-type.enum.ts +++ b/libs/common/src/admin-console/enums/provider-type.enum.ts @@ -1,3 +1,5 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum ProviderType { Msp = 0, Reseller = 1, diff --git a/libs/common/src/admin-console/enums/provider-user-status-type.enum.ts b/libs/common/src/admin-console/enums/provider-user-status-type.enum.ts index 38d6c2e4961..253128aa25f 100644 --- a/libs/common/src/admin-console/enums/provider-user-status-type.enum.ts +++ b/libs/common/src/admin-console/enums/provider-user-status-type.enum.ts @@ -1,3 +1,5 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum ProviderUserStatusType { Invited = 0, Accepted = 1, diff --git a/libs/common/src/admin-console/enums/provider-user-type.enum.ts b/libs/common/src/admin-console/enums/provider-user-type.enum.ts index 00490adcfca..d20755c3196 100644 --- a/libs/common/src/admin-console/enums/provider-user-type.enum.ts +++ b/libs/common/src/admin-console/enums/provider-user-type.enum.ts @@ -1,3 +1,5 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum ProviderUserType { ProviderAdmin = 0, ServiceUser = 1, diff --git a/libs/common/src/admin-console/enums/scim-provider-type.enum.ts b/libs/common/src/admin-console/enums/scim-provider-type.enum.ts index 43c518fdfbf..cd33a1cf891 100644 --- a/libs/common/src/admin-console/enums/scim-provider-type.enum.ts +++ b/libs/common/src/admin-console/enums/scim-provider-type.enum.ts @@ -1,3 +1,5 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum ScimProviderType { Default = 0, AzureAd = 1, diff --git a/libs/common/src/admin-console/models/data/organization.data.spec.ts b/libs/common/src/admin-console/models/data/organization.data.spec.ts index fae24133502..7d66e7bc0d5 100644 --- a/libs/common/src/admin-console/models/data/organization.data.spec.ts +++ b/libs/common/src/admin-console/models/data/organization.data.spec.ts @@ -59,6 +59,7 @@ describe("ORGANIZATIONS state", () => { userIsManagedByOrganization: false, useRiskInsights: false, useAdminSponsoredFamilies: false, + isAdminInitiated: false, }, }; const result = sut.deserializer(JSON.parse(JSON.stringify(expectedResult))); diff --git a/libs/common/src/admin-console/models/data/organization.data.ts b/libs/common/src/admin-console/models/data/organization.data.ts index 799d062aefa..e0783957117 100644 --- a/libs/common/src/admin-console/models/data/organization.data.ts +++ b/libs/common/src/admin-console/models/data/organization.data.ts @@ -61,6 +61,7 @@ export class OrganizationData { userIsManagedByOrganization: boolean; useRiskInsights: boolean; useAdminSponsoredFamilies: boolean; + isAdminInitiated: boolean; constructor( response?: ProfileOrganizationResponse, @@ -124,6 +125,7 @@ export class OrganizationData { this.userIsManagedByOrganization = response.userIsManagedByOrganization; this.useRiskInsights = response.useRiskInsights; this.useAdminSponsoredFamilies = response.useAdminSponsoredFamilies; + this.isAdminInitiated = response.isAdminInitiated; this.isMember = options.isMember; this.isProviderUser = options.isProviderUser; diff --git a/libs/common/src/admin-console/models/domain/encrypted-organization-key.ts b/libs/common/src/admin-console/models/domain/encrypted-organization-key.ts index 984d80ba519..297bcf08d8c 100644 --- a/libs/common/src/admin-console/models/domain/encrypted-organization-key.ts +++ b/libs/common/src/admin-console/models/domain/encrypted-organization-key.ts @@ -56,14 +56,14 @@ export class ProviderEncryptedOrganizationKey implements BaseEncryptedOrganizati ) {} async decrypt(encryptService: EncryptService, providerKeys: Record) { - const decValue = await encryptService.decryptToBytes( + const decValue = await encryptService.unwrapSymmetricKey( new EncString(this.key), providerKeys[this.providerId], ); if (decValue == null) { throw new Error("Failed to decrypt organization key"); } - return new SymmetricCryptoKey(decValue) as OrgKey; + return decValue as OrgKey; } get encryptedOrganizationKey() { diff --git a/libs/common/src/admin-console/models/domain/organization.ts b/libs/common/src/admin-console/models/domain/organization.ts index 2e51c54b0ad..1864d56649b 100644 --- a/libs/common/src/admin-console/models/domain/organization.ts +++ b/libs/common/src/admin-console/models/domain/organization.ts @@ -91,6 +91,7 @@ export class Organization { userIsManagedByOrganization: boolean; useRiskInsights: boolean; useAdminSponsoredFamilies: boolean; + isAdminInitiated: boolean; constructor(obj?: OrganizationData) { if (obj == null) { @@ -150,6 +151,7 @@ export class Organization { this.userIsManagedByOrganization = obj.userIsManagedByOrganization; this.useRiskInsights = obj.useRiskInsights; this.useAdminSponsoredFamilies = obj.useAdminSponsoredFamilies; + this.isAdminInitiated = obj.isAdminInitiated; } get canAccess() { diff --git a/libs/common/src/admin-console/models/request/organization-create.request.ts b/libs/common/src/admin-console/models/request/organization-create.request.ts index e8561307b20..d9c62f1e20a 100644 --- a/libs/common/src/admin-console/models/request/organization-create.request.ts +++ b/libs/common/src/admin-console/models/request/organization-create.request.ts @@ -6,4 +6,5 @@ import { OrganizationNoPaymentMethodCreateRequest } from "../../../billing/model export class OrganizationCreateRequest extends OrganizationNoPaymentMethodCreateRequest { paymentMethodType: PaymentMethodType; paymentToken: string; + skipTrial?: boolean; } diff --git a/libs/common/src/admin-console/models/response/profile-organization.response.ts b/libs/common/src/admin-console/models/response/profile-organization.response.ts index da97a1034b1..3a86c764eb8 100644 --- a/libs/common/src/admin-console/models/response/profile-organization.response.ts +++ b/libs/common/src/admin-console/models/response/profile-organization.response.ts @@ -56,6 +56,7 @@ export class ProfileOrganizationResponse extends BaseResponse { userIsManagedByOrganization: boolean; useRiskInsights: boolean; useAdminSponsoredFamilies: boolean; + isAdminInitiated: boolean; constructor(response: any) { super(response); @@ -123,5 +124,6 @@ export class ProfileOrganizationResponse extends BaseResponse { this.userIsManagedByOrganization = this.getResponseProperty("UserIsManagedByOrganization"); this.useRiskInsights = this.getResponseProperty("UseRiskInsights"); this.useAdminSponsoredFamilies = this.getResponseProperty("UseAdminSponsoredFamilies"); + this.isAdminInitiated = this.getResponseProperty("IsAdminInitiated"); } } diff --git a/libs/common/src/auth/enums/auth-request-type.ts b/libs/common/src/auth/enums/auth-request-type.ts index 31db2467861..d23fec03205 100644 --- a/libs/common/src/auth/enums/auth-request-type.ts +++ b/libs/common/src/auth/enums/auth-request-type.ts @@ -1,3 +1,5 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum AuthRequestType { AuthenticateAndUnlock = 0, Unlock = 1, diff --git a/libs/common/src/auth/enums/authentication-status.ts b/libs/common/src/auth/enums/authentication-status.ts index 17b4f1f21e8..6a6f9467ae7 100644 --- a/libs/common/src/auth/enums/authentication-status.ts +++ b/libs/common/src/auth/enums/authentication-status.ts @@ -1,3 +1,5 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum AuthenticationStatus { LoggedOut = 0, Locked = 1, diff --git a/libs/common/src/auth/enums/authentication-type.ts b/libs/common/src/auth/enums/authentication-type.ts index 35b50e6400a..13a3d70ddda 100644 --- a/libs/common/src/auth/enums/authentication-type.ts +++ b/libs/common/src/auth/enums/authentication-type.ts @@ -1,3 +1,5 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum AuthenticationType { Password = 0, Sso = 1, diff --git a/libs/common/src/auth/enums/sso.ts b/libs/common/src/auth/enums/sso.ts index 0c86a27151f..1e5766c7afd 100644 --- a/libs/common/src/auth/enums/sso.ts +++ b/libs/common/src/auth/enums/sso.ts @@ -1,25 +1,35 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum SsoType { None = 0, OpenIdConnect = 1, Saml2 = 2, } +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum MemberDecryptionType { MasterPassword = 0, KeyConnector = 1, TrustedDeviceEncryption = 2, } +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum OpenIdConnectRedirectBehavior { RedirectGet = 0, FormPost = 1, } +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum Saml2BindingType { HttpRedirect = 1, HttpPost = 2, } +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum Saml2NameIdFormat { NotConfigured = 0, Unspecified = 1, @@ -32,6 +42,8 @@ export enum Saml2NameIdFormat { Transient = 8, } +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum Saml2SigningBehavior { IfIdpWantAuthnRequestsSigned = 0, Always = 1, diff --git a/libs/common/src/auth/enums/two-factor-provider-type.ts b/libs/common/src/auth/enums/two-factor-provider-type.ts index b3308b6c12f..9be22bf90c8 100644 --- a/libs/common/src/auth/enums/two-factor-provider-type.ts +++ b/libs/common/src/auth/enums/two-factor-provider-type.ts @@ -1,3 +1,5 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum TwoFactorProviderType { Authenticator = 0, Email = 1, diff --git a/libs/common/src/auth/enums/verification-type.ts b/libs/common/src/auth/enums/verification-type.ts index c1991162f91..f0ad4c0d19c 100644 --- a/libs/common/src/auth/enums/verification-type.ts +++ b/libs/common/src/auth/enums/verification-type.ts @@ -1,3 +1,5 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum VerificationType { MasterPassword = 0, OTP = 1, diff --git a/libs/common/src/auth/models/domain/force-set-password-reason.ts b/libs/common/src/auth/models/domain/force-set-password-reason.ts index 56d52860443..68392125281 100644 --- a/libs/common/src/auth/models/domain/force-set-password-reason.ts +++ b/libs/common/src/auth/models/domain/force-set-password-reason.ts @@ -2,6 +2,8 @@ * This enum is used to determine if a user should be forced to initially set or reset their password * on login (server flag) or unlock via MP (client evaluation). */ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum ForceSetPasswordReason { /** * A password reset should not be forced. diff --git a/libs/common/src/auth/services/token.service.ts b/libs/common/src/auth/services/token.service.ts index c27afa6805a..61c00f69215 100644 --- a/libs/common/src/auth/services/token.service.ts +++ b/libs/common/src/auth/services/token.service.ts @@ -43,6 +43,8 @@ import { SECURITY_STAMP_MEMORY, } from "./token.state"; +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum TokenStorageLocation { Disk = "disk", SecureStorage = "secureStorage", diff --git a/libs/common/src/autofill/constants/index.ts b/libs/common/src/autofill/constants/index.ts index 62ad10e9a90..dc79e27b6aa 100644 --- a/libs/common/src/autofill/constants/index.ts +++ b/libs/common/src/autofill/constants/index.ts @@ -38,7 +38,7 @@ export const ClearClipboardDelay = { FiveMinutes: 300, } as const; -/* Context Menu item Ids */ +/* Ids for context menu items and messaging events */ export const AUTOFILL_CARD_ID = "autofill-card"; export const AUTOFILL_ID = "autofill"; export const SHOW_AUTOFILL_BUTTON = "show-autofill-button"; @@ -54,6 +54,7 @@ export const GENERATE_PASSWORD_ID = "generate-password"; export const NOOP_COMMAND_SUFFIX = "noop"; export const ROOT_ID = "root"; export const SEPARATOR_ID = "separator"; +export const UPDATE_PASSWORD = "update-password"; export const NOTIFICATION_BAR_LIFESPAN_MS = 150000; // 150 seconds diff --git a/libs/common/src/billing/abstractions/organization-billing.service.ts b/libs/common/src/billing/abstractions/organization-billing.service.ts index 8024a120b0a..58c537c99cc 100644 --- a/libs/common/src/billing/abstractions/organization-billing.service.ts +++ b/libs/common/src/billing/abstractions/organization-billing.service.ts @@ -39,6 +39,7 @@ export type BillingInformation = { export type PaymentInformation = { paymentMethod: [string, PaymentMethodType]; billing: BillingInformation; + skipTrial?: boolean; }; export type SubscriptionInformation = { diff --git a/libs/common/src/billing/abstractions/organizations/organization-sponsorship-api.service.abstraction.ts b/libs/common/src/billing/abstractions/organizations/organization-sponsorship-api.service.abstraction.ts index 7bd6aac17bd..5e69f57ca19 100644 --- a/libs/common/src/billing/abstractions/organizations/organization-sponsorship-api.service.abstraction.ts +++ b/libs/common/src/billing/abstractions/organizations/organization-sponsorship-api.service.abstraction.ts @@ -10,4 +10,9 @@ export abstract class OrganizationSponsorshipApiServiceAbstraction { sponsoringOrgId: string, friendlyName?: string, ): Promise; + + abstract deleteRevokeSponsorship: ( + sponsoringOrganizationId: string, + isAdminInitiated?: boolean, + ) => Promise; } diff --git a/libs/common/src/billing/abstractions/tax.service.abstraction.ts b/libs/common/src/billing/abstractions/tax.service.abstraction.ts index 7a744dae856..73dc848c95f 100644 --- a/libs/common/src/billing/abstractions/tax.service.abstraction.ts +++ b/libs/common/src/billing/abstractions/tax.service.abstraction.ts @@ -1,7 +1,9 @@ import { CountryListItem } from "../models/domain"; import { PreviewIndividualInvoiceRequest } from "../models/request/preview-individual-invoice.request"; import { PreviewOrganizationInvoiceRequest } from "../models/request/preview-organization-invoice.request"; +import { PreviewTaxAmountForOrganizationTrialRequest } from "../models/request/tax"; import { PreviewInvoiceResponse } from "../models/response/preview-invoice.response"; +import { PreviewTaxAmountResponse } from "../models/response/tax"; export abstract class TaxServiceAbstraction { abstract getCountries(): CountryListItem[]; @@ -15,4 +17,8 @@ export abstract class TaxServiceAbstraction { abstract previewOrganizationInvoice( request: PreviewOrganizationInvoiceRequest, ): Promise; + + abstract previewTaxAmountForOrganizationTrial: ( + request: PreviewTaxAmountForOrganizationTrialRequest, + ) => Promise; } diff --git a/libs/common/src/billing/enums/bitwarden-product-type.enum.ts b/libs/common/src/billing/enums/bitwarden-product-type.enum.ts index 76b0899fd9c..4389d283c00 100644 --- a/libs/common/src/billing/enums/bitwarden-product-type.enum.ts +++ b/libs/common/src/billing/enums/bitwarden-product-type.enum.ts @@ -1,3 +1,5 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum BitwardenProductType { PasswordManager = 0, SecretsManager = 1, diff --git a/libs/common/src/billing/enums/payment-method-type.enum.ts b/libs/common/src/billing/enums/payment-method-type.enum.ts index 9b29263175c..6ea98fdc5ec 100644 --- a/libs/common/src/billing/enums/payment-method-type.enum.ts +++ b/libs/common/src/billing/enums/payment-method-type.enum.ts @@ -1,3 +1,5 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum PaymentMethodType { Card = 0, BankAccount = 1, diff --git a/libs/common/src/billing/enums/plan-interval.enum.ts b/libs/common/src/billing/enums/plan-interval.enum.ts index 546336748cd..c048160310b 100644 --- a/libs/common/src/billing/enums/plan-interval.enum.ts +++ b/libs/common/src/billing/enums/plan-interval.enum.ts @@ -1,3 +1,5 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum PlanInterval { Monthly = 0, Annually = 1, diff --git a/libs/common/src/billing/enums/plan-sponsorship-type.enum.ts b/libs/common/src/billing/enums/plan-sponsorship-type.enum.ts index 3b4c00467c2..845b698f509 100644 --- a/libs/common/src/billing/enums/plan-sponsorship-type.enum.ts +++ b/libs/common/src/billing/enums/plan-sponsorship-type.enum.ts @@ -1,3 +1,5 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum PlanSponsorshipType { FamiliesForEnterprise = 0, } diff --git a/libs/common/src/billing/enums/plan-type.enum.ts b/libs/common/src/billing/enums/plan-type.enum.ts index c8977703454..5c356ce42fe 100644 --- a/libs/common/src/billing/enums/plan-type.enum.ts +++ b/libs/common/src/billing/enums/plan-type.enum.ts @@ -1,3 +1,5 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum PlanType { Free = 0, FamiliesAnnually2019 = 1, diff --git a/libs/common/src/billing/enums/product-tier-type.enum.ts b/libs/common/src/billing/enums/product-tier-type.enum.ts index fadf57ccdc5..e94243de588 100644 --- a/libs/common/src/billing/enums/product-tier-type.enum.ts +++ b/libs/common/src/billing/enums/product-tier-type.enum.ts @@ -1,3 +1,5 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum ProductTierType { Free = 0, Families = 1, diff --git a/libs/common/src/billing/enums/product-type.enum.ts b/libs/common/src/billing/enums/product-type.enum.ts index 3072ad0f96a..0c11eb92c79 100644 --- a/libs/common/src/billing/enums/product-type.enum.ts +++ b/libs/common/src/billing/enums/product-type.enum.ts @@ -1,3 +1,5 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum ProductType { PasswordManager = 0, SecretsManager = 1, diff --git a/libs/common/src/billing/enums/transaction-type.enum.ts b/libs/common/src/billing/enums/transaction-type.enum.ts index 34731a2ec33..d4c48253a39 100644 --- a/libs/common/src/billing/enums/transaction-type.enum.ts +++ b/libs/common/src/billing/enums/transaction-type.enum.ts @@ -1,3 +1,5 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum TransactionType { Charge = 0, Credit = 1, diff --git a/libs/common/src/billing/models/request/tax/index.ts b/libs/common/src/billing/models/request/tax/index.ts new file mode 100644 index 00000000000..cda1930c614 --- /dev/null +++ b/libs/common/src/billing/models/request/tax/index.ts @@ -0,0 +1 @@ +export * from "./preview-tax-amount-for-organization-trial.request"; diff --git a/libs/common/src/billing/models/request/tax/preview-tax-amount-for-organization-trial.request.ts b/libs/common/src/billing/models/request/tax/preview-tax-amount-for-organization-trial.request.ts new file mode 100644 index 00000000000..3f366335a47 --- /dev/null +++ b/libs/common/src/billing/models/request/tax/preview-tax-amount-for-organization-trial.request.ts @@ -0,0 +1,11 @@ +import { PlanType, ProductType } from "../../../enums"; + +export type PreviewTaxAmountForOrganizationTrialRequest = { + planType: PlanType; + productType: ProductType; + taxInformation: { + country: string; + postalCode: string; + taxId?: string; + }; +}; diff --git a/libs/common/src/billing/models/response/tax/index.ts b/libs/common/src/billing/models/response/tax/index.ts new file mode 100644 index 00000000000..525d6d7c80a --- /dev/null +++ b/libs/common/src/billing/models/response/tax/index.ts @@ -0,0 +1 @@ +export * from "./preview-tax-amount.response"; diff --git a/libs/common/src/billing/models/response/tax/preview-tax-amount.response.ts b/libs/common/src/billing/models/response/tax/preview-tax-amount.response.ts new file mode 100644 index 00000000000..cf15156551a --- /dev/null +++ b/libs/common/src/billing/models/response/tax/preview-tax-amount.response.ts @@ -0,0 +1,11 @@ +import { BaseResponse } from "../../../../models/response/base.response"; + +export class PreviewTaxAmountResponse extends BaseResponse { + taxAmount: number; + + constructor(response: any) { + super(response); + + this.taxAmount = this.getResponseProperty("TaxAmount"); + } +} diff --git a/libs/common/src/billing/services/organization-billing.service.ts b/libs/common/src/billing/services/organization-billing.service.ts index c6bd88d8dd6..fe5623fd5e6 100644 --- a/libs/common/src/billing/services/organization-billing.service.ts +++ b/libs/common/src/billing/services/organization-billing.service.ts @@ -174,6 +174,7 @@ export class OrganizationBillingService implements OrganizationBillingServiceAbs const [paymentToken, paymentMethodType] = information.paymentMethod; request.paymentToken = paymentToken; request.paymentMethodType = paymentMethodType; + request.skipTrial = information.skipTrial; const billingInformation = information.billing; request.billingAddressPostalCode = billingInformation.postalCode; diff --git a/libs/common/src/billing/services/organization/organization-sponsorship-api.service.ts b/libs/common/src/billing/services/organization/organization-sponsorship-api.service.ts index 22ab3ec86ee..99440b10dec 100644 --- a/libs/common/src/billing/services/organization/organization-sponsorship-api.service.ts +++ b/libs/common/src/billing/services/organization/organization-sponsorship-api.service.ts @@ -1,12 +1,16 @@ import { ApiService } from "../../../abstractions/api.service"; import { ListResponse } from "../../../models/response/list.response"; +import { PlatformUtilsService } from "../../../platform/abstractions/platform-utils.service"; import { OrganizationSponsorshipApiServiceAbstraction } from "../../abstractions/organizations/organization-sponsorship-api.service.abstraction"; import { OrganizationSponsorshipInvitesResponse } from "../../models/response/organization-sponsorship-invites.response"; export class OrganizationSponsorshipApiService implements OrganizationSponsorshipApiServiceAbstraction { - constructor(private apiService: ApiService) {} + constructor( + private apiService: ApiService, + private platformUtilsService: PlatformUtilsService, + ) {} async getOrganizationSponsorship( sponsoredOrgId: string, ): Promise> { @@ -33,4 +37,21 @@ export class OrganizationSponsorshipApiService return await this.apiService.send("POST", url, null, true, false); } + + async deleteRevokeSponsorship( + sponsoringOrganizationId: string, + isAdminInitiated: boolean = false, + ): Promise { + const basePath = "/organization/sponsorship/"; + const hostPath = this.platformUtilsService.isSelfHost() ? "self-hosted/" : ""; + const queryParam = `?isAdminInitiated=${isAdminInitiated}`; + + return await this.apiService.send( + "DELETE", + basePath + hostPath + sponsoringOrganizationId + queryParam, + null, + true, + false, + ); + } } diff --git a/libs/common/src/billing/services/tax.service.ts b/libs/common/src/billing/services/tax.service.ts index aa27c99adc8..2632ca7083b 100644 --- a/libs/common/src/billing/services/tax.service.ts +++ b/libs/common/src/billing/services/tax.service.ts @@ -1,3 +1,6 @@ +import { PreviewTaxAmountForOrganizationTrialRequest } from "@bitwarden/common/billing/models/request/tax"; +import { PreviewTaxAmountResponse } from "@bitwarden/common/billing/models/response/tax"; + import { ApiService } from "../../abstractions/api.service"; import { TaxServiceAbstraction } from "../abstractions/tax.service.abstraction"; import { CountryListItem } from "../models/domain"; @@ -300,4 +303,16 @@ export class TaxService implements TaxServiceAbstraction { ); return new PreviewInvoiceResponse(response); } + + async previewTaxAmountForOrganizationTrial( + request: PreviewTaxAmountForOrganizationTrialRequest, + ): Promise { + return await this.apiService.send( + "POST", + "/tax/preview-amount/organization-trial", + request, + true, + true, + ); + } } diff --git a/libs/common/src/enums/client-type.enum.ts b/libs/common/src/enums/client-type.enum.ts index 54653f74462..25e9d6f3371 100644 --- a/libs/common/src/enums/client-type.enum.ts +++ b/libs/common/src/enums/client-type.enum.ts @@ -1,3 +1,5 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum ClientType { Web = "web", Browser = "browser", diff --git a/libs/common/src/enums/device-type.enum.ts b/libs/common/src/enums/device-type.enum.ts index ff6329b9ac4..d5628536ff7 100644 --- a/libs/common/src/enums/device-type.enum.ts +++ b/libs/common/src/enums/device-type.enum.ts @@ -1,3 +1,5 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum DeviceType { Android = 0, iOS = 1, diff --git a/libs/common/src/enums/event-system-user.enum.ts b/libs/common/src/enums/event-system-user.enum.ts index e2d43a4f113..f4abbb1e3e9 100644 --- a/libs/common/src/enums/event-system-user.enum.ts +++ b/libs/common/src/enums/event-system-user.enum.ts @@ -1,4 +1,6 @@ // Note: the enum key is used to describe the EventSystemUser in the UI. Be careful about changing it. +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum EventSystemUser { SCIM = 1, DomainVerification = 2, diff --git a/libs/common/src/enums/event-type.enum.ts b/libs/common/src/enums/event-type.enum.ts index 51b324bb434..9efe49b1b0f 100644 --- a/libs/common/src/enums/event-type.enum.ts +++ b/libs/common/src/enums/event-type.enum.ts @@ -1,4 +1,6 @@ // Increment by 100 for each new set of events +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum EventType { User_LoggedIn = 1000, User_ChangedPassword = 1001, diff --git a/libs/common/src/enums/feature-flag.enum.ts b/libs/common/src/enums/feature-flag.enum.ts index 32ccf11241f..c4312c067b1 100644 --- a/libs/common/src/enums/feature-flag.enum.ts +++ b/libs/common/src/enums/feature-flag.enum.ts @@ -7,6 +7,8 @@ import { ServerConfig } from "../platform/abstractions/config/server-config"; * * Flags should be grouped by team to have visibility of ownership and cleanup. */ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum FeatureFlag { /* Admin Console Team */ VerifiedSsoDomainEndpoint = "pm-12337-refactor-sso-details-endpoint", @@ -16,9 +18,8 @@ export enum FeatureFlag { SeparateCustomRolePermissions = "pm-19917-separate-custom-role-permissions", /* Auth */ - PM9112_DeviceApprovalPersistence = "pm-9112-device-approval-persistence", - PM16117_ChangeExistingPasswordRefactor = "pm-16117-change-existing-password-refactor", PM9115_TwoFactorExtensionDataPersistence = "pm-9115-two-factor-extension-data-persistence", + PM16117_ChangeExistingPasswordRefactor = "pm-16117-change-existing-password-refactor", /* Autofill */ BlockBrowserInjectionsByDomain = "block-browser-injections-by-domain", @@ -56,7 +57,6 @@ export enum FeatureFlag { /* Vault */ PM8851_BrowserOnboardingNudge = "pm-8851-browser-onboarding-nudge", PM9111ExtensionPersistAddEditForm = "pm-9111-extension-persist-add-edit-form", - VaultBulkManagementAction = "vault-bulk-management-action", SecurityTasks = "security-tasks", CipherKeyEncryption = "cipher-key-encryption", PM18520_UpdateDesktopCipherForm = "pm-18520-desktop-cipher-forms", @@ -108,14 +108,12 @@ export const DefaultFeatureFlagValue = { /* Vault */ [FeatureFlag.PM8851_BrowserOnboardingNudge]: FALSE, [FeatureFlag.PM9111ExtensionPersistAddEditForm]: FALSE, - [FeatureFlag.VaultBulkManagementAction]: FALSE, [FeatureFlag.SecurityTasks]: FALSE, [FeatureFlag.CipherKeyEncryption]: FALSE, [FeatureFlag.PM18520_UpdateDesktopCipherForm]: FALSE, [FeatureFlag.EndUserNotifications]: FALSE, /* Auth */ - [FeatureFlag.PM9112_DeviceApprovalPersistence]: FALSE, [FeatureFlag.PM16117_ChangeExistingPasswordRefactor]: FALSE, [FeatureFlag.PM9115_TwoFactorExtensionDataPersistence]: FALSE, diff --git a/libs/common/src/enums/http-status-code.enum.ts b/libs/common/src/enums/http-status-code.enum.ts index 94226c82552..d2dba5d8d4c 100644 --- a/libs/common/src/enums/http-status-code.enum.ts +++ b/libs/common/src/enums/http-status-code.enum.ts @@ -4,6 +4,8 @@ * @see {@link https://en.wikipedia.org/wiki/List_of_HTTP_status_codes} * src: https://gist.github.com/RWOverdijk/6cef816cfdf5722228e01cc05fd4b094 */ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum HttpStatusCode { /** * The server has received the request headers and the client should proceed to send the request body diff --git a/libs/common/src/enums/integration-type.enum.ts b/libs/common/src/enums/integration-type.enum.ts index 42c385fe715..ac8bb9c6afa 100644 --- a/libs/common/src/enums/integration-type.enum.ts +++ b/libs/common/src/enums/integration-type.enum.ts @@ -1,3 +1,5 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum IntegrationType { Integration = "integration", SDK = "sdk", diff --git a/libs/common/src/enums/native-messaging-version.enum.ts b/libs/common/src/enums/native-messaging-version.enum.ts index f7cf411a40a..f83ec8f4b25 100644 --- a/libs/common/src/enums/native-messaging-version.enum.ts +++ b/libs/common/src/enums/native-messaging-version.enum.ts @@ -1,3 +1,5 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum NativeMessagingVersion { One = 1, // Original implementation Latest = One, diff --git a/libs/common/src/enums/notification-type.enum.ts b/libs/common/src/enums/notification-type.enum.ts index 0e4d0bfee3d..6d731253ce3 100644 --- a/libs/common/src/enums/notification-type.enum.ts +++ b/libs/common/src/enums/notification-type.enum.ts @@ -1,3 +1,5 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum NotificationType { SyncCipherUpdate = 0, SyncCipherCreate = 1, diff --git a/libs/common/src/enums/push-technology.enum.ts b/libs/common/src/enums/push-technology.enum.ts index 9452c144bb7..1bc4e62cc9d 100644 --- a/libs/common/src/enums/push-technology.enum.ts +++ b/libs/common/src/enums/push-technology.enum.ts @@ -1,6 +1,8 @@ /** * The preferred push technology of the server. */ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum PushTechnology { /** * Indicates that we should use SignalR over web sockets to receive push notifications from the server. diff --git a/libs/common/src/key-management/master-password/abstractions/master-password.service.abstraction.ts b/libs/common/src/key-management/master-password/abstractions/master-password.service.abstraction.ts index 221ce8ed6ef..fded0cea023 100644 --- a/libs/common/src/key-management/master-password/abstractions/master-password.service.abstraction.ts +++ b/libs/common/src/key-management/master-password/abstractions/master-password.service.abstraction.ts @@ -37,13 +37,13 @@ export abstract class MasterPasswordServiceAbstraction { * @param userKey The user's encrypted symmetric key * @throws If either the MasterKey or UserKey are not resolved, or if the UserKey encryption type * is neither AesCbc256_B64 nor AesCbc256_HmacSha256_B64 - * @returns The user key + * @returns The user key or null if the masterkey is wrong */ abstract decryptUserKeyWithMasterKey: ( masterKey: MasterKey, userId: string, userKey?: EncString, - ) => Promise; + ) => Promise; } export abstract class InternalMasterPasswordServiceAbstraction extends MasterPasswordServiceAbstraction { diff --git a/libs/common/src/key-management/master-password/services/master-password.service.ts b/libs/common/src/key-management/master-password/services/master-password.service.ts index b9b11d6cbe8..9e58680d453 100644 --- a/libs/common/src/key-management/master-password/services/master-password.service.ts +++ b/libs/common/src/key-management/master-password/services/master-password.service.ts @@ -166,7 +166,7 @@ export class MasterPasswordService implements InternalMasterPasswordServiceAbstr masterKey: MasterKey, userId: UserId, userKey?: EncString, - ): Promise { + ): Promise { userKey ??= await this.getMasterKeyEncryptedUserKey(userId); masterKey ??= await firstValueFrom(this.masterKey$(userId)); @@ -177,16 +177,26 @@ export class MasterPasswordService implements InternalMasterPasswordServiceAbstr let decUserKey: SymmetricCryptoKey; if (userKey.encryptionType === EncryptionType.AesCbc256_B64) { - decUserKey = await this.encryptService.unwrapSymmetricKey(userKey, masterKey); + try { + decUserKey = await this.encryptService.unwrapSymmetricKey(userKey, masterKey); + } catch { + this.logService.warning("Failed to decrypt user key with master key."); + return null; + } } else if (userKey.encryptionType === EncryptionType.AesCbc256_HmacSha256_B64) { - const newKey = await this.keyGenerationService.stretchKey(masterKey); - decUserKey = await this.encryptService.unwrapSymmetricKey(userKey, newKey); + try { + const newKey = await this.keyGenerationService.stretchKey(masterKey); + decUserKey = await this.encryptService.unwrapSymmetricKey(userKey, newKey); + } catch { + this.logService.warning("Failed to decrypt user key with stretched master key."); + return null; + } } else { throw new Error("Unsupported encryption type."); } if (decUserKey == null) { - this.logService.warning("Failed to decrypt user key with master key."); + this.logService.warning("Failed to decrypt user key with master key, user key is null."); return null; } diff --git a/libs/common/src/key-management/vault-timeout/enums/vault-timeout-action.enum.ts b/libs/common/src/key-management/vault-timeout/enums/vault-timeout-action.enum.ts index 239a7490191..9e70b7ebb12 100644 --- a/libs/common/src/key-management/vault-timeout/enums/vault-timeout-action.enum.ts +++ b/libs/common/src/key-management/vault-timeout/enums/vault-timeout-action.enum.ts @@ -1,3 +1,5 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum VaultTimeoutAction { Lock = "lock", LogOut = "logOut", diff --git a/libs/common/src/platform/abstractions/environment.service.ts b/libs/common/src/platform/abstractions/environment.service.ts index 4a10f856893..b8931656848 100644 --- a/libs/common/src/platform/abstractions/environment.service.ts +++ b/libs/common/src/platform/abstractions/environment.service.ts @@ -17,6 +17,8 @@ export type Urls = { /** * A subset of available regions, additional regions can be loaded through configuration. */ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum Region { US = "US", EU = "EU", diff --git a/libs/common/src/platform/abstractions/fido2/fido2-authenticator.service.abstraction.ts b/libs/common/src/platform/abstractions/fido2/fido2-authenticator.service.abstraction.ts index e9e68ca92c3..15655393362 100644 --- a/libs/common/src/platform/abstractions/fido2/fido2-authenticator.service.abstraction.ts +++ b/libs/common/src/platform/abstractions/fido2/fido2-authenticator.service.abstraction.ts @@ -46,11 +46,15 @@ export abstract class Fido2AuthenticatorService { silentCredentialDiscovery: (rpId: string) => Promise; } +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum Fido2AlgorithmIdentifier { ES256 = -7, RS256 = -257, } +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum Fido2AuthenticatorErrorCode { Unknown = "UnknownError", NotSupported = "NotSupportedError", diff --git a/libs/common/src/platform/enums/encryption-type.enum.ts b/libs/common/src/platform/enums/encryption-type.enum.ts index fd484dc2fdf..7f4b5048a45 100644 --- a/libs/common/src/platform/enums/encryption-type.enum.ts +++ b/libs/common/src/platform/enums/encryption-type.enum.ts @@ -1,3 +1,5 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum EncryptionType { AesCbc256_B64 = 0, // Type 1 was the unused and removed AesCbc128_HmacSha256_B64 diff --git a/libs/common/src/platform/enums/file-upload-type.enum.ts b/libs/common/src/platform/enums/file-upload-type.enum.ts index 4cf654fd0ff..a94797b9ef3 100644 --- a/libs/common/src/platform/enums/file-upload-type.enum.ts +++ b/libs/common/src/platform/enums/file-upload-type.enum.ts @@ -1,3 +1,5 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum FileUploadType { Direct = 0, Azure = 1, diff --git a/libs/common/src/platform/enums/hash-purpose.enum.ts b/libs/common/src/platform/enums/hash-purpose.enum.ts index 887931b9edd..4b61db914a1 100644 --- a/libs/common/src/platform/enums/hash-purpose.enum.ts +++ b/libs/common/src/platform/enums/hash-purpose.enum.ts @@ -1,3 +1,5 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum HashPurpose { ServerAuthorization = 1, LocalAuthorization = 2, diff --git a/libs/common/src/platform/enums/html-storage-location.enum.ts b/libs/common/src/platform/enums/html-storage-location.enum.ts index 19c84fe88c7..1d018a72869 100644 --- a/libs/common/src/platform/enums/html-storage-location.enum.ts +++ b/libs/common/src/platform/enums/html-storage-location.enum.ts @@ -1,3 +1,5 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum HtmlStorageLocation { Local = "local", Memory = "memory", diff --git a/libs/common/src/platform/enums/key-suffix-options.enum.ts b/libs/common/src/platform/enums/key-suffix-options.enum.ts index 98fa215be6a..7cc412f563b 100644 --- a/libs/common/src/platform/enums/key-suffix-options.enum.ts +++ b/libs/common/src/platform/enums/key-suffix-options.enum.ts @@ -1,3 +1,5 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum KeySuffixOptions { Auto = "auto", Pin = "pin", diff --git a/libs/common/src/platform/enums/log-level-type.enum.ts b/libs/common/src/platform/enums/log-level-type.enum.ts index 709871dd5e9..b5f84467d6e 100644 --- a/libs/common/src/platform/enums/log-level-type.enum.ts +++ b/libs/common/src/platform/enums/log-level-type.enum.ts @@ -1,3 +1,5 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum LogLevelType { Debug, Info, diff --git a/libs/common/src/platform/enums/storage-location.enum.ts b/libs/common/src/platform/enums/storage-location.enum.ts index 46d50d1d38d..9f6e22babec 100644 --- a/libs/common/src/platform/enums/storage-location.enum.ts +++ b/libs/common/src/platform/enums/storage-location.enum.ts @@ -1,3 +1,5 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum StorageLocation { Both = "both", Disk = "disk", diff --git a/libs/common/src/platform/enums/theme-type.enum.ts b/libs/common/src/platform/enums/theme-type.enum.ts index d1767c4990a..c0f9aa2d52f 100644 --- a/libs/common/src/platform/enums/theme-type.enum.ts +++ b/libs/common/src/platform/enums/theme-type.enum.ts @@ -1,6 +1,8 @@ /** * @deprecated prefer the `ThemeTypes` constants and `Theme` type over unsafe enum types **/ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum ThemeType { System = "system", Light = "light", diff --git a/libs/common/src/platform/services/cryptography/initializer-key.ts b/libs/common/src/platform/services/cryptography/initializer-key.ts index 88e36d90515..59287a62c46 100644 --- a/libs/common/src/platform/services/cryptography/initializer-key.ts +++ b/libs/common/src/platform/services/cryptography/initializer-key.ts @@ -1,3 +1,5 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum InitializerKey { Cipher = 0, CipherView = 1, diff --git a/libs/common/src/services/api.service.ts b/libs/common/src/services/api.service.ts index 5c4bcdedb26..639daa7c658 100644 --- a/libs/common/src/services/api.service.ts +++ b/libs/common/src/services/api.service.ts @@ -1621,18 +1621,6 @@ export class ApiService implements ApiServiceAbstraction { return new OrganizationSponsorshipSyncStatusResponse(response); } - async deleteRevokeSponsorship(sponsoringOrganizationId: string): Promise { - return await this.send( - "DELETE", - "/organization/sponsorship/" + - (this.platformUtilsService.isSelfHost() ? "self-hosted/" : "") + - sponsoringOrganizationId, - null, - true, - false, - ); - } - async deleteRemoveSponsorship(sponsoringOrgId: string): Promise { return await this.send( "DELETE", diff --git a/libs/common/src/state-migrations/migrations/28-move-provider-state-to-state-provider.ts b/libs/common/src/state-migrations/migrations/28-move-provider-state-to-state-provider.ts index 96f0a9acd5d..5ae943438d2 100644 --- a/libs/common/src/state-migrations/migrations/28-move-provider-state-to-state-provider.ts +++ b/libs/common/src/state-migrations/migrations/28-move-provider-state-to-state-provider.ts @@ -5,6 +5,8 @@ import { Jsonify } from "type-fest"; import { KeyDefinitionLike, MigrationHelper } from "../migration-helper"; import { Migrator } from "../migrator"; +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums enum ProviderUserStatusType { Invited = 0, Accepted = 1, @@ -12,6 +14,8 @@ enum ProviderUserStatusType { Revoked = -1, } +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums enum ProviderUserType { ProviderAdmin = 0, ServiceUser = 1, diff --git a/libs/common/src/state-migrations/migrations/30-move-policy-state-to-state-provider.ts b/libs/common/src/state-migrations/migrations/30-move-policy-state-to-state-provider.ts index 0b4c95cb55c..f188bc0a33e 100644 --- a/libs/common/src/state-migrations/migrations/30-move-policy-state-to-state-provider.ts +++ b/libs/common/src/state-migrations/migrations/30-move-policy-state-to-state-provider.ts @@ -3,6 +3,8 @@ import { KeyDefinitionLike, MigrationHelper } from "../migration-helper"; import { Migrator } from "../migrator"; +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums enum PolicyType { TwoFactorAuthentication = 0, // Requires users to have 2fa enabled MasterPassword = 1, // Sets minimum requirements for master password complexity diff --git a/libs/common/src/state-migrations/migrations/40-move-organization-state-to-state-provider.ts b/libs/common/src/state-migrations/migrations/40-move-organization-state-to-state-provider.ts index 862fe33bd4e..b23b712aefe 100644 --- a/libs/common/src/state-migrations/migrations/40-move-organization-state-to-state-provider.ts +++ b/libs/common/src/state-migrations/migrations/40-move-organization-state-to-state-provider.ts @@ -7,6 +7,8 @@ import { Migrator } from "../migrator"; // Local declarations of `OrganizationData` and the types of it's properties. // Duplicated to remain frozen in time when migration occurs. +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums enum OrganizationUserStatusType { Invited = 0, Accepted = 1, @@ -14,6 +16,8 @@ enum OrganizationUserStatusType { Revoked = -1, } +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums enum OrganizationUserType { Owner = 0, Admin = 1, @@ -40,11 +44,15 @@ type PermissionsApi = { manageScim: boolean; }; +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums enum ProviderType { Msp = 0, Reseller = 1, } +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums enum ProductType { Free = 0, Families = 1, diff --git a/libs/common/src/state-migrations/migrations/54-move-encrypted-sends.ts b/libs/common/src/state-migrations/migrations/54-move-encrypted-sends.ts index 7d3a2bebbf9..489fb2258ee 100644 --- a/libs/common/src/state-migrations/migrations/54-move-encrypted-sends.ts +++ b/libs/common/src/state-migrations/migrations/54-move-encrypted-sends.ts @@ -3,6 +3,8 @@ import { KeyDefinitionLike, MigrationHelper } from "../migration-helper"; import { Migrator } from "../migrator"; +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum SendType { Text = 0, File = 1, diff --git a/libs/common/src/state-migrations/migrations/59-move-kdf-config-to-state-provider.ts b/libs/common/src/state-migrations/migrations/59-move-kdf-config-to-state-provider.ts index 81ee193867b..a01ef42a8ff 100644 --- a/libs/common/src/state-migrations/migrations/59-move-kdf-config-to-state-provider.ts +++ b/libs/common/src/state-migrations/migrations/59-move-kdf-config-to-state-provider.ts @@ -3,6 +3,8 @@ import { KeyDefinitionLike, MigrationHelper } from "../migration-helper"; import { Migrator } from "../migrator"; +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums enum KdfType { PBKDF2_SHA256 = 0, Argon2id = 1, diff --git a/libs/common/src/state-migrations/migrations/62-migrate-vault-timeout-settings-svc-to-state-provider.ts b/libs/common/src/state-migrations/migrations/62-migrate-vault-timeout-settings-svc-to-state-provider.ts index 5874a80dc60..3557bfae083 100644 --- a/libs/common/src/state-migrations/migrations/62-migrate-vault-timeout-settings-svc-to-state-provider.ts +++ b/libs/common/src/state-migrations/migrations/62-migrate-vault-timeout-settings-svc-to-state-provider.ts @@ -57,6 +57,8 @@ const vaultTimeoutTypeRollbackRecord: Record = { onIdle: -4, }; +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum ClientType { Web = "web", Browser = "browser", diff --git a/libs/common/src/tools/send/enums/send-type.ts b/libs/common/src/tools/send/enums/send-type.ts index 487930c90c7..5b03c71d22a 100644 --- a/libs/common/src/tools/send/enums/send-type.ts +++ b/libs/common/src/tools/send/enums/send-type.ts @@ -1,3 +1,5 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum SendType { Text = 0, File = 1, diff --git a/libs/common/src/vault/enums/cipher-reprompt-type.ts b/libs/common/src/vault/enums/cipher-reprompt-type.ts index 1d0a523ced0..190a9bad042 100644 --- a/libs/common/src/vault/enums/cipher-reprompt-type.ts +++ b/libs/common/src/vault/enums/cipher-reprompt-type.ts @@ -1,3 +1,5 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum CipherRepromptType { None = 0, Password = 1, diff --git a/libs/common/src/vault/enums/cipher-type.ts b/libs/common/src/vault/enums/cipher-type.ts index 0b7bbf1ee17..30d80cdef7e 100644 --- a/libs/common/src/vault/enums/cipher-type.ts +++ b/libs/common/src/vault/enums/cipher-type.ts @@ -1,3 +1,5 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum CipherType { Login = 1, SecureNote = 2, diff --git a/libs/common/src/vault/enums/field-type.enum.ts b/libs/common/src/vault/enums/field-type.enum.ts index d6deb30e691..df5016890b2 100644 --- a/libs/common/src/vault/enums/field-type.enum.ts +++ b/libs/common/src/vault/enums/field-type.enum.ts @@ -1,3 +1,5 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum FieldType { Text = 0, Hidden = 1, diff --git a/libs/common/src/vault/enums/linked-id-type.enum.ts b/libs/common/src/vault/enums/linked-id-type.enum.ts index c38ebc1c6e8..b329aecb3f4 100644 --- a/libs/common/src/vault/enums/linked-id-type.enum.ts +++ b/libs/common/src/vault/enums/linked-id-type.enum.ts @@ -1,12 +1,16 @@ export type LinkedIdType = LoginLinkedId | CardLinkedId | IdentityLinkedId; // LoginView +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum LoginLinkedId { Username = 100, Password = 101, } // CardView +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum CardLinkedId { CardholderName = 300, ExpMonth = 301, @@ -17,6 +21,8 @@ export enum CardLinkedId { } // IdentityView +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum IdentityLinkedId { Title = 400, MiddleName = 401, diff --git a/libs/common/src/vault/enums/secure-note-type.enum.ts b/libs/common/src/vault/enums/secure-note-type.enum.ts index 8015236d148..4fbd05e6bd4 100644 --- a/libs/common/src/vault/enums/secure-note-type.enum.ts +++ b/libs/common/src/vault/enums/secure-note-type.enum.ts @@ -1,3 +1,5 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum SecureNoteType { Generic = 0, } diff --git a/libs/common/src/vault/tasks/enums/security-task-status.enum.ts b/libs/common/src/vault/tasks/enums/security-task-status.enum.ts index 1c6e7decc20..c8c26266e66 100644 --- a/libs/common/src/vault/tasks/enums/security-task-status.enum.ts +++ b/libs/common/src/vault/tasks/enums/security-task-status.enum.ts @@ -1,3 +1,5 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum SecurityTaskStatus { /** * Default status for newly created tasks that have not been completed. diff --git a/libs/common/src/vault/tasks/enums/security-task-type.enum.ts b/libs/common/src/vault/tasks/enums/security-task-type.enum.ts index 264cd88696b..79a2d23c8b3 100644 --- a/libs/common/src/vault/tasks/enums/security-task-type.enum.ts +++ b/libs/common/src/vault/tasks/enums/security-task-type.enum.ts @@ -1,3 +1,5 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum SecurityTaskType { /** * Task to update a cipher's password that was found to be at-risk by an administrator diff --git a/libs/components/src/color-password/color-password.component.ts b/libs/components/src/color-password/color-password.component.ts index 86ccb41ba3c..2dd78e8525d 100644 --- a/libs/components/src/color-password/color-password.component.ts +++ b/libs/components/src/color-password/color-password.component.ts @@ -2,6 +2,8 @@ import { Component, computed, HostBinding, input } from "@angular/core"; import { Utils } from "@bitwarden/common/platform/misc/utils"; +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums enum CharacterType { Letter, Emoji, diff --git a/libs/eslint/platform/index.mjs b/libs/eslint/platform/index.mjs index 049d95e2074..c7ea3f1dd89 100644 --- a/libs/eslint/platform/index.mjs +++ b/libs/eslint/platform/index.mjs @@ -1,3 +1,4 @@ import requiredUsing from "./required-using.mjs"; +import noEnums from "./no-enums.mjs"; -export default { rules: { "required-using": requiredUsing } }; +export default { rules: { "required-using": requiredUsing, "no-enums": noEnums } }; diff --git a/libs/eslint/platform/no-enums.mjs b/libs/eslint/platform/no-enums.mjs new file mode 100644 index 00000000000..4f3039f7e34 --- /dev/null +++ b/libs/eslint/platform/no-enums.mjs @@ -0,0 +1,23 @@ +export const errorMessage = "Enums are discouraged, please use a const object instead"; + +export default { + meta: { + type: "suggestion", + docs: { + description: "Enforce using consts instead of enums", + category: "Best Practices", + recommended: false, + }, + schema: [], + }, + create(context) { + return { + TSEnumDeclaration(node) { + context.report({ + node, + message: errorMessage, + }); + }, + }; + }, +}; diff --git a/libs/eslint/platform/no-enums.spec.mjs b/libs/eslint/platform/no-enums.spec.mjs new file mode 100644 index 00000000000..5ded12d6ed3 --- /dev/null +++ b/libs/eslint/platform/no-enums.spec.mjs @@ -0,0 +1,71 @@ +import { RuleTester } from "@typescript-eslint/rule-tester"; + +import rule, { errorMessage } from "./no-enums.mjs"; + +const ruleTester = new RuleTester({ + languageOptions: { + parserOptions: { + project: [__dirname + "/../tsconfig.spec.json"], + projectService: { + allowDefaultProject: ["*.ts*"], + }, + tsconfigRootDir: __dirname + "/..", + }, + }, +}); + +ruleTester.run("no-enums", rule.default, { + valid: [ + { + name: "Using const instead of enum", + code: ` + const Status = { + Active: "active", + Inactive: "inactive", + } as const; + `, + }, + { + name: "Using const with type", + code: ` + const Status = { + Active: "active", + Inactive: "inactive", + } as const; + type Status = typeof Status[keyof typeof Status]; + `, + }, + ], + invalid: [ + { + name: "Using enum declaration", + code: ` + enum Status { + Active = "active", + Inactive = "inactive", + } + `, + errors: [ + { + message: errorMessage, + }, + ], + }, + { + name: "Using enum with numeric values", + code: ` + enum Direction { + Up = 1, + Down = 2, + Left = 3, + Right = 4, + } + `, + errors: [ + { + message: errorMessage, + }, + ], + }, + ], +}); diff --git a/libs/importer/src/importers/fsecure/fsecure-fsk-types.ts b/libs/importer/src/importers/fsecure/fsecure-fsk-types.ts index 71797a0f8cd..1235426d683 100644 --- a/libs/importer/src/importers/fsecure/fsecure-fsk-types.ts +++ b/libs/importer/src/importers/fsecure/fsecure-fsk-types.ts @@ -6,6 +6,8 @@ export interface Data { [key: string]: FskEntry; } +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum FskEntryTypesEnum { Login = 1, CreditCard = 2, diff --git a/libs/importer/src/importers/lastpass/access/enums/idp-provider.ts b/libs/importer/src/importers/lastpass/access/enums/idp-provider.ts index 32e74c36ee1..01c4572fcf9 100644 --- a/libs/importer/src/importers/lastpass/access/enums/idp-provider.ts +++ b/libs/importer/src/importers/lastpass/access/enums/idp-provider.ts @@ -1,3 +1,5 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum IdpProvider { Azure = 0, OktaAuthServer = 1, diff --git a/libs/importer/src/importers/lastpass/access/enums/lastpass-login-type.ts b/libs/importer/src/importers/lastpass/access/enums/lastpass-login-type.ts index 611dd0b6dab..a3be36c790e 100644 --- a/libs/importer/src/importers/lastpass/access/enums/lastpass-login-type.ts +++ b/libs/importer/src/importers/lastpass/access/enums/lastpass-login-type.ts @@ -1,3 +1,5 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum LastpassLoginType { MasterPassword = 0, // Not sure what Types 1 and 2 are? diff --git a/libs/importer/src/importers/lastpass/access/enums/otp-method.ts b/libs/importer/src/importers/lastpass/access/enums/otp-method.ts index 6b940486ff0..f1237160179 100644 --- a/libs/importer/src/importers/lastpass/access/enums/otp-method.ts +++ b/libs/importer/src/importers/lastpass/access/enums/otp-method.ts @@ -1,3 +1,5 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum OtpMethod { GoogleAuth, MicrosoftAuth, diff --git a/libs/importer/src/importers/lastpass/access/enums/platform.ts b/libs/importer/src/importers/lastpass/access/enums/platform.ts index 283e0c36ce2..6870fc28c24 100644 --- a/libs/importer/src/importers/lastpass/access/enums/platform.ts +++ b/libs/importer/src/importers/lastpass/access/enums/platform.ts @@ -1,3 +1,5 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum Platform { Desktop, Mobile, diff --git a/libs/importer/src/importers/onepassword/types/onepassword-1pux-importer-types.ts b/libs/importer/src/importers/onepassword/types/onepassword-1pux-importer-types.ts index 63a0427b2c7..d7f4dec8f95 100644 --- a/libs/importer/src/importers/onepassword/types/onepassword-1pux-importer-types.ts +++ b/libs/importer/src/importers/onepassword/types/onepassword-1pux-importer-types.ts @@ -25,6 +25,8 @@ export interface VaultAttributes { type: string; } +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum CategoryEnum { Login = "001", CreditCard = "002", @@ -67,6 +69,8 @@ export interface Details { password?: string | null; } +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum LoginFieldTypeEnum { TextOrHtml = "T", EmailAddress = "E", diff --git a/libs/importer/src/importers/protonpass/types/protonpass-json-type.ts b/libs/importer/src/importers/protonpass/types/protonpass-json-type.ts index 20fa314a314..af2eb15a740 100644 --- a/libs/importer/src/importers/protonpass/types/protonpass-json-type.ts +++ b/libs/importer/src/importers/protonpass/types/protonpass-json-type.ts @@ -27,6 +27,8 @@ export type ProtonPassItem = { pinned: boolean; }; +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum ProtonPassItemState { ACTIVE = 1, TRASHED = 2, diff --git a/libs/key-management-ui/src/lock/components/lock.component.ts b/libs/key-management-ui/src/lock/components/lock.component.ts index 80d64e17b84..3cb0dbaca52 100644 --- a/libs/key-management-ui/src/lock/components/lock.component.ts +++ b/libs/key-management-ui/src/lock/components/lock.component.ts @@ -556,6 +556,15 @@ export class LockComponent implements OnInit, OnDestroy { masterPasswordVerificationResponse!.masterKey, this.activeAccount.id, ); + if (userKey == null) { + this.toastService.showToast({ + variant: "error", + title: this.i18nService.t("errorOccurred"), + message: this.i18nService.t("invalidMasterPassword"), + }); + return; + } + await this.setUserKeyAndContinue(userKey, true); } diff --git a/libs/key-management/src/biometrics/biometrics-commands.ts b/libs/key-management/src/biometrics/biometrics-commands.ts index 81f0ea747e4..1ef31a31fb4 100644 --- a/libs/key-management/src/biometrics/biometrics-commands.ts +++ b/libs/key-management/src/biometrics/biometrics-commands.ts @@ -1,3 +1,5 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum BiometricsCommands { /** Perform biometric authentication for the system's user. Does not require setup, and does not return cryptographic material, only yes or no. */ AuthenticateWithBiometrics = "authenticateWithBiometrics", diff --git a/libs/key-management/src/biometrics/biometrics-status.ts b/libs/key-management/src/biometrics/biometrics-status.ts index fb46ed1c4be..e436574ff7d 100644 --- a/libs/key-management/src/biometrics/biometrics-status.ts +++ b/libs/key-management/src/biometrics/biometrics-status.ts @@ -1,3 +1,5 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum BiometricsStatus { /** For the biometrics interface, this means that biometric unlock is available and can be used. Querying for the user specifically, this means that biometric can be used for to unlock this user */ Available, diff --git a/libs/key-management/src/enums/kdf-type.enum.ts b/libs/key-management/src/enums/kdf-type.enum.ts index 29fcd9f1f8e..4f468e63a29 100644 --- a/libs/key-management/src/enums/kdf-type.enum.ts +++ b/libs/key-management/src/enums/kdf-type.enum.ts @@ -1,3 +1,5 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum KdfType { PBKDF2_SHA256 = 0, Argon2id = 1, diff --git a/libs/tools/export/vault-export/vault-export-ui/src/enums/encrypted-export-type.enum.ts b/libs/tools/export/vault-export/vault-export-ui/src/enums/encrypted-export-type.enum.ts index 4767869f7d0..2f416e4a49a 100644 --- a/libs/tools/export/vault-export/vault-export-ui/src/enums/encrypted-export-type.enum.ts +++ b/libs/tools/export/vault-export/vault-export-ui/src/enums/encrypted-export-type.enum.ts @@ -1,3 +1,5 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum EncryptedExportType { AccountEncrypted = 0, FileEncrypted = 1, diff --git a/libs/tools/send/send-ui/src/add-edit/send-add-edit-dialog.component.ts b/libs/tools/send/send-ui/src/add-edit/send-add-edit-dialog.component.ts index 5da2c6f8bed..0bb753d3f37 100644 --- a/libs/tools/send/send-ui/src/add-edit/send-add-edit-dialog.component.ts +++ b/libs/tools/send/send-ui/src/add-edit/send-add-edit-dialog.component.ts @@ -35,6 +35,8 @@ export interface SendItemDialogParams { disableForm?: boolean; } +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum SendItemDialogResult { /** * A Send was saved (created or updated). diff --git a/libs/tools/send/send-ui/src/send-form/components/send-details/send-details.component.ts b/libs/tools/send/send-ui/src/send-form/components/send-details/send-details.component.ts index c77c44467d8..9ca9aefb4ac 100644 --- a/libs/tools/send/send-ui/src/send-form/components/send-details/send-details.component.ts +++ b/libs/tools/send/send-ui/src/send-form/components/send-details/send-details.component.ts @@ -30,6 +30,8 @@ import { SendFileDetailsComponent } from "./send-file-details.component"; import { SendTextDetailsComponent } from "./send-text-details.component"; // Value = hours +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum DatePreset { OneHour = 1, OneDay = 24, diff --git a/libs/vault/src/cipher-form/cipher-form.stories.ts b/libs/vault/src/cipher-form/cipher-form.stories.ts index 9943f07292d..7090502ef14 100644 --- a/libs/vault/src/cipher-form/cipher-form.stories.ts +++ b/libs/vault/src/cipher-form/cipher-form.stories.ts @@ -13,7 +13,7 @@ import { import { BehaviorSubject } from "rxjs"; import { CollectionView } from "@bitwarden/admin-console/common"; -import { ViewCacheService } from "@bitwarden/angular/platform/abstractions/view-cache.service"; +import { ViewCacheService } from "@bitwarden/angular/platform/view-cache"; import { AuditService } from "@bitwarden/common/abstractions/audit.service"; import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; diff --git a/libs/vault/src/cipher-form/components/cipher-form.component.spec.ts b/libs/vault/src/cipher-form/components/cipher-form.component.spec.ts index 4c61ad5d2d5..da687f33ef9 100644 --- a/libs/vault/src/cipher-form/components/cipher-form.component.spec.ts +++ b/libs/vault/src/cipher-form/components/cipher-form.component.spec.ts @@ -3,7 +3,7 @@ import { ComponentFixture, TestBed } from "@angular/core/testing"; import { ReactiveFormsModule } from "@angular/forms"; import { mock } from "jest-mock-extended"; -import { ViewCacheService } from "@bitwarden/angular/platform/abstractions/view-cache.service"; +import { ViewCacheService } from "@bitwarden/angular/platform/view-cache"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { Cipher } from "@bitwarden/common/vault/models/domain/cipher"; diff --git a/libs/vault/src/cipher-form/services/default-cipher-form-cache.service.spec.ts b/libs/vault/src/cipher-form/services/default-cipher-form-cache.service.spec.ts index 6236e2d3dac..0dec46e1b20 100644 --- a/libs/vault/src/cipher-form/services/default-cipher-form-cache.service.spec.ts +++ b/libs/vault/src/cipher-form/services/default-cipher-form-cache.service.spec.ts @@ -1,7 +1,7 @@ import { signal } from "@angular/core"; import { TestBed } from "@angular/core/testing"; -import { ViewCacheService } from "@bitwarden/angular/platform/abstractions/view-cache.service"; +import { ViewCacheService } from "@bitwarden/angular/platform/view-cache"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; diff --git a/libs/vault/src/cipher-form/services/default-cipher-form-cache.service.ts b/libs/vault/src/cipher-form/services/default-cipher-form-cache.service.ts index 268b2db306b..b4a8138e025 100644 --- a/libs/vault/src/cipher-form/services/default-cipher-form-cache.service.ts +++ b/libs/vault/src/cipher-form/services/default-cipher-form-cache.service.ts @@ -1,6 +1,6 @@ import { inject, Injectable } from "@angular/core"; -import { ViewCacheService } from "@bitwarden/angular/platform/abstractions/view-cache.service"; +import { ViewCacheService } from "@bitwarden/angular/platform/view-cache"; import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; diff --git a/libs/vault/src/cipher-view/attachments/attachments-v2.component.ts b/libs/vault/src/cipher-view/attachments/attachments-v2.component.ts index 68660c4bbd9..b34d0d3a312 100644 --- a/libs/vault/src/cipher-view/attachments/attachments-v2.component.ts +++ b/libs/vault/src/cipher-view/attachments/attachments-v2.component.ts @@ -24,6 +24,8 @@ export interface AttachmentsDialogParams { /** * Enum representing the possible results of the attachment dialog. */ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum AttachmentDialogResult { Uploaded = "uploaded", Removed = "removed", diff --git a/libs/vault/src/components/add-edit-folder-dialog/add-edit-folder-dialog.component.ts b/libs/vault/src/components/add-edit-folder-dialog/add-edit-folder-dialog.component.ts index c8559799eec..dd3cbc4c5c9 100644 --- a/libs/vault/src/components/add-edit-folder-dialog/add-edit-folder-dialog.component.ts +++ b/libs/vault/src/components/add-edit-folder-dialog/add-edit-folder-dialog.component.ts @@ -34,6 +34,8 @@ import { } from "@bitwarden/components"; import { KeyService } from "@bitwarden/key-management"; +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum AddEditFolderDialogResult { Created = "created", Deleted = "deleted", diff --git a/libs/vault/src/components/assign-collections.component.ts b/libs/vault/src/components/assign-collections.component.ts index 45d25a037e9..6a0c45cfbe3 100644 --- a/libs/vault/src/components/assign-collections.component.ts +++ b/libs/vault/src/components/assign-collections.component.ts @@ -80,6 +80,8 @@ export interface CollectionAssignmentParams { isSingleCipherAdmin?: boolean; } +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum CollectionAssignmentResult { Saved = "saved", Canceled = "canceled", diff --git a/libs/vault/src/services/vault-nudges.service.ts b/libs/vault/src/services/vault-nudges.service.ts index be6e978eaa0..d27cd09e954 100644 --- a/libs/vault/src/services/vault-nudges.service.ts +++ b/libs/vault/src/services/vault-nudges.service.ts @@ -23,6 +23,8 @@ export type NudgeStatus = { /** * Enum to list the various nudge types, to be used by components/badges to show/hide the nudge */ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums export enum VaultNudgeType { /** Nudge to show when user has no items in their vault * Add future nudges here diff --git a/package-lock.json b/package-lock.json index a15275a695e..d1378d63ec3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,7 +27,7 @@ "@bitwarden/sdk-internal": "0.2.0-main.159", "@electron/fuses": "1.8.0", "@emotion/css": "11.13.5", - "@koa/multer": "3.0.2", + "@koa/multer": "3.1.0", "@koa/router": "13.1.0", "@microsoft/signalr": "8.0.7", "@microsoft/signalr-protocol-msgpack": "8.0.7", @@ -54,7 +54,7 @@ "lit": "3.2.1", "lowdb": "1.0.0", "lunr": "2.3.9", - "multer": "1.4.5-lts.1", + "multer": "1.4.5-lts.2", "ngx-toastr": "19.0.0", "node-fetch": "2.6.12", "node-forge": "1.3.1", @@ -91,6 +91,7 @@ "@storybook/addon-essentials": "8.6.12", "@storybook/addon-interactions": "8.6.12", "@storybook/addon-links": "8.6.12", + "@storybook/test-runner": "0.22.0", "@storybook/addon-themes": "8.6.12", "@storybook/angular": "8.6.12", "@storybook/manager-api": "8.6.12", @@ -123,6 +124,7 @@ "@yao-pkg/pkg": "5.16.1", "angular-eslint": "18.4.3", "autoprefixer": "10.4.21", + "axe-playwright": "2.1.0", "babel-loader": "9.2.1", "base64-loader": "1.0.0", "browserslist": "4.23.2", @@ -198,13 +200,14 @@ "version": "2025.4.0", "license": "SEE LICENSE IN LICENSE.txt", "dependencies": { - "@koa/multer": "3.0.2", + "@koa/multer": "3.1.0", "@koa/router": "13.1.0", "argon2": "0.41.1", "big-integer": "1.6.52", "browser-hrtime": "1.1.8", "chalk": "4.1.2", "commander": "11.1.0", + "core-js": "3.40.0", "form-data": "4.0.1", "https-proxy-agent": "7.0.6", "inquirer": "8.2.6", @@ -215,7 +218,7 @@ "koa-json": "2.0.2", "lowdb": "1.0.0", "lunr": "2.3.9", - "multer": "1.4.5-lts.1", + "multer": "1.4.5-lts.2", "node-fetch": "2.6.12", "node-forge": "1.3.1", "open": "8.4.2", @@ -387,6 +390,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, "license": "Apache-2.0", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", @@ -2743,6 +2747,7 @@ "version": "7.26.8", "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.8.tgz", "integrity": "sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -2752,6 +2757,7 @@ "version": "7.24.9", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.9.tgz", "integrity": "sha512-5e3FI4Q3M3Pbr21+5xJwCv6ZT6KmGkI0vw3Tozy5ODAQFTIWe37iT8Cr7Ice2Ntb+M3iSKCEWMB1MBgKrW3whg==", + "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", @@ -2782,12 +2788,14 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, "license": "MIT" }, "node_modules/@babel/core/node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -2797,6 +2805,7 @@ "version": "7.26.10", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.10.tgz", "integrity": "sha512-rRHT8siFIXQrAYOYqZQVsAr8vJ+cBNqcVAY6m5V8/4QqzaPl+zDBe6cLEPRDuNOUf3ww8RfJVlOyQMoSI+5Ang==", + "dev": true, "license": "MIT", "dependencies": { "@babel/parser": "^7.26.10", @@ -2826,6 +2835,7 @@ "version": "7.26.5", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.26.5.tgz", "integrity": "sha512-IXuyn5EkouFJscIDuFF5EsiSolseme1s0CZB+QxVugqJLYmKdxI1VfIBOst0SUu4rnk2Z7kqTwmoO1lp3HIfnA==", + "dev": true, "license": "MIT", "dependencies": { "@babel/compat-data": "^7.26.5", @@ -2842,6 +2852,7 @@ "version": "4.24.4", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz", "integrity": "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==", + "dev": true, "funding": [ { "type": "opencollective", @@ -2874,6 +2885,7 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -3013,6 +3025,7 @@ "version": "7.26.0", "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.25.9", @@ -3043,6 +3056,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -3146,6 +3160,7 @@ "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -3170,6 +3185,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.1.tgz", "integrity": "sha512-FCvFTm0sWV8Fxhpp2McP5/W53GPllQ9QeQ7SiqGWjMf/LVG07lFa5+pgK05IRhVwtvafT22KF+ZSnM9I545CvQ==", + "dev": true, "license": "MIT", "dependencies": { "@babel/template": "^7.27.1", @@ -3278,23 +3294,6 @@ "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-proposal-export-namespace-from": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz", - "integrity": "sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==", - "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-export-namespace-from instead.", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.9", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/plugin-proposal-private-property-in-object": { "version": "7.21.0-placeholder-for-preset-env.2", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", @@ -3327,7 +3326,6 @@ "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -3381,6 +3379,7 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.3" @@ -3453,7 +3452,6 @@ "integrity": "sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, @@ -3580,7 +3578,6 @@ "integrity": "sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, @@ -4011,6 +4008,7 @@ "version": "7.26.3", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.26.3.tgz", "integrity": "sha512-MgR55l4q9KddUDITEzEFYn5ZsGDXMSsU9E+kh7fjRXTIC3RHqfCo8RPRbyReYJh44HQ/yomFkqbOFohXvDCiIQ==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-module-transforms": "^7.26.0", @@ -4714,8 +4712,7 @@ "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@bitwarden/admin-console": { "resolved": "libs/admin-console", @@ -7179,7 +7176,6 @@ "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", "dev": true, "license": "ISC", - "peer": true, "dependencies": { "camelcase": "^5.3.1", "find-up": "^4.1.0", @@ -7197,7 +7193,6 @@ "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "sprintf-js": "~1.0.2" } @@ -7208,7 +7203,6 @@ "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" @@ -7223,7 +7217,6 @@ "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" @@ -7238,7 +7231,6 @@ "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "p-locate": "^4.1.0" }, @@ -7252,7 +7244,6 @@ "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "p-try": "^2.0.0" }, @@ -7269,7 +7260,6 @@ "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "p-limit": "^2.2.0" }, @@ -7283,7 +7273,6 @@ "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=8" } @@ -7293,8 +7282,7 @@ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", "dev": true, - "license": "BSD-3-Clause", - "peer": true + "license": "BSD-3-Clause" }, "node_modules/@istanbuljs/schema": { "version": "0.1.3", @@ -7312,7 +7300,6 @@ "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jest/types": "^29.6.3", "@types/node": "*", @@ -7331,7 +7318,6 @@ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=8" } @@ -7342,7 +7328,6 @@ "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jest/console": "^29.7.0", "@jest/reporters": "^29.7.0", @@ -7391,7 +7376,6 @@ "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=10" }, @@ -7405,7 +7389,6 @@ "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jest/schemas": "^29.6.3", "ansi-styles": "^5.0.0", @@ -7420,8 +7403,7 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@jest/core/node_modules/slash": { "version": "3.0.0", @@ -7429,11 +7411,23 @@ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=8" } }, + "node_modules/@jest/create-cache-key-function": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/create-cache-key-function/-/create-cache-key-function-29.7.0.tgz", + "integrity": "sha512-4QqS3LY5PBmTRHj9sAg1HLoPzqAI0uOX6wI/TRqHIcOxlFidy6YEmCQJk6FSZjNLGCeubDMfmkWL+qaLKhSGQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, "node_modules/@jest/environment": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", @@ -7456,7 +7450,6 @@ "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "expect": "^29.7.0", "jest-snapshot": "^29.7.0" @@ -7502,7 +7495,6 @@ "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jest/environment": "^29.7.0", "@jest/expect": "^29.7.0", @@ -7519,7 +7511,6 @@ "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@bcoe/v8-coverage": "^0.2.3", "@jest/console": "^29.7.0", @@ -7564,7 +7555,6 @@ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -7577,7 +7567,6 @@ "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, "license": "ISC", - "peer": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -7599,7 +7588,6 @@ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "license": "ISC", - "peer": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -7613,7 +7601,6 @@ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=8" } @@ -7637,7 +7624,6 @@ "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jridgewell/trace-mapping": "^0.3.18", "callsites": "^3.0.0", @@ -7653,7 +7639,6 @@ "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jest/console": "^29.7.0", "@jest/types": "^29.6.3", @@ -7670,7 +7655,6 @@ "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jest/test-result": "^29.7.0", "graceful-fs": "^4.2.9", @@ -7687,7 +7671,6 @@ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=8" } @@ -7698,7 +7681,6 @@ "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/core": "^7.11.6", "@jest/types": "^29.6.3", @@ -7725,8 +7707,7 @@ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@jest/transform/node_modules/slash": { "version": "3.0.0", @@ -7734,7 +7715,6 @@ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=8" } @@ -7874,15 +7854,12 @@ } }, "node_modules/@koa/multer": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@koa/multer/-/multer-3.0.2.tgz", - "integrity": "sha512-Q6WfPpE06mJWyZD1fzxM6zWywaoo+zocAn2YA9QYz4RsecoASr1h/kSzG0c5seDpFVKCMZM9raEfuM7XfqbRLw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@koa/multer/-/multer-3.1.0.tgz", + "integrity": "sha512-ETf4OLpOew9XE9lyU+5HIqk3TCmdGAw9pUXgxzrlYip+PkxLGoU4meiVTxiW4B6lxdBNijb3DFQ7M2woLcDL1g==", "license": "MIT", - "dependencies": { - "fix-esm": "1.0.1" - }, "engines": { - "node": ">= 8" + "node": ">= 14" }, "peerDependencies": { "multer": "*" @@ -10819,6 +10796,43 @@ "storybook": "^8.6.12" } }, + "node_modules/@storybook/test-runner": { + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@storybook/test-runner/-/test-runner-0.22.0.tgz", + "integrity": "sha512-fKY6MTE/bcvMaulKXy+z0fPmRXJx1REkYMOMcGn8zn6uffyBigGgaVf/sZ+AZfibwvjzg/StWhJ9HvAM8pc14g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.22.5", + "@babel/generator": "^7.22.5", + "@babel/template": "^7.22.5", + "@babel/types": "^7.22.5", + "@jest/types": "^29.6.3", + "@storybook/csf": "^0.1.11", + "@swc/core": "^1.5.22", + "@swc/jest": "^0.2.23", + "expect-playwright": "^0.8.0", + "jest": "^29.6.4", + "jest-circus": "^29.6.4", + "jest-environment-node": "^29.6.4", + "jest-junit": "^16.0.0", + "jest-playwright-preset": "^4.0.0", + "jest-runner": "^29.6.4", + "jest-serializer-html": "^7.1.0", + "jest-watch-typeahead": "^2.0.0", + "nyc": "^15.1.0", + "playwright": "^1.14.0" + }, + "bin": { + "test-storybook": "dist/test-storybook.js" + }, + "engines": { + "node": "^16.10.0 || ^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "storybook": "^0.0.0-0 || ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 || ^9.0.0-0" + } + }, "node_modules/@storybook/theming": { "version": "8.6.12", "resolved": "https://registry.npmjs.org/@storybook/theming/-/theming-8.6.12.tgz", @@ -10882,6 +10896,250 @@ "storybook": "^8.6.12" } }, + "node_modules/@swc/core": { + "version": "1.11.24", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.11.24.tgz", + "integrity": "sha512-MaQEIpfcEMzx3VWWopbofKJvaraqmL6HbLlw2bFZ7qYqYw3rkhM0cQVEgyzbHtTWwCwPMFZSC2DUbhlZgrMfLg==", + "dev": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.3", + "@swc/types": "^0.1.21" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/swc" + }, + "optionalDependencies": { + "@swc/core-darwin-arm64": "1.11.24", + "@swc/core-darwin-x64": "1.11.24", + "@swc/core-linux-arm-gnueabihf": "1.11.24", + "@swc/core-linux-arm64-gnu": "1.11.24", + "@swc/core-linux-arm64-musl": "1.11.24", + "@swc/core-linux-x64-gnu": "1.11.24", + "@swc/core-linux-x64-musl": "1.11.24", + "@swc/core-win32-arm64-msvc": "1.11.24", + "@swc/core-win32-ia32-msvc": "1.11.24", + "@swc/core-win32-x64-msvc": "1.11.24" + }, + "peerDependencies": { + "@swc/helpers": ">=0.5.17" + }, + "peerDependenciesMeta": { + "@swc/helpers": { + "optional": true + } + } + }, + "node_modules/@swc/core-darwin-arm64": { + "version": "1.11.24", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.11.24.tgz", + "integrity": "sha512-dhtVj0PC1APOF4fl5qT2neGjRLgHAAYfiVP8poJelhzhB/318bO+QCFWAiimcDoyMgpCXOhTp757gnoJJrheWA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-darwin-x64": { + "version": "1.11.24", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.11.24.tgz", + "integrity": "sha512-H/3cPs8uxcj2Fe3SoLlofN5JG6Ny5bl8DuZ6Yc2wr7gQFBmyBkbZEz+sPVgsID7IXuz7vTP95kMm1VL74SO5AQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm-gnueabihf": { + "version": "1.11.24", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.11.24.tgz", + "integrity": "sha512-PHJgWEpCsLo/NGj+A2lXZ2mgGjsr96ULNW3+T3Bj2KTc8XtMUkE8tmY2Da20ItZOvPNC/69KroU7edyo1Flfbw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-gnu": { + "version": "1.11.24", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.11.24.tgz", + "integrity": "sha512-C2FJb08+n5SD4CYWCTZx1uR88BN41ZieoHvI8A55hfVf2woT8+6ZiBzt74qW2g+ntZ535Jts5VwXAKdu41HpBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-musl": { + "version": "1.11.24", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.11.24.tgz", + "integrity": "sha512-ypXLIdszRo0re7PNNaXN0+2lD454G8l9LPK/rbfRXnhLWDBPURxzKlLlU/YGd2zP98wPcVooMmegRSNOKfvErw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-gnu": { + "version": "1.11.24", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.11.24.tgz", + "integrity": "sha512-IM7d+STVZD48zxcgo69L0yYptfhaaE9cMZ+9OoMxirNafhKKXwoZuufol1+alEFKc+Wbwp+aUPe/DeWC/Lh3dg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-musl": { + "version": "1.11.24", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.11.24.tgz", + "integrity": "sha512-DZByJaMVzSfjQKKQn3cqSeqwy6lpMaQDQQ4HPlch9FWtDx/dLcpdIhxssqZXcR2rhaQVIaRQsCqwV6orSDGAGw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-arm64-msvc": { + "version": "1.11.24", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.11.24.tgz", + "integrity": "sha512-Q64Ytn23y9aVDKN5iryFi8mRgyHw3/kyjTjT4qFCa8AEb5sGUuSj//AUZ6c0J7hQKMHlg9do5Etvoe61V98/JQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-ia32-msvc": { + "version": "1.11.24", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.11.24.tgz", + "integrity": "sha512-9pKLIisE/Hh2vJhGIPvSoTK4uBSPxNVyXHmOrtdDot4E1FUUI74Vi8tFdlwNbaj8/vusVnb8xPXsxF1uB0VgiQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-x64-msvc": { + "version": "1.11.24", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.11.24.tgz", + "integrity": "sha512-sybnXtOsdB+XvzVFlBVGgRHLqp3yRpHK7CrmpuDKszhj/QhmsaZzY/GHSeALlMtLup13M0gqbcQvsTNlAHTg3w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/counter": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", + "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/@swc/jest": { + "version": "0.2.38", + "resolved": "https://registry.npmjs.org/@swc/jest/-/jest-0.2.38.tgz", + "integrity": "sha512-HMoZgXWMqChJwffdDjvplH53g9G2ALQes3HKXDEdliB/b85OQ0CTSbxG8VSeCwiAn7cOaDVEt4mwmZvbHcS52w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/create-cache-key-function": "^29.7.0", + "@swc/counter": "^0.1.3", + "jsonc-parser": "^3.2.0" + }, + "engines": { + "npm": ">= 7.0.0" + }, + "peerDependencies": { + "@swc/core": "*" + } + }, + "node_modules/@swc/types": { + "version": "0.1.21", + "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.21.tgz", + "integrity": "sha512-2YEtj5HJVbKivud9N4bpPBAyZhj4S2Ipe5LkUG94alTpr7in/GU/EARgPAd3BwU+YOmFVJC2+kjqhGRi3r0ZpQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.3" + } + }, "node_modules/@szmarczak/http-timer": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", @@ -11102,7 +11360,6 @@ "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", @@ -11117,7 +11374,6 @@ "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/types": "^7.0.0" } @@ -11128,7 +11384,6 @@ "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/parser": "^7.1.0", "@babel/types": "^7.0.0" @@ -11140,7 +11395,6 @@ "integrity": "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/types": "^7.20.7" } @@ -11336,7 +11590,6 @@ "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/node": "*" } @@ -11506,6 +11759,13 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/junit-report-builder": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/junit-report-builder/-/junit-report-builder-3.0.2.tgz", + "integrity": "sha512-R5M+SYhMbwBeQcNXYWNCZkl09vkVfAtcPIaCGdzIkkbeaTrVbGQ7HVgi4s+EmM/M1K4ZuWQH0jGcvMvNePfxYA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/keygrip": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/@types/keygrip/-/keygrip-1.0.6.tgz", @@ -11908,6 +12168,16 @@ "license": "MIT", "optional": true }, + "node_modules/@types/wait-on": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/@types/wait-on/-/wait-on-5.3.4.tgz", + "integrity": "sha512-EBsPjFMrFlMbbUFf9D1Fp+PAB2TwmUn7a3YtHyD9RLuTIk1jDd8SxXVAoez2Ciy+8Jsceo2MYEYZzJ/DvorOKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/webpack-env": { "version": "1.18.8", "resolved": "https://registry.npmjs.org/@types/webpack-env/-/webpack-env-1.18.8.tgz", @@ -13845,6 +14115,19 @@ "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==", "license": "MIT" }, + "node_modules/append-transform": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz", + "integrity": "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==", + "dev": true, + "license": "MIT", + "dependencies": { + "default-require-extensions": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/archiver": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.2.tgz", @@ -13981,6 +14264,13 @@ "safe-buffer": "~5.1.0" } }, + "node_modules/archy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==", + "dev": true, + "license": "MIT" + }, "node_modules/arg": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", @@ -14356,6 +14646,39 @@ "node": ">=4" } }, + "node_modules/axe-html-reporter": { + "version": "2.2.11", + "resolved": "https://registry.npmjs.org/axe-html-reporter/-/axe-html-reporter-2.2.11.tgz", + "integrity": "sha512-WlF+xlNVgNVWiM6IdVrsh+N0Cw7qupe5HT9N6Uyi+aN7f6SSi92RDomiP1noW8OWIV85V6x404m5oKMeqRV3tQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mustache": "^4.0.1" + }, + "engines": { + "node": ">=8.9.0" + }, + "peerDependencies": { + "axe-core": ">=3" + } + }, + "node_modules/axe-playwright": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/axe-playwright/-/axe-playwright-2.1.0.tgz", + "integrity": "sha512-tY48SX56XaAp16oHPyD4DXpybz8Jxdz9P7exTjF/4AV70EGUavk+1fUPWirM0OYBR+YyDx6hUeDvuHVA6fB9YA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/junit-report-builder": "^3.0.2", + "axe-core": "^4.10.1", + "axe-html-reporter": "2.2.11", + "junit-report-builder": "^5.1.1", + "picocolors": "^1.1.1" + }, + "peerDependencies": { + "playwright": ">1.0.0" + } + }, "node_modules/axios": { "version": "1.8.4", "resolved": "https://registry.npmjs.org/axios/-/axios-1.8.4.tgz", @@ -14383,7 +14706,6 @@ "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jest/transform": "^29.7.0", "@types/babel__core": "^7.1.14", @@ -14406,7 +14728,6 @@ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=8" } @@ -14435,7 +14756,6 @@ "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", "dev": true, "license": "BSD-3-Clause", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@istanbuljs/load-nyc-config": "^1.0.0", @@ -14453,7 +14773,6 @@ "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", "dev": true, "license": "BSD-3-Clause", - "peer": true, "dependencies": { "@babel/core": "^7.12.3", "@babel/parser": "^7.14.7", @@ -14471,7 +14790,6 @@ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "license": "ISC", - "peer": true, "bin": { "semver": "bin/semver.js" } @@ -14482,7 +14800,6 @@ "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/template": "^7.3.3", "@babel/types": "^7.3.3", @@ -14600,7 +14917,6 @@ "integrity": "sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-bigint": "^7.8.3", @@ -14628,7 +14944,6 @@ "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "babel-plugin-jest-hoist": "^29.6.3", "babel-preset-current-node-syntax": "^1.0.0" @@ -15043,6 +15358,7 @@ "version": "4.23.2", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.2.tgz", "integrity": "sha512-qkqSyistMYdxAcw+CzbZwlBy8AGmS/eEWs+sEV5TnLRGDOL+C5M2EnH6tlZyg0YoAxGJAFKh61En9BR941GnHA==", + "dev": true, "funding": [ { "type": "opencollective", @@ -15090,7 +15406,6 @@ "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", "dev": true, "license": "Apache-2.0", - "peer": true, "dependencies": { "node-int64": "^0.4.0" } @@ -15471,6 +15786,68 @@ "node": ">=8" } }, + "node_modules/caching-transform": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz", + "integrity": "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasha": "^5.0.0", + "make-dir": "^3.0.0", + "package-hash": "^4.0.0", + "write-file-atomic": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/caching-transform/node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/caching-transform/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/caching-transform/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/caching-transform/node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, "node_modules/call-bind": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", @@ -15553,7 +15930,6 @@ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=6" } @@ -15572,6 +15948,7 @@ "version": "1.0.30001717", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001717.tgz", "integrity": "sha512-auPpttCq6BDEG8ZAuHJIplGw6GODhjw+/11e7IjpnYCxZcW/ONgPs0KVBJ0d1bY3e2+7PRe5RCLyP+PfwVgkYw==", + "dev": true, "funding": [ { "type": "opencollective", @@ -15670,7 +16047,6 @@ "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=10" } @@ -16037,8 +16413,7 @@ "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/color-convert": { "version": "2.0.1", @@ -16123,6 +16498,13 @@ "node": ">=4.0.0" } }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true, + "license": "MIT" + }, "node_modules/compare-version": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/compare-version/-/compare-version-0.1.2.tgz", @@ -16579,7 +16961,6 @@ "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.40.0.tgz", "integrity": "sha512-7vsMc/Lty6AGnn7uFpYT56QesI5D2Y/UkgKounk87OP9Z2H9Z8kj6jzcSGAxFmUtDOS0ntK6lbQz+Nsa0Jj6mQ==", "hasInstallScript": true, - "license": "MIT", "funding": { "type": "opencollective", "url": "https://opencollective.com/core-js" @@ -16751,7 +17132,6 @@ "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jest/types": "^29.6.3", "chalk": "^4.0.0", @@ -16942,6 +17322,20 @@ "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", "license": "MIT" }, + "node_modules/cwd": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/cwd/-/cwd-0.10.0.tgz", + "integrity": "sha512-YGZxdTTL9lmLkCUTpg4j0zQ7IhRB5ZmqNBbGCl3Tg6MP/d5/6sY7L5mmTjzbc6JKgVZYiqTQTNhPFsbXNGlRaA==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-pkg": "^0.1.2", + "fs-exists-sync": "^0.1.0" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/data-urls": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", @@ -17120,7 +17514,6 @@ "integrity": "sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==", "dev": true, "license": "MIT", - "peer": true, "peerDependencies": { "babel-plugin-macros": "^3.1.0" }, @@ -17216,6 +17609,22 @@ "node": ">= 10" } }, + "node_modules/default-require-extensions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.1.tgz", + "integrity": "sha512-eXTJmRbm2TIt9MgWTsOH1wEuhew6XGZcMeGKCtLedIg/NCsg1iBePXkceTdK4Fii7pzmN9tGsZhKzZ4h7O/fxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "strip-bom": "^4.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/defaults": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", @@ -17342,7 +17751,6 @@ "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=8" } @@ -17385,6 +17793,100 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/diffable-html": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/diffable-html/-/diffable-html-4.1.0.tgz", + "integrity": "sha512-++kyNek+YBLH8cLXS+iTj/Hiy2s5qkRJEJ8kgu/WHbFrVY2vz9xPFUT+fii2zGF0m1CaojDlQJjkfrCt7YWM1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "htmlparser2": "^3.9.2" + } + }, + "node_modules/diffable-html/node_modules/dom-serializer": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", + "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "domelementtype": "^2.0.1", + "entities": "^2.0.0" + } + }, + "node_modules/diffable-html/node_modules/dom-serializer/node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/diffable-html/node_modules/dom-serializer/node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true, + "license": "BSD-2-Clause", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/diffable-html/node_modules/domelementtype": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", + "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/diffable-html/node_modules/domhandler": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", + "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "1" + } + }, + "node_modules/diffable-html/node_modules/domutils": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", + "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "node_modules/diffable-html/node_modules/entities": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", + "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/diffable-html/node_modules/htmlparser2": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", + "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "domelementtype": "^1.3.1", + "domhandler": "^2.3.0", + "domutils": "^1.5.1", + "entities": "^1.1.1", + "inherits": "^2.0.1", + "readable-stream": "^3.1.1" + } + }, "node_modules/dir-compare": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/dir-compare/-/dir-compare-3.3.0.tgz", @@ -17977,6 +18479,7 @@ "version": "1.5.151", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.151.tgz", "integrity": "sha512-Rl6uugut2l9sLojjS4H4SAr3A4IgACMLgpuEMPYCVcKydzfyPrn5absNRju38IhQOf/NwjJY8OGWjlteqYeBCA==", + "dev": true, "license": "ISC" }, "node_modules/electron-updater": { @@ -18057,7 +18560,6 @@ "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -18382,8 +18884,7 @@ "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", "dev": true, - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/es6-shim": { "version": "0.35.8", @@ -18462,6 +18963,7 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -19185,7 +19687,6 @@ "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", "dev": true, - "peer": true, "engines": { "node": ">= 0.8.0" } @@ -19200,6 +19701,19 @@ "node": ">=6" } }, + "node_modules/expand-tilde": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-1.2.2.tgz", + "integrity": "sha512-rtmc+cjLZqnu9dSYosX9EWmSJhTwpACgJQTfj4hgg2JjOD/6SIQalZrt4a3aQeh++oNxkazcaxrhPUj6+g5G/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "os-homedir": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/expect": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", @@ -19217,6 +19731,24 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/expect-playwright": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/expect-playwright/-/expect-playwright-0.8.0.tgz", + "integrity": "sha512-+kn8561vHAY+dt+0gMqqj1oY+g5xWrsuGMk4QGxotT2WS545nVqqjs37z6hrYfIuucwqthzwJfCJUEYqixyljg==", + "dev": true, + "license": "MIT" + }, + "node_modules/expect-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.1.0.tgz", + "integrity": "sha512-bFi65yM+xZgk+u/KRIpekdSYkTB5W1pEf0Lt8Q8Msh7b+eQ7LXVtIB1Bkm4fvclDEL1b2CZkMhv2mOeF8tMdkA==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/exponential-backoff": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.2.tgz", @@ -19596,7 +20128,6 @@ "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", "dev": true, "license": "Apache-2.0", - "peer": true, "dependencies": { "bser": "2.1.1" } @@ -19771,6 +20302,58 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/find-file-up": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/find-file-up/-/find-file-up-0.1.3.tgz", + "integrity": "sha512-mBxmNbVyjg1LQIIpgO8hN+ybWBgDQK8qjht+EbrTCGmmPV/sc7RF1i9stPTD6bpvXZywBdrwRYxhSdJv867L6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "fs-exists-sync": "^0.1.0", + "resolve-dir": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/find-pkg": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/find-pkg/-/find-pkg-0.1.2.tgz", + "integrity": "sha512-0rnQWcFwZr7eO0513HahrWafsc3CTFioEB7DRiEYCUM/70QXSY8f3mCST17HXLcPvEhzH/Ty/Bxd72ZZsr/yvw==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-file-up": "^0.1.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/find-process": { + "version": "1.4.10", + "resolved": "https://registry.npmjs.org/find-process/-/find-process-1.4.10.tgz", + "integrity": "sha512-ncYFnWEIwL7PzmrK1yZtaccN8GhethD37RzBHG6iOZoFYB4vSmLLXfeWJjeN5nMvCJMjOtBvBBF8OgxEcikiZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "~4.1.2", + "commander": "^12.1.0", + "loglevel": "^1.9.2" + }, + "bin": { + "find-process": "bin/find-process.js" + } + }, + "node_modules/find-process/node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/find-root": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", @@ -19803,17 +20386,6 @@ "micromatch": "^4.0.2" } }, - "node_modules/fix-esm": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/fix-esm/-/fix-esm-1.0.1.tgz", - "integrity": "sha512-EZtb7wPXZS54GaGxaWxMlhd1DUDCnAg5srlYdu/1ZVeW+7wwR3Tp59nu52dXByFs3MBRq+SByx1wDOJpRvLEXw==", - "license": "WTFPL OR CC0-1.0", - "dependencies": { - "@babel/core": "^7.14.6", - "@babel/plugin-proposal-export-namespace-from": "^7.14.5", - "@babel/plugin-transform-modules-commonjs": "^7.14.5" - } - }, "node_modules/flat": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", @@ -20305,6 +20877,27 @@ "safe-buffer": "~5.1.0" } }, + "node_modules/fromentries": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz", + "integrity": "sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/front-matter": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/front-matter/-/front-matter-4.0.2.tgz", @@ -20349,6 +20942,16 @@ "dev": true, "license": "MIT" }, + "node_modules/fs-exists-sync": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz", + "integrity": "sha512-cR/vflFyPZtrN6b38ZyWxpWdhlXrzZEBawlpBQMq7033xVY7/kg0GDMBK5jg8lDYQckdJ5x/YC88lM3C7VMsLg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/fs-extra": { "version": "11.3.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.0.tgz", @@ -20469,6 +21072,7 @@ "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -20527,7 +21131,6 @@ "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=8.0.0" } @@ -20678,6 +21281,56 @@ "node": ">=10.0" } }, + "node_modules/global-modules": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-0.2.3.tgz", + "integrity": "sha512-JeXuCbvYzYXcwE6acL9V2bAOeSIGl4dD+iwLY9iUx2VBJJ80R18HCn+JCwHM9Oegdfya3lEkGCdaRkSyc10hDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "global-prefix": "^0.1.4", + "is-windows": "^0.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/global-prefix": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-0.1.5.tgz", + "integrity": "sha512-gOPiyxcD9dJGCEArAhF4Hd0BAqvAe/JzERP7tYumE4yIkmIedPUVXcJFWbV3/p/ovIIvKjkrTk+f1UVkq7vvbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "homedir-polyfill": "^1.0.0", + "ini": "^1.3.4", + "is-windows": "^0.2.0", + "which": "^1.2.12" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/global-prefix/node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true, + "license": "ISC" + }, + "node_modules/global-prefix/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, "node_modules/globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", @@ -20942,6 +21595,33 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/hasha": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz", + "integrity": "sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-stream": "^2.0.0", + "type-fest": "^0.8.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/hasha/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=8" + } + }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", @@ -20964,6 +21644,19 @@ "he": "bin/he" } }, + "node_modules/homedir-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "parse-passwd": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/hosted-git-info": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", @@ -21084,8 +21777,7 @@ "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/html-loader": { "version": "5.1.0", @@ -22170,7 +22862,6 @@ "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=6" } @@ -22475,6 +23166,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "dev": true, + "license": "MIT" + }, "node_modules/is-unicode-supported": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", @@ -22540,6 +23238,16 @@ "dev": true, "license": "MIT" }, + "node_modules/is-windows": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-0.2.0.tgz", + "integrity": "sha512-n67eJYmXbniZB7RF4I/FTjK1s6RPOCTxhYrVYLRaCt3lF0mpWZPKr3T2LSZAqyjQsxR2qMmGYXXzK0YWwcPM1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-wsl": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", @@ -22597,6 +23305,19 @@ "node": ">=8" } }, + "node_modules/istanbul-lib-hook": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz", + "integrity": "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "append-transform": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/istanbul-lib-instrument": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", @@ -22614,13 +23335,116 @@ "node": ">=10" } }, + "node_modules/istanbul-lib-processinfo": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.3.tgz", + "integrity": "sha512-NkwHbo3E00oybX6NGJi6ar0B29vxyvNwoC7eJ4G4Yq28UfY758Hgn/heV8VRFhevPED4LXfFz0DQ8z/0kw9zMg==", + "dev": true, + "license": "ISC", + "dependencies": { + "archy": "^1.0.0", + "cross-spawn": "^7.0.3", + "istanbul-lib-coverage": "^3.2.0", + "p-map": "^3.0.0", + "rimraf": "^3.0.0", + "uuid": "^8.3.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-processinfo/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/istanbul-lib-processinfo/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/istanbul-lib-processinfo/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/istanbul-lib-processinfo/node_modules/p-map": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", + "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-processinfo/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/istanbul-lib-processinfo/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/istanbul-lib-report": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", "dev": true, "license": "BSD-3-Clause", - "peer": true, "dependencies": { "istanbul-lib-coverage": "^3.0.0", "make-dir": "^4.0.0", @@ -22636,7 +23460,6 @@ "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", "dev": true, "license": "BSD-3-Clause", - "peer": true, "dependencies": { "debug": "^4.1.1", "istanbul-lib-coverage": "^3.0.0", @@ -22652,7 +23475,6 @@ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, "license": "BSD-3-Clause", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -22663,7 +23485,6 @@ "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", "dev": true, "license": "BSD-3-Clause", - "peer": true, "dependencies": { "html-escaper": "^2.0.0", "istanbul-lib-report": "^3.0.0" @@ -22737,7 +23558,6 @@ "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jest/core": "^29.7.0", "@jest/types": "^29.6.3", @@ -22765,7 +23585,6 @@ "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "execa": "^5.0.0", "jest-util": "^29.7.0", @@ -22781,7 +23600,6 @@ "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jest/environment": "^29.7.0", "@jest/expect": "^29.7.0", @@ -22814,7 +23632,6 @@ "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=10" }, @@ -22828,7 +23645,6 @@ "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jest/schemas": "^29.6.3", "ansi-styles": "^5.0.0", @@ -22843,8 +23659,7 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/jest-circus/node_modules/slash": { "version": "3.0.0", @@ -22852,7 +23667,6 @@ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=8" } @@ -22863,7 +23677,6 @@ "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jest/core": "^29.7.0", "@jest/test-result": "^29.7.0", @@ -22898,7 +23711,6 @@ "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/core": "^7.11.6", "@jest/test-sequencer": "^29.7.0", @@ -22945,7 +23757,6 @@ "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=10" }, @@ -22959,7 +23770,6 @@ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -22972,7 +23782,6 @@ "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, "license": "ISC", - "peer": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -22994,7 +23803,6 @@ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "license": "ISC", - "peer": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -23008,7 +23816,6 @@ "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jest/schemas": "^29.6.3", "ansi-styles": "^5.0.0", @@ -23023,8 +23830,7 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/jest-config/node_modules/slash": { "version": "3.0.0", @@ -23032,7 +23838,6 @@ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=8" } @@ -23094,7 +23899,6 @@ "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "detect-newline": "^3.0.0" }, @@ -23108,7 +23912,6 @@ "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jest/types": "^29.6.3", "chalk": "^4.0.0", @@ -23126,7 +23929,6 @@ "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=10" }, @@ -23140,7 +23942,6 @@ "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jest/schemas": "^29.6.3", "ansi-styles": "^5.0.0", @@ -23155,8 +23956,7 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/jest-environment-jsdom": { "version": "29.7.0", @@ -23385,7 +24185,6 @@ "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jest/environment": "^29.7.0", "@jest/fake-timers": "^29.7.0", @@ -23414,7 +24213,6 @@ "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jest/types": "^29.6.3", "@types/graceful-fs": "^4.1.3", @@ -23467,7 +24265,6 @@ "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "jest-get-type": "^29.6.3", "pretty-format": "^29.7.0" @@ -23482,7 +24279,6 @@ "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=10" }, @@ -23496,7 +24292,6 @@ "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jest/schemas": "^29.6.3", "ansi-styles": "^5.0.0", @@ -23511,8 +24306,7 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/jest-matcher-utils": { "version": "29.7.0", @@ -23660,13 +24454,106 @@ "typescript": "^3.0.0 || ^4.0.0 || ^5.0.0" } }, + "node_modules/jest-playwright-preset": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jest-playwright-preset/-/jest-playwright-preset-4.0.0.tgz", + "integrity": "sha512-+dGZ1X2KqtwXaabVjTGxy0a3VzYfvYsWaRcuO8vMhyclHSOpGSI1+5cmlqzzCwQ3+fv0EjkTc7I5aV9lo08dYw==", + "dev": true, + "license": "MIT", + "dependencies": { + "expect-playwright": "^0.8.0", + "jest-process-manager": "^0.4.0", + "nyc": "^15.1.0", + "playwright-core": ">=1.2.0", + "rimraf": "^3.0.2", + "uuid": "^8.3.2" + }, + "peerDependencies": { + "jest": "^29.3.1", + "jest-circus": "^29.3.1", + "jest-environment-node": "^29.3.1", + "jest-runner": "^29.3.1" + } + }, + "node_modules/jest-playwright-preset/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/jest-playwright-preset/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/jest-playwright-preset/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/jest-playwright-preset/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/jest-playwright-preset/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/jest-pnp-resolver": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=6" }, @@ -23743,13 +24630,58 @@ "dev": true, "license": "MIT" }, + "node_modules/jest-process-manager": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/jest-process-manager/-/jest-process-manager-0.4.0.tgz", + "integrity": "sha512-80Y6snDyb0p8GG83pDxGI/kQzwVTkCxc7ep5FPe/F6JYdvRDhwr6RzRmPSP7SEwuLhxo80lBS/NqOdUIbHIfhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/wait-on": "^5.2.0", + "chalk": "^4.1.0", + "cwd": "^0.10.0", + "exit": "^0.1.2", + "find-process": "^1.4.4", + "prompts": "^2.4.1", + "signal-exit": "^3.0.3", + "spawnd": "^5.0.0", + "tree-kill": "^1.2.2", + "wait-on": "^7.0.0" + } + }, + "node_modules/jest-process-manager/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/jest-process-manager/node_modules/wait-on": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-7.2.0.tgz", + "integrity": "sha512-wCQcHkRazgjG5XoAq9jbTMLpNIjoSlZslrJ2+N9MxDsGEv1HnFoVjOCexL0ESva7Y9cu350j+DWADdk54s4AFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "axios": "^1.6.1", + "joi": "^17.11.0", + "lodash": "^4.17.21", + "minimist": "^1.2.8", + "rxjs": "^7.8.1" + }, + "bin": { + "wait-on": "bin/wait-on" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/jest-regex-util": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } @@ -23760,7 +24692,6 @@ "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "chalk": "^4.0.0", "graceful-fs": "^4.2.9", @@ -23782,7 +24713,6 @@ "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "jest-regex-util": "^29.6.3", "jest-snapshot": "^29.7.0" @@ -23797,7 +24727,6 @@ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=8" } @@ -23808,7 +24737,6 @@ "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jest/console": "^29.7.0", "@jest/environment": "^29.7.0", @@ -23842,7 +24770,6 @@ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, "license": "BSD-3-Clause", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -23853,7 +24780,6 @@ "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -23865,7 +24791,6 @@ "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jest/environment": "^29.7.0", "@jest/fake-timers": "^29.7.0", @@ -23900,7 +24825,6 @@ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -23913,7 +24837,6 @@ "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, "license": "ISC", - "peer": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -23935,7 +24858,6 @@ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "license": "ISC", - "peer": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -23949,18 +24871,26 @@ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=8" } }, + "node_modules/jest-serializer-html": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/jest-serializer-html/-/jest-serializer-html-7.1.0.tgz", + "integrity": "sha512-xYL2qC7kmoYHJo8MYqJkzrl/Fdlx+fat4U1AqYg+kafqwcKPiMkOcjWHPKhueuNEgr+uemhGc+jqXYiwCyRyLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "diffable-html": "^4.1.0" + } + }, "node_modules/jest-snapshot": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/core": "^7.11.6", "@babel/generator": "^7.7.2", @@ -23993,7 +24923,6 @@ "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=10" }, @@ -24007,7 +24936,6 @@ "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jest/schemas": "^29.6.3", "ansi-styles": "^5.0.0", @@ -24022,8 +24950,7 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/jest-util": { "version": "29.7.0", @@ -24062,7 +24989,6 @@ "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jest/types": "^29.6.3", "camelcase": "^6.2.0", @@ -24081,7 +25007,6 @@ "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=10" }, @@ -24095,7 +25020,6 @@ "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=10" }, @@ -24109,7 +25033,6 @@ "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jest/schemas": "^29.6.3", "ansi-styles": "^5.0.0", @@ -24124,8 +25047,111 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", "dev": true, + "license": "MIT" + }, + "node_modules/jest-watch-typeahead": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/jest-watch-typeahead/-/jest-watch-typeahead-2.2.2.tgz", + "integrity": "sha512-+QgOFW4o5Xlgd6jGS5X37i08tuuXNW8X0CV9WNFi+3n8ExCIP+E1melYhvYLjv5fE6D0yyzk74vsSO8I6GqtvQ==", + "dev": true, "license": "MIT", - "peer": true + "dependencies": { + "ansi-escapes": "^6.0.0", + "chalk": "^5.2.0", + "jest-regex-util": "^29.0.0", + "jest-watcher": "^29.0.0", + "slash": "^5.0.0", + "string-length": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": "^14.17.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "jest": "^27.0.0 || ^28.0.0 || ^29.0.0" + } + }, + "node_modules/jest-watch-typeahead/node_modules/ansi-escapes": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.2.1.tgz", + "integrity": "sha512-4nJ3yixlEthEJ9Rk4vPcdBRkZvQZlYyu8j4/Mqz5sgIkddmEnH2Yj2ZrnP9S3tQOvSNRUIgVNF/1yPpRAGNRig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-watch-typeahead/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/jest-watch-typeahead/node_modules/chalk": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz", + "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-watch-typeahead/node_modules/char-regex": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-2.0.2.tgz", + "integrity": "sha512-cbGOjAptfM2LVmWhwRFHEKTPkLwNddVmuqYZQt895yXwAsWsXObCG+YN4DGQ/JBtT4GP1a1lPPdio2z413LmTg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.20" + } + }, + "node_modules/jest-watch-typeahead/node_modules/string-length": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-5.0.1.tgz", + "integrity": "sha512-9Ep08KAMUn0OadnVaBuRdE2l615CQ508kr0XMadjClfYpdCyvrbFp6Taebo8yyxokQ4viUd/xPPUA4FGgUa0ow==", + "dev": true, + "license": "MIT", + "dependencies": { + "char-regex": "^2.0.0", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-watch-typeahead/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } }, "node_modules/jest-watcher": { "version": "29.7.0", @@ -24133,7 +25159,6 @@ "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jest/test-result": "^29.7.0", "@jest/types": "^29.6.3", @@ -24154,7 +25179,6 @@ "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/node": "*", "jest-util": "^29.7.0", @@ -24171,7 +25195,6 @@ "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -24418,6 +25441,7 @@ "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, "license": "MIT", "bin": { "json5": "lib/cli.js" @@ -24518,6 +25542,47 @@ "safe-buffer": "~5.1.0" } }, + "node_modules/junit-report-builder": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/junit-report-builder/-/junit-report-builder-5.1.1.tgz", + "integrity": "sha512-ZNOIIGMzqCGcHQEA2Q4rIQQ3Df6gSIfne+X9Rly9Bc2y55KxAZu8iGv+n2pP0bLf0XAOctJZgeloC54hWzCahQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash": "^4.17.21", + "make-dir": "^3.1.0", + "xmlbuilder": "^15.1.1" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/junit-report-builder/node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/junit-report-builder/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/jwt-decode": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz", @@ -24897,7 +25962,6 @@ "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=6" } @@ -25602,6 +26666,13 @@ "license": "MIT", "peer": true }, + "node_modules/lodash.flattendeep": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", + "integrity": "sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==", + "dev": true, + "license": "MIT" + }, "node_modules/lodash.isequal": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", @@ -25951,6 +27022,7 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, "license": "ISC", "dependencies": { "yallist": "^3.0.2" @@ -26001,7 +27073,6 @@ "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "semver": "^7.5.3" }, @@ -26097,7 +27168,6 @@ "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", "dev": true, "license": "BSD-3-Clause", - "peer": true, "dependencies": { "tmpl": "1.0.5" } @@ -27519,9 +28589,9 @@ } }, "node_modules/multer": { - "version": "1.4.5-lts.1", - "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.5-lts.1.tgz", - "integrity": "sha512-ywPWvcDMeH+z9gQq5qYHCCy+ethsk4goepZ45GLD63fOu0YcNecQxi64nDs3qluZB+murG3/D4dJ7+dGctcCQQ==", + "version": "1.4.5-lts.2", + "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.5-lts.2.tgz", + "integrity": "sha512-VzGiVigcG9zUAoCNU+xShztrlr1auZOlurXynNvO9GiWD1/mTBbUljOKY+qMeazBqXgRnjzeEgJI/wyjJUHg9A==", "license": "MIT", "dependencies": { "append-field": "^1.0.0", @@ -27587,6 +28657,16 @@ "readable-stream": "^3.6.0" } }, + "node_modules/mustache": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", + "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==", + "dev": true, + "license": "MIT", + "bin": { + "mustache": "bin/mustache" + } + }, "node_modules/mute-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz", @@ -28164,8 +29244,7 @@ "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/node-machine-id": { "version": "1.1.12", @@ -28173,10 +29252,24 @@ "integrity": "sha512-QNABxbrPa3qEIfrE6GOJ7BYIuignnJw7iQ2YPbc3Nla1HzRJjXzZOiikfF8m7eAMfichLt3M4VgLOetqgDmgGQ==", "dev": true }, + "node_modules/node-preload": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", + "integrity": "sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "process-on-spawn": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/node-releases": { "version": "2.0.19", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", + "dev": true, "license": "MIT" }, "node_modules/nopt": { @@ -28844,6 +29937,350 @@ "node": ">=6" } }, + "node_modules/nyc": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz", + "integrity": "sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==", + "dev": true, + "license": "ISC", + "dependencies": { + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "caching-transform": "^4.0.0", + "convert-source-map": "^1.7.0", + "decamelize": "^1.2.0", + "find-cache-dir": "^3.2.0", + "find-up": "^4.1.0", + "foreground-child": "^2.0.0", + "get-package-type": "^0.1.0", + "glob": "^7.1.6", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-hook": "^3.0.0", + "istanbul-lib-instrument": "^4.0.0", + "istanbul-lib-processinfo": "^2.0.2", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.0.2", + "make-dir": "^3.0.0", + "node-preload": "^0.2.1", + "p-map": "^3.0.0", + "process-on-spawn": "^1.0.0", + "resolve-from": "^5.0.0", + "rimraf": "^3.0.0", + "signal-exit": "^3.0.2", + "spawn-wrap": "^2.0.0", + "test-exclude": "^6.0.0", + "yargs": "^15.0.2" + }, + "bin": { + "nyc": "bin/nyc.js" + }, + "engines": { + "node": ">=8.9" + } + }, + "node_modules/nyc/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/nyc/node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/nyc/node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nyc/node_modules/find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "dev": true, + "license": "MIT", + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + } + }, + "node_modules/nyc/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/foreground-child": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", + "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/nyc/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/nyc/node_modules/istanbul-lib-instrument": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", + "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.7.5", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.0.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nyc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/nyc/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nyc/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/p-map": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", + "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/nyc/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/nyc/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/nyc/node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/nyc/node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -29113,6 +30550,16 @@ "dev": true, "license": "MIT" }, + "node_modules/os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/os-name": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/os-name/-/os-name-4.0.1.tgz", @@ -29270,6 +30717,22 @@ "node": ">=6" } }, + "node_modules/package-hash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz", + "integrity": "sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "graceful-fs": "^4.1.15", + "hasha": "^5.0.0", + "lodash.flattendeep": "^4.4.0", + "release-zalgo": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/package-json-from-dist": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", @@ -29551,6 +31014,16 @@ "node": ">= 0.10" } }, + "node_modules/parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/parse5": { "version": "7.2.1", "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.2.1.tgz", @@ -30112,6 +31585,53 @@ "node": ">=4" } }, + "node_modules/playwright": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.52.0.tgz", + "integrity": "sha512-JAwMNMBlxJ2oD1kce4KPtMkDeKGHQstdpFPcPH3maElAXon/QZeTvtsfXmTMRyO9TslfoYOXkSsvao2nE1ilTw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.52.0" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.52.0.tgz", + "integrity": "sha512-l2osTgLXSMeuLZOML9qYODUQoPPnUsKsb5/P6LJ2e6uPKXUdPK5WYhN4z03G+YNbWmGDY4YENauNu4ZKczreHg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/playwright/node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/plist": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/plist/-/plist-3.1.0.tgz", @@ -30634,6 +32154,19 @@ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "license": "MIT" }, + "node_modules/process-on-spawn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.1.0.tgz", + "integrity": "sha512-JOnOPQ/8TZgjs1JIH/m9ni7FfimjNa/PRx7y/Wb5qdItsnhO0jE4AT7fC0HjC28DUQWDr50dwSYZLdRMlqDq3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "fromentries": "^1.2.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/progress": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", @@ -30808,8 +32341,7 @@ "url": "https://opencollective.com/fast-check" } ], - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/qrcode-parser": { "version": "2.1.3", @@ -31308,6 +32840,19 @@ "node": ">= 0.10" } }, + "node_modules/release-zalgo": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", + "integrity": "sha512-gUAyHVHPPC5wdqX/LG4LWtRYtgjxyX78oanFNTMMyFEfOqdC54s3eE82imuWKbOeqYht2CrNf64Qb8vgmmtZGA==", + "dev": true, + "license": "ISC", + "dependencies": { + "es6-error": "^4.0.1" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/remark-gfm": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.1.tgz", @@ -31487,6 +33032,13 @@ "node": ">=0.10.0" } }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true, + "license": "ISC" + }, "node_modules/requireindex": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/requireindex/-/requireindex-1.2.0.tgz", @@ -31550,6 +33102,20 @@ "node": ">=8" } }, + "node_modules/resolve-dir": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-0.1.1.tgz", + "integrity": "sha512-QxMPqI6le2u0dCLyiGzgy92kjkkL6zO0XyvHzjdTNH3zM6e5Hz3BwG6+aEyNgiQ5Xz6PwTwgQEj3U50dByPKIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "expand-tilde": "^1.2.2", + "global-modules": "^0.2.3" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -32444,6 +34010,13 @@ "node": ">= 0.8" } }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "dev": true, + "license": "ISC" + }, "node_modules/set-cookie-parser": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz", @@ -32888,6 +34461,164 @@ "node": ">=0.10.0" } }, + "node_modules/spawn-wrap": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz", + "integrity": "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^2.0.0", + "is-windows": "^1.0.2", + "make-dir": "^3.0.0", + "rimraf": "^3.0.0", + "signal-exit": "^3.0.2", + "which": "^2.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/spawn-wrap/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/spawn-wrap/node_modules/foreground-child": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", + "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/spawn-wrap/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/spawn-wrap/node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/spawn-wrap/node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/spawn-wrap/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/spawn-wrap/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/spawn-wrap/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/spawn-wrap/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/spawnd": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/spawnd/-/spawnd-5.0.0.tgz", + "integrity": "sha512-28+AJr82moMVWolQvlAIv3JcYDkjkFTEmfDc503wxrF5l2rQ3dFz6DpbXp3kD4zmgGGldfM4xM4v1sFj/ZaIOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "exit": "^0.1.2", + "signal-exit": "^3.0.3", + "tree-kill": "^1.2.2", + "wait-port": "^0.2.9" + } + }, + "node_modules/spawnd/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, "node_modules/spdx-correct": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", @@ -33234,7 +34965,6 @@ "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "char-regex": "^1.0.2", "strip-ansi": "^6.0.0" @@ -33364,7 +35094,6 @@ "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=8" } @@ -33927,7 +35656,6 @@ "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", "dev": true, "license": "ISC", - "peer": true, "dependencies": { "@istanbuljs/schema": "^0.1.2", "glob": "^7.1.4", @@ -33943,7 +35671,6 @@ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -33956,7 +35683,6 @@ "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, "license": "ISC", - "peer": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -33978,7 +35704,6 @@ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "license": "ISC", - "peer": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -34148,8 +35873,7 @@ "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", "dev": true, - "license": "BSD-3-Clause", - "peer": true + "license": "BSD-3-Clause" }, "node_modules/to-regex-range": { "version": "5.0.1", @@ -34899,6 +36623,16 @@ "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", "license": "MIT" }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, "node_modules/typescript": { "version": "5.4.2", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.2.tgz", @@ -35346,6 +37080,7 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", + "dev": true, "funding": [ { "type": "opencollective", @@ -35490,7 +37225,6 @@ "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", "dev": true, "license": "ISC", - "peer": true, "dependencies": { "@jridgewell/trace-mapping": "^0.3.12", "@types/istanbul-lib-coverage": "^2.0.1", @@ -35505,8 +37239,7 @@ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/validate-npm-package-license": { "version": "3.0.4", @@ -36131,6 +37864,109 @@ "tslib": "^2.1.0" } }, + "node_modules/wait-port": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/wait-port/-/wait-port-0.2.14.tgz", + "integrity": "sha512-kIzjWcr6ykl7WFbZd0TMae8xovwqcqbx6FM9l+7agOgUByhzdjfzZBPK2CPufldTOMxbUivss//Sh9MFawmPRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^2.4.2", + "commander": "^3.0.2", + "debug": "^4.1.1" + }, + "bin": { + "wait-port": "bin/wait-port.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wait-port/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/wait-port/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/wait-port/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/wait-port/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true, + "license": "MIT" + }, + "node_modules/wait-port/node_modules/commander": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/commander/-/commander-3.0.2.tgz", + "integrity": "sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==", + "dev": true, + "license": "MIT" + }, + "node_modules/wait-port/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/wait-port/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/wait-port/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/walk-up-path": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/walk-up-path/-/walk-up-path-3.0.1.tgz", @@ -36144,7 +37980,6 @@ "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", "dev": true, "license": "Apache-2.0", - "peer": true, "dependencies": { "makeerror": "1.0.12" } @@ -36883,6 +38718,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/which-module": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", + "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", + "dev": true, + "license": "ISC" + }, "node_modules/which-typed-array": { "version": "1.1.18", "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.18.tgz", @@ -37030,7 +38872,6 @@ "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", "dev": true, "license": "ISC", - "peer": true, "dependencies": { "imurmurhash": "^0.1.4", "signal-exit": "^3.0.7" @@ -37044,8 +38885,7 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true, - "license": "ISC", - "peer": true + "license": "ISC" }, "node_modules/ws": { "version": "8.18.1", @@ -37123,6 +38963,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, "license": "ISC" }, "node_modules/yaml": { diff --git a/package.json b/package.json index 904ae121cc9..2993707313f 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,8 @@ "storybook": "ng run components:storybook", "build-storybook": "ng run components:build-storybook", "build-storybook:ci": "ng run components:build-storybook --webpack-stats-json", + "test-stories": "test-storybook --url http://localhost:6006", + "test-stories:watch": "test-stories --watch", "postinstall": "patch-package" }, "workspaces": [ @@ -53,6 +55,7 @@ "@storybook/addon-essentials": "8.6.12", "@storybook/addon-interactions": "8.6.12", "@storybook/addon-links": "8.6.12", + "@storybook/test-runner": "0.22.0", "@storybook/addon-themes": "8.6.12", "@storybook/angular": "8.6.12", "@storybook/manager-api": "8.6.12", @@ -85,6 +88,7 @@ "@yao-pkg/pkg": "5.16.1", "angular-eslint": "18.4.3", "autoprefixer": "10.4.21", + "axe-playwright": "2.1.0", "babel-loader": "9.2.1", "base64-loader": "1.0.0", "browserslist": "4.23.2", @@ -159,7 +163,7 @@ "@bitwarden/sdk-internal": "0.2.0-main.159", "@electron/fuses": "1.8.0", "@emotion/css": "11.13.5", - "@koa/multer": "3.0.2", + "@koa/multer": "3.1.0", "@koa/router": "13.1.0", "@microsoft/signalr": "8.0.7", "@microsoft/signalr-protocol-msgpack": "8.0.7", @@ -186,7 +190,7 @@ "lit": "3.2.1", "lowdb": "1.0.0", "lunr": "2.3.9", - "multer": "1.4.5-lts.1", + "multer": "1.4.5-lts.2", "ngx-toastr": "19.0.0", "node-fetch": "2.6.12", "node-forge": "1.3.1", diff --git a/tsconfig.eslint.json b/tsconfig.eslint.json index 7ffa34df58c..e8c3f669c0c 100644 --- a/tsconfig.eslint.json +++ b/tsconfig.eslint.json @@ -45,6 +45,7 @@ "files": [ ".storybook/main.ts", ".storybook/manager.js", + ".storybook/test-runner.ts", "apps/browser/src/autofill/content/components/.lit-storybook/main.ts" ], "include": ["apps/**/*", "libs/**/*", "bitwarden_license/**/*", "scripts/**/*"],