mirror of
https://github.com/bitwarden/browser
synced 2025-12-19 09:43:23 +00:00
* Remove DDG forwarder from SH (#3888) * [EC-272] Web workers using EncryptionService (#3532) * Add item decryption to encryptService * Create multithreadEncryptService subclass to handle web workers * Create encryption web worker * Refactor cipherService to use new interface * Update dependencies * Don't refresh org vault on filter change (#3879) * Autosync the updated translations (#3914) Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com> * Autosync the updated translations (#3915) Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com> * Autosync the updated translations (#3916) Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com> * Revert "[PS-1465] Fix #2806 - The "Import Data" page's file selector button cannot be translated (#3502)" (#3900) This reverts commit768de03269. * Autosync the updated translations (#3919) Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com> * [SM-260] Hide email verification prompt if already verified (#3922) Co-authored-by: Sammy Chang <sammychang2185@gmail.com> * Two-Step Login (#3852) * [SG-163] Two step login flow web (#3648) * two step login flow * moved code from old branch and reafctored * fixed review comments * [SG-164] Two Step Login Flow - Browser (#3793) * Add new messages * Remove SSO button from home component * Change create account button to text * Add top padding to create account link * Add email input to HomeComponent * Add continue button to email input * Add form to home component * Retreive email from state service * Redirect to login after submit * Add error message for invalid email * Remove email input from login component * Remove loggingInTo from under MP input * Style the MP hint link * Add self hosted domain to email form * Made the mp hint link bold * Add the new login button * Style app-private-mode-warning in its component * Bitwarden -> Login text change * Remove the old login button * Cancel -> Close text change * Add avatar to login header * Login -> LoginWithMasterPassword text change * Add SSO button to login screen * Add not you button * Allow all clients to use the email query param on the login component * Introduct HomeGuard * Clear remembered email when clicking Not You * Make remember email opt-in * Use formGroup.patchValue instead of directly patching individual controls * [SG-165] Desktop login flow changes (#3814) * two step login flow * moved code from old branch and reafctored * fixed review comments * Make toggleValidateEmail in base class public * Add desktop login messages * Desktop login flow changes * Fix known device api error * Only submit if email has been validated * Clear remembered email when switching accounts * Fix merge issue * Add 'login with another device' button * Remove 'log in with another device' button for now * Pin login pag content to top instead of center justified * Leave email if 'Not you?' is clicked * Continue when enter is hit on email input Co-authored-by: gbubemismith <gsmithwalter@gmail.com> * [SG-750] and [SG-751] Web two step login bug fixes (#3843) * Continue when enter is hit on email input * Mark email input as touched on 'continue' so field is validated * disable login with device on self-hosted (#3895) * [SG-753] Keep email after hint component is launched in browser (#3883) * Keep email after hint component is launched in browser * Use query params instead of state for consistency * Send email and rememberEmail to home component on navigation (#3897) * removed avatar and close button from the password screen (#3901) * [SG-781] Remove extra login page and remove rememberEmail code (#3902) * Remove browser home guard * Always remember email for browser * Remove login landing page button * [SG-782] Add login service to streamline login form data persistence (#3911) * Add login service and abstraction * Inject login service into apps * Inject and use new service in login component * Use service in hint component to prefill email * Add method in LoginService to clear service values * Add LoginService to two-factor component to clear values * make login.service variables private Co-authored-by: Gbubemi Smith <gsmith@bitwarden.com> Co-authored-by: Addison Beck <addisonbeck1@gmail.com> Co-authored-by: Robyn MacCallum <robyntmaccallum@gmail.com> Co-authored-by: gbubemismith <gsmithwalter@gmail.com> * 400s only log out on invalid grant error (#3924) * Fix rust tests apt-get install (#3933) * Added focus to the email and master password fields (#3934) * Ps 1754 community pr reviewed (#3929) * community PR reviewed, Update search cancel button to be visible in all themes * community PR reviewed, Update search cancel button to be visible in all themes 2 * Update search cancel button to be visible in all themes (#3876) * Adding the 'libs/**' directory back to the Desktop build pipeline PR trigger list (#3938) * Re-\added the focusInput method to allow desktop build run (#3937) * [EC-522] Improve handling of rxjs subjects (#3772) * [EC-522] feat: no public rxjs subjects * [EC-522] feat: improve null handling * [EC-552] fix: init subject with empty set instead of null * [EC-552] fix: don't push null into account subject * [EC-522] feat: remove null filter * [EC-641] Browser Ext UI Update (#3842) * more css changes * add icon button hover * Update apps/browser/src/popup/scss/box.scss Co-authored-by: Oscar Hinton <Hinton@users.noreply.github.com> * Update apps/desktop/src/scss/box.scss Co-authored-by: Oscar Hinton <Hinton@users.noreply.github.com> * feedback updates * restore desktop pseudo rule * update to include some variable fixes and deletions * updates per oscar * feedback updates more universal variable, adjusted box padding (per Kyle), and aligned footer text * changes per product design added border for selects, border around generator, and hover for solarizeddark * add more helper text space below for visual separation * group new variable * login page button fix Dflinn found an odd margin on the login page * Revert "Merge branch 'master' into browser-ext-ui-update-test" This reverts commitb8007102f9, reversing changes made to246768cb12. * fix button height * revert file changes * test adjustments Co-authored-by: Oscar Hinton <Hinton@users.noreply.github.com> Co-authored-by: Kyle Spearrin <kyle.spearrin@gmail.com> * [SG-792] Added focus to master password field on browser and desktop (#3939) * Added focus to master password field on browser client * Added focus to master password field on desktop client * Tell eslint & prettier to ignore storybook-static (#3946) * [SG-792] Fixed focus on master password when enter key is pressed (#3948) * Added focus to master password field on browser client * Added focus to master password field on desktop client * fixed focus on master password when enter is pressed * [EC-7] Org Admin Vault Refresh Client V1 (#3925) * [EC-8] Restructure Tabs (#3109) * Cherry pick pending PR for tabs component [CL-17] Tabs - Routing * Update organization tabs from 4 to 6 * Create initial 'Members' tab * Create initial 'Groups' tab * Add initial "Reporting" tab * Use correct report label/layout by product type * Create initial 'Billing' tab * Breakup billing payment and billing history pages * Cleanup org routing and nav permission service * More org tab permission cleanup * Refactor organization billing to use a module * Refactor organization reporting to use module * Cherry pick finished/merged tabs component [CL-17] Tabs - Router (#2952) * This partially reverts commit24bb775to fix tracking of people.component.html rename. * Fix people component file rename * Recover lost member page changes * Undo members component rename as it was causing difficult merge conflicts * Fix member and group page container * Remove unnecessary organization lookup * [EC-8] Some PR suggestions * [EC-8] Reuse user billing history for orgs * [EC-8] Renamed user billing history component * [EC-8] Repurpose payment method component Update end user payment method component to be usable for organizations. * [EC-8] Fix missing verify bank condition * [EC-8] Remove org payment method component * [EC-8] Use CL in payment method component * [EC-8] Extend maxWidth Tailwind theme config * [EC-8] Add lazy loading to org reports * [EC-8] Add lazy loading to org billing * [EC-8] Prettier * [EC-8] Cleanup org reporting component redundancy * [EC-8] Use different class for negative margin * [EC-8] Make billing history component "dumb" * Revert "[EC-8] Cleanup org reporting component redundancy" This reverts commiteca337e89b. * [EC-8] Create and export shared reports module * [EC-8] Use shared reports module in orgs * [EC-8] Use takeUntil pattern * [EC-8] Move org reporting module out of old modules folder * [EC-8] Move org billing module out of old modules folder * [EC-8] Fix some remaining merge conflicts * [EC-8] Move maxWidth into 'extend' key for Tailwind config * [EC-8] Remove unused module * [EC-8] Rename org report list component * Prettier Co-authored-by: Vincent Salucci <vincesalucci21@gmail.com> * [EC-451] Org Admin Refresh Permissions Refactor (#3320) * [EC-451] Update new org permissions for new tabs * [EC-451] Remove redudant route guards * [EC-451] Remove canAccessManageTab() * [EC-451] Use canAccess* callbacks in org routing module * Fix org api service refactor and linting after pulling in master * Fix broken org people and group pages after merge * [EC-18] Reporting side nav direction (#3420) * [EC-18] Re-order side nav for org reports according to Figma * [EC-18] Fix rxjs linter errors and redundant org flag * [EC-526] Default to Event Logs page for Reporting Tab (#3470) * [EC-526] Default to the Events Logs page when navigating to the Reporting tab * [EC-526] Undo default routing redirect when the child path is missing. Avoids defaulting to "/events" in case a user/org doesn't have access to event logs. * [EC-19] Update Organization Settings Page (#3251) * [EC-19] Refactor existing organization settings components to its own module * [EC-19] Move SSO page to settings tab * [EC-19] Move Policies page to Settings tab Refactor Policy components into its own module * [EC-19] Move ImageSubscriptionHiddenComponent * [EC-19] Lazy load org settings module * [EC-19] Add SSO Id to SSO config view * [EC-19] Remove SSO identfier from org info page * [EC-19] Update org settings/policies to follow ADR-0011 * [EC-19] Update two-step login setup description * [EC-19] Revert nested policy components folder * [EC-19] Revert nested org setting components folder * [EC-19] Remove left over image component * [EC-19] Prettier * [EC-19] Fix missing i18n * [EC-19] Update SSO form to use CL * [EC-19] Remove unused SSO input components * [EC-19] Fix bad SSO locale identifier * [EC-19] Fix import order linting * [EC-19] Add explicit whitespace check for launch click directive * [EC-19] Add restricted import paths to eslint config * [EC-19] Tag deprecated field with Jira issue to cleanup in future release * [EC-19] Remove out of date comment * [EC-19] Move policy components to policies module * [EC-19] Remove dityRequired validator * [EC-19] Use explicit type for SSO config form * [EC-19] Fix rxjs linter errors * [EC-19] Fix RxJS eslint comments in org settings component * [EC-19] Use explicit ControlsOf<T> helper for nested SSO form groups. * [EC-19] Attribute source of ControlsOf<T> helper * [EC-19] Fix missing settings side nav links * [EC-19] Fix member/user language for policy modals * [EC-551] Update Event Logs Client Column (#3572) * [EC-551] Fix RxJS warnings * [EC-551] Update page to use CL components and Tailwind classes * [EC-551] Update Client column to use text instead of icon. Update language and i18n. * [EC-14] Refactor vault filter (#3440) * [EC-14] initial refactoring of vault filter * [EC-14] return observable trees for all filters with head node * [EC-14] Remove bindings on callbacks * [EC-14] fix formatting on disabled orgs * [EC-14] hide MyVault if personal org policy * [EC-14] add check for single org policy * [EC-14] add policies to org and change node constructor * [EC-14] don't show options if personal vault policy * [EC-14] default to all vaults * [EC-14] add default selection to filters * [EC-14] finish filter model callbacks * [EC-14] finish filter functionality and begin cleaning up * [EC-14] clean up old components and start on org vault * [EC-14] loop through filters for presentation * [EC-14] refactor VaultFilterService and put filter presentation data back into Vault Filter component. Remove VaultService * [EC-14] begin refactoring org vault * [EC-14] Refactor Vault Filter Service to use observables * [EC-14] finish org vault filter * [EC-14] fix vault model tests * [EC-14] fix org service calls * [EC-14] pull refactor out of shared code * [EC-14] include head node for collections even if collections aren't loaded yet * [EC-14] fix url params for vaults * [EC-14] remove comments * [EC-14] Remove unnecesary getter for org on vault filter * [EC-14] fix linter * [EC-14] fix prettier * [EC-14] add deprecated methods to collection service for desktop and browser * [EC-14] simplify cipher type node check * [EC-14] add getters to vault filter model * [EC-14] refactor how we build the filter list into methods * [EC-14] add getters to build filter method * [EC-14] remove param ids if false * [EC-14] fix collapsing nodes * [EC-14] add specific type to search placeholder * [EC-14] remove extra constructor and comment from org vault filter * [EC-14] extract subscription callback to methods * [EC-14] Remove unecessary await * [EC-14] Remove ternary operators while building org filter * [EC-14] remove unnecessary deps array in vault filter service declaration * [EC-14] consolidate new models into one file * [EC-14] initialize nested observable inside of service Signed-off-by: Jacob Fink <jfink@bitwarden.com> * [EC-14] change how we load orgs into the vault filter and select the default filter * [EC-14] remove get from getters name * [EC-14] remove eslint-disable comment * [EC-14] move vault filter service abstraction to angular folder and separate * [EC-14] rename filter types and delete VaultFilterLabel * [EC-14] remove changes to workspace file * [EC-14] remove deprecated service from jslib module * [EC-14] remove any remaining files from common code * [EC-14] consolidate vault filter components into components folder * [EC-14] simplify method call * [EC-14] refactor the vault filter service - orgs now have observable property - BehaviorSubjects have been migrated to ReplaySubjects if they don't need starting value - added unit tests - fix small error when selecting org badge of personal vault - renamed some properties * [EC-14] replace mergeMap with switchMap in vault filter service * [EC-14] early return to prevent nesting * [EC-14] clean up filterCollections method * [EC-14] use isDeleted helper in html * [EC-14] add jsdoc comments to ServiceUtils * [EC-14] fix linter * [EC-14] use array.slice instead of setting length * Update apps/web/src/app/vault/vault-filter/services/vault-filter.service.ts Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com> * [EC-14] add missing high level jsdoc description * [EC-14] fix storybook absolute imports * [EC-14] delete vault-shared.module * [EC-14] change search placeholder text to getter and add missing strings * [EC-14] remove two way binding from search text in vault filter * [EC-14] removed all binding from search text and just use input event * [EC-14] remove async from apply vault filter * [EC-14] remove circular observable calls in vault filter service Co-authored-by: Thomas Rittson <eliykat@users.noreply.github.com> * [EC-14] move collapsed nodes to vault filter section * [EC-14] deconstruct filter section inside component * [EC-14] fix merge conflicts and introduce refactored organization service to vault filter service * [EC-14] remove mutation from filter builders * [EC-14] fix styling on buildFolderTree * [EC-14] remove leftover folder-filters reference and use ternary for collapse icon * [EC-14] remove unecessary checks * [EC-14] stop rebuilding filters when the organization changes * [EC-14] Move subscription out of setter in vault filter section * [EC-14] remove extra policy service methods from vault filter service * [EC-14] remove new methods from old vault-filter.service * [EC-14] Use vault filter service in vault components * [EC-14] reload collections from vault now that we have vault filter service * [EC-14] remove currentFilterCollections in vault filter component * [EC-14] change VaultFilterType to more specific OrganizationFilter in organization-options * [EC-14] include org check in isNodeSelected * [EC-14] add getters to filter function, fix storybook, and add test for All Collections * [EC-14] show org options even if there's a personal vault policy * [EC-14] use !"AllCollections" instead of just !null * [EC-14] Remove extra org Subject in vault filter service * [EC-14] remove null check from vault search text * [EC-14] replace store/build names with set/get. Remove extra call to setOrganizationFilter * [EC-14] add take(1) to subscribe in test * [EC-14] move init logic in org vault filter component to ngOnInit * [EC-14] Fix linter * [EC-14] revert change to vault filter model * [EC-14] be specific about ignoring All Collections * [EC-14] move observable init logic to beforeEach in test * [EC-14] make buildAllFilters return something to reduce side effects Signed-off-by: Jacob Fink <jfink@bitwarden.com> Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com> Co-authored-by: Thomas Rittson <eliykat@users.noreply.github.com> * [EC-97] Organization Billing Language / RxJS Warnings (#3688) * [EC-97] Update copy to use the word members in a few places * [EC-97] Cleanup RxJS warnings and unused properties in org billing components * [EC-599] Access Selector Component (#3717) * Add Access Selector Component and Stories * Cherry pick FormSelectionList * Fix some problems caused from cherry-pick * Fix some Web module problems caused from cherry-pick * Move AccessSelector out of the root components directory. Move UserType pipe to AccessSelectorModule * Fix broken member access selector story * Add organization feature module * Undo changes to messages.json * Fix messages.json * Remove redundant CommonModule * [EC-599] Fix avatar/icon sizing * [EC-599] Remove padding in permission column * [EC-599] Make FormSelectionList operations immutable * [EC-599] Integrate the multi-select component * [EC-599] Handle readonly/access all edge cases * [EC-599] Add initial unit tests Also cleans up public interface for the AccessSelectorComponent. Fixes a bug found during unit test creation. * [EC-599] Include item name in control labels * [EC-599] Cleanup member email display * [EC-599] Review suggestions - Change PermissionMode to Enum - Rename permControl to permissionControl to be more clear - Rename FormSelectionList file to kebab case. - Move permission row boolean logic to named function for readability * [EC-599] Cleanup AccessSelectorComponent tests - Clarify test states - Add tests for column rendering - Add tests for permission mode - Add id to column headers for testing - Fix small permissionControl bug found during testing * [EC-599] Add FormSelectionList unit tests * [EC-599] Fix unit test and linter * [EC-599] Update Enums to Pascal case * [EC-599] Undo change to Enum values * [EC-7] fix: broken build * [EC-646] Org Admin Vault Refresh November Release Prep (#3913) * [EC-646] Remove links from Manage component These links are no longer necessary as they are now located in the new OAVR tabs. * [EC-646] Re-introduce the canAccessManageTab helper * [EC-646] Re-introduce /manage route in Organization routing module - Add the parent /manage route - Add child routes for collections, people, and groups * [EC-646] Adjust Org admin tabs Re-introduce the Manage tab and remove Groups and Members tabs. * [EC-646] Change Members title back to People * [EC-646] Move missing billing components Some billing components were in the org settings module and needed to be moved the org billing module * [EC-646] Fix import file upload button -Update to use click event handler and tailwind class to hide input. Avoids inline styles/js blocked by CSP - Fix broken async pipe * [EC-646] Fix groups and people page overflow Remove the container and page-content wrapper as the pages are no longer on their own tab * [EC-646] Change People to Members Change the text regarding managing members from People to Members to more closely follow changes coming later in the OAVR. Also update the URL to use /manage/members * [EC-646] Cherry-pickae39afeto fix tab text color * [EC-646] Fix org routing permissions helpers - Add canAccessVaultTab helper - Update canAccessOrgAdmin include check for vault tab access - Simplify canManageCollections * [EC-646] Fix Manage tab conditional logic - Add *ngIf condition for rendering Manage tab - Re-introduce dynamic route for Manage tab * Revert "[EC-14] Refactor vault filter (#3440)" (#3926) This reverts commit4d83b81d82. * Remove old reference to bit-submit-button that no longer exists (#3927) * [EC-593] Top align event logs row content (#3813) * [EC-593] Top align event log row contents * [EC-593] Prevent event log timestamp from wrapping * [EC-593] Add alignContent input to bitRow directive * [EC-593] Remove ineffective inline styles (CSP) * [EC-593] Remove templated tailwind classes Tailwind minimizes the bundled stylesheet by removing classes that aren't used in code. Using a string template for the classes causes those classes to be ignored. * [EC-593] Introduce alignContent input to table story * [EC-657] Hide Billing History and Payment Method for selfhosted orgs (#3935) Signed-off-by: Jacob Fink <jfink@bitwarden.com> Co-authored-by: Vincent Salucci <vincesalucci21@gmail.com> Co-authored-by: Andreas Coroiu <andreas.coroiu@gmail.com> Co-authored-by: Jake Fink <jfink@bitwarden.com> Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com> Co-authored-by: Thomas Rittson <eliykat@users.noreply.github.com> * Add padding to top of Safari extension (#3949) * Use correct provider icon instead of bank icon (#3950) * Fix undefined property error in event logs (#3947) EventService.policies was undefined because the service was erroneously using ngOnInit to subscribe to the policies observable * PS-1763 - handle undefined locale value that exists before a user sets their language (#3952) * Autosync the updated translations (#3968) Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com> * Autosync the updated translations (#3967) Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com> * fixed typo in event log (#3962) * Org admin refresh translation nitpicks (#3971) * Fix use of personal in favor of individual vault * Fix capitalization according to #3577 * Fix capitalization on organizationInfo * Autosync the updated translations (#3974) Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com> * Autosync the updated translations (#3973) Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com> * add csp and only pass hostname to duo init (#3972) * add csp and only pass hostname to duo init * expand style-src * Update apps/web/src/connectors/duo.html Co-authored-by: Oscar Hinton <Hinton@users.noreply.github.com> Co-authored-by: Oscar Hinton <Hinton@users.noreply.github.com> * Move hint button out of the formfield (#3960) * [PS-1734] Send saved urls to autofill script (#3861) * Send all saved url to autofill script * Handle array of matched urls in content script * Prompt at most once to override insecure autofill * Do not send never match URIs to content script We know these URIs did not cause the autofill match, so we can safely remove these from the list of potential matches. * [PS-1804] Display Organization tab for users with custom permissions (#3980) * [EC-584] Fixed OrganizationExportResponse to correctly parse data (#3641) * [EC-584] Fixed OrganizationExportResponse to correctly parse data and use CollectionResponse and CipherResponse constructors * [EC-584] Removed ListResponse from OrganizationExportResponse properties * Bumped web version to 2022.10.3 (#3957) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Revert "Bumped web version to 2022.10.3 (#3957)" This reverts commit5d8d547cd2. * Web version bump to 2022.11.0 for QA testing * Revert "Web version bump to 2022.11.0 for QA testing" This reverts commit484db431ed. Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Joseph Flinn <joseph.s.flinn@gmail.com> * [EC-678] [EC-673] Fix active tab not showing selected while in child route (#3964) * [PS-1114] hide reporting sidebar if only events * [PS-1114] add orgRedirectGuard * [PS-1114] highlight tabs based on route subset * [PS-1114] redirect to correct child route on tab - Use new OrgRedirectGuard * [PS-1114] add settings redirect using guard - refactored guard to accept array of strings * [EC-678] [EC-673] remove remaining methods * [EC-678][EC-673] address PR feedback - change switch to if statements - remove ternary * [EC-672] Update SSO login page language (#3997) - Replace 'Organization Identifier' with 'SSO identifier' - Sentence case 'SSO identifier' - Add 'SSO' to SSO login page helper text * Autosync the updated translations (#3969) Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com> * [EC-661] Add web worker code bundles to Safari browser extension (#3986) * Make browser bundle encrypt-worker.ts into a single named file * Add encrypt-worker bundle to xcode proj * Fixed EC reported event log copy bugs (#3977) * [EC-645] fix: web payment component breaking storybook compilation (#3906) * add run-name for releases to include their workflow trigger (#3996) * add run-name for releases to include their workflow trigger * add edit for linter error * Update .github/workflows/release-web.yml Co-authored-by: Vince Grassia <593223+vgrassia@users.noreply.github.com> Co-authored-by: Vince Grassia <593223+vgrassia@users.noreply.github.com> * Extract and fix trigger for PR auto responses (Translation-PRs) (#3992) * Extract and fix trigger for PR auto responses * Fix permission used for job * [EC-650] Revert observable usage from ImportComponent (#4010) * Run enforce labels workflow on version bump in clients repo (#4006) * Fix version bump to run enforce labels workflow * Add login to Azure * Trigger enforce labels manually from bump version workflow * Update .github/workflows/enforce-labels.yml Co-authored-by: Vince Grassia <593223+vgrassia@users.noreply.github.com> * Update .github/workflows/version-bump.yml Co-authored-by: Vince Grassia <593223+vgrassia@users.noreply.github.com> Co-authored-by: Vince Grassia <593223+vgrassia@users.noreply.github.com> * [EC-670] Update Members tab to support flex wrap (#4003) Use tailwind classes to style the Members page header so that it supports wrapping the controls to a new line should they exceed the width of the container. * [PS-1841] Fix org-* commands for CLI (#4013) * Add getFromState method * Added a method for CLI to get an org from state * Converted all CLI calls to `.get()` * Used `.getFromState` instead of `.get` * Deprecate getFromState method * Remove local vaultFilter (#4014) * Use vault filter item from vaultFilterService * [PS-1843] Sort organizations in `buildOrganizations` (#4015) * Sort organizations in buildOrganizations * Add sort by name to Organization Switcher * [EC-675] Display the Event for “Viewed Card Number for item item-identifier” (#3976) * [EC-675] Add missing Event capture for viewing item Card Number * [EC-675] Fix correct event type for viewing item Card Number * Update apps/web/src/locales/en/messages.json Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com> Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com> * [EC-449] Event log user for SCIM events (#3643) * [EC-449] Added EventSystemUser Enum and added systemUser property to eventResponse * [EC-449] Add systemUser property to BaseEventsComponent, EventExport and EventView * [EC-449] Set EventSystemUser as string on EventExport * [EC-449] Remove systemUser from EventExport * [EC-449] Rename EventSystemUser file to lowercase * [EC-449] Force git to rename EventSystemUser file * [EC-449] Rename EventSystemUser file to event-system-user.ts * [EC-449] Fix EventSystemUser reference on EventsComponent * [EC-449] Move installationId username logic to BaseEventsComponent * Update libs/common/src/enums/event-system-user.ts Add a note to warn about using the Enum key in the UI. Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com> * [EC-449] Remove EventSystemUser from provider events. Remove nested condition on events component Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com> * [PS-1840] - fix for covered dropdown on empty vault (#4019) * fix for covered dropdown on empty vault This could be done one of 2-3 ways. I think this might be the least problematic, but could also be done with just changing "position: absolute" to "relative on the ".no-items" class - base.css:461 For some reason, I'm unable to load the spinner to test. * rename class * Remove uses of rxjs in CLI (#4028) * [SM-327] Electron hard reset (#3988) * Add folders to whitelist (#3994) * Defect/sg 650 desktop pw/passphrase gen not auto updating on min value change (#4032) * SG-650 - Desktop - Pw Generation - Min value ctrls now use (change) instead of (blur) for better responsiveness when using arrows on input or arrow keys. Note: (input) has change detection issues for resetting the value to either max pw length or max value of 9 + passwordGeneration.service logic possibly needs refactoring to either enforce max of 9 or not * SG-650 - Desktop - Passphrase Gen - min words now uses (change) instead of (blur) for better responsiveness * Autosync the updated translations (#4035) Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com> * Autosync the updated translations (#4036) Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com> * Autosync the updated translations (#4037) Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com> * Expand serve origin protection warning (#4024) This warning was kept vague during fix rollout, but now that we're more than a release past, we can expand the explanation. * [SM-340] Fix share modal not closing on cancel (#4041) * [EC-739 / EC-740] Add null check to policyFilter on PolicyService (#4039) * [EC-739 / EC-740] Add null check to policyFilter on PolicyService * [EC-739 / EC-740] Add unit tests for policy filter * [PS-1805] BEEEP: Renamed importers based on agreed naming-convention (#3978) * Rename all importer related files Renamed all files based on our naming convention which we decided on with https://github.com/bitwarden/adr/blob/master/decisions/0012-angular-filename-convention.md * Removed entries from whitelist-capital-letters.txt * Rename missing safeInCloud test data * Fix broken import * Renamed folders (removed capital letters) * Fix filename of BitwardenCsvImporter * Fix imports of onepassword mac/win importer tests * Remove already renamed folders from whitelist * Rename dashlaneImporters to dashlane Rename the folder Fix all the imports Remove dashlaneImporters from white-list * Rename keeperImporters to keeper Rename the folder Fix all the imports Remove keeperImporters from white-list * Rename onepasswordImporters to onepassword Rename the folder Fix all the imports Remove onepasswordImporters from white-list * Rename safeinCloud test data folder * Fix onepassword importer type imports * [EC-744] Revert PolicyService back to clearing DecryptedPolicies on StateService (#4042) * [EC-746] Call BaseAddEditComponent.ngOnInit on Desktop AddEditComponent (#4044) * PS-1798 - ensure admin users can edit ciphers (#4025) * Use loginService to get and set remember email values (#3941) * SG-428 - Browser Extension - Send - Expiration / Deletion date calendar icon +… (#4034) * Browser Extension - Send - Expiration / Deletion date calendar icon + datepicker pop up now respect theme better in Chrome / Chromium based browsers and Safari (Firefox datepicker pop up doesn't seem to have an easy mechanism for theming) * SG-428 - Extension - Iconography for date inputs for Chromium browsers now reflects theme colors properly + hover states; icon not shown on non-Chromium browsers * Variables.scss - ran prettier locally after tweaking comments to pass eslint checks * [EC-743] Call super to ngOnInit to include policy observable changes (#4047) * Hide My Vault if Remove Individual Vault is on (#4052) * Devops 1039 update release flow dry run step names (#4016) * Updated workflows to not create Github deployment on Dry Run. (#4049) * Add organization-options menu to single org (#3678) (#4051) Re-apply commit7c3255d(#3678) which was accidentally reverted by the Org Admin Refresh changes in commit09c3bc8(#3925) * SG-725 - Desktop - Moved DuckDuckGo setting down so that the Biometric browser settings are not separated (#4059) * [EC-750] Specify organizationId for credit and adjust payment components (#4061) * [SM-330] Disable managed environments for safari (#3953) * [EC-665] Fix biometrics button style (#3979) * fix biometrics button style * expand button to fill space this is a result of it being used outside the box-content * remove padding from box-footer * Added Mastodon to follow us menu (#4029) * Add branch check for Staged Rollout Desktop workflow (#4062) * [PS-1783] Fix file selector input bug from PS-1465 ( #3502 ) (#3928) * Fix file selector input * Add file selector state changes back * Remove async pipe * Revert "[EC-646] Org Admin Vault Refresh November Release Prep (#3913)" This reverts commit4b57d28e28. * [EC-646] Move missing billing components Some billing components were in the org settings module and needed to be moved the org billing module (cherry picked from commit1c11695f46) * [EC-646] Cherry-pickae39afeto fix tab text color (cherry picked from commit467f584b9e) * Make destroy$ protected to fix linting error Signed-off-by: Jacob Fink <jfink@bitwarden.com> Co-authored-by: Justin Baur <19896123+justindbaur@users.noreply.github.com> Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com> Co-authored-by: Daniel James Smith <djsmith85@users.noreply.github.com> Co-authored-by: Oscar Hinton <Hinton@users.noreply.github.com> Co-authored-by: Sammy Chang <sammychang2185@gmail.com> Co-authored-by: Todd Martin <106564991+trmartin4@users.noreply.github.com> Co-authored-by: Gbubemi Smith <gsmith@bitwarden.com> Co-authored-by: Addison Beck <addisonbeck1@gmail.com> Co-authored-by: Robyn MacCallum <robyntmaccallum@gmail.com> Co-authored-by: gbubemismith <gsmithwalter@gmail.com> Co-authored-by: Kyle Spearrin <kspearrin@users.noreply.github.com> Co-authored-by: Michał Chęciński <mchecinski@bitwarden.com> Co-authored-by: cd-bitwarden <106776772+cd-bitwarden@users.noreply.github.com> Co-authored-by: Scott McFarlane <91044021+scottmondo@users.noreply.github.com> Co-authored-by: Joseph Flinn <58369717+joseph-flinn@users.noreply.github.com> Co-authored-by: Andreas Coroiu <acoroiu@bitwarden.com> Co-authored-by: DanHillesheim <79476558+DanHillesheim@users.noreply.github.com> Co-authored-by: Kyle Spearrin <kyle.spearrin@gmail.com> Co-authored-by: Vincent Salucci <vincesalucci21@gmail.com> Co-authored-by: Andreas Coroiu <andreas.coroiu@gmail.com> Co-authored-by: Jake Fink <jfink@bitwarden.com> Co-authored-by: Thomas Rittson <eliykat@users.noreply.github.com> Co-authored-by: dgoodman-bw <109169446+dgoodman-bw@users.noreply.github.com> Co-authored-by: Danielle Flinn <43477473+danielleflinn@users.noreply.github.com> Co-authored-by: Matt Gibson <mgibson@bitwarden.com> Co-authored-by: Rui Tomé <108268980+r-tome@users.noreply.github.com> Co-authored-by: Joseph Flinn <joseph.s.flinn@gmail.com> Co-authored-by: Opeyemi <54288773+Eebru-gzy@users.noreply.github.com> Co-authored-by: Vince Grassia <593223+vgrassia@users.noreply.github.com> Co-authored-by: Jared Snider <116684653+JaredSnider-Bitwarden@users.noreply.github.com> Co-authored-by: Vincent Salucci <26154748+vincentsalucci@users.noreply.github.com> Co-authored-by: Ash Leece <ash@leece.im>
690 lines
31 KiB
TypeScript
690 lines
31 KiB
TypeScript
import { CipherType } from "@bitwarden/common/enums/cipherType";
|
|
import { FieldType } from "@bitwarden/common/enums/fieldType";
|
|
import { SecureNoteType } from "@bitwarden/common/enums/secureNoteType";
|
|
import { OnePassword1PuxImporter as Importer } from "@bitwarden/common/importers/onepassword/onepassword-1pux-importer";
|
|
import { Utils } from "@bitwarden/common/misc/utils";
|
|
import { FieldView } from "@bitwarden/common/models/view/field.view";
|
|
|
|
import { APICredentialsData } from "./test-data/onepassword-1pux/api-credentials";
|
|
import { BankAccountData } from "./test-data/onepassword-1pux/bank-account";
|
|
import { CreditCardData } from "./test-data/onepassword-1pux/credit-card";
|
|
import { DatabaseData } from "./test-data/onepassword-1pux/database";
|
|
import { DriversLicenseData } from "./test-data/onepassword-1pux/drivers-license";
|
|
import { EmailAccountData } from "./test-data/onepassword-1pux/email-account";
|
|
import { EmailFieldData } from "./test-data/onepassword-1pux/email-field";
|
|
import { EmailFieldOnIdentityData } from "./test-data/onepassword-1pux/email-field-on-identity";
|
|
import { EmailFieldOnIdentityPrefilledData } from "./test-data/onepassword-1pux/email-field-on-identity_prefilled";
|
|
import { IdentityData } from "./test-data/onepassword-1pux/identity-data";
|
|
import { LoginData } from "./test-data/onepassword-1pux/login-data";
|
|
import { MedicalRecordData } from "./test-data/onepassword-1pux/medical-record";
|
|
import { MembershipData } from "./test-data/onepassword-1pux/membership";
|
|
import { OnePuxExampleFile } from "./test-data/onepassword-1pux/onepux_example";
|
|
import { OutdoorLicenseData } from "./test-data/onepassword-1pux/outdoor-license";
|
|
import { PassportData } from "./test-data/onepassword-1pux/passport";
|
|
import { PasswordData } from "./test-data/onepassword-1pux/password";
|
|
import { RewardsProgramData } from "./test-data/onepassword-1pux/rewards-program";
|
|
import { SanitizedExport } from "./test-data/onepassword-1pux/sanitized-export";
|
|
import { SecureNoteData } from "./test-data/onepassword-1pux/secure-note";
|
|
import { ServerData } from "./test-data/onepassword-1pux/server";
|
|
import { SoftwareLicenseData } from "./test-data/onepassword-1pux/software-license";
|
|
import { SSNData } from "./test-data/onepassword-1pux/ssn";
|
|
import { WirelessRouterData } from "./test-data/onepassword-1pux/wireless-router";
|
|
|
|
function validateCustomField(fields: FieldView[], fieldName: string, expectedValue: any) {
|
|
expect(fields).toBeDefined();
|
|
const customField = fields.find((f) => f.name === fieldName);
|
|
expect(customField).toBeDefined();
|
|
|
|
expect(customField.value).toEqual(expectedValue);
|
|
}
|
|
|
|
describe("1Password 1Pux Importer", () => {
|
|
const OnePuxExampleFileJson = JSON.stringify(OnePuxExampleFile);
|
|
const LoginDataJson = JSON.stringify(LoginData);
|
|
const CreditCardDataJson = JSON.stringify(CreditCardData);
|
|
const IdentityDataJson = JSON.stringify(IdentityData);
|
|
const SecureNoteDataJson = JSON.stringify(SecureNoteData);
|
|
const SanitizedExportJson = JSON.stringify(SanitizedExport);
|
|
|
|
it("should parse login data", async () => {
|
|
const importer = new Importer();
|
|
const result = await importer.parse(LoginDataJson);
|
|
expect(result != null).toBe(true);
|
|
|
|
const cipher = result.ciphers.shift();
|
|
|
|
expect(cipher.type).toEqual(CipherType.Login);
|
|
expect(cipher.name).toEqual("eToro");
|
|
|
|
expect(cipher.login.username).toEqual("username123123123@gmail.com");
|
|
expect(cipher.login.password).toEqual("password!");
|
|
expect(cipher.login.uris.length).toEqual(1);
|
|
expect(cipher.login.uri).toEqual("https://www.fakesite.com");
|
|
expect(cipher.login.totp).toEqual("otpseed777");
|
|
|
|
// remaining fields as custom fields
|
|
expect(cipher.fields.length).toEqual(3);
|
|
validateCustomField(cipher.fields, "terms", "false");
|
|
validateCustomField(cipher.fields, "policies", "true");
|
|
validateCustomField(cipher.fields, "cyqyggt2otns6tbbqtsl6w2ceu", "username123123");
|
|
});
|
|
|
|
it("should parse notes", async () => {
|
|
const importer = new Importer();
|
|
const result = await importer.parse(OnePuxExampleFileJson);
|
|
expect(result != null).toBe(true);
|
|
|
|
const cipher = result.ciphers.shift();
|
|
expect(cipher.notes).toEqual("This is a note. *bold*! _italic_!");
|
|
});
|
|
|
|
it("should set favourite if favIndex equals 1", async () => {
|
|
const importer = new Importer();
|
|
const result = await importer.parse(OnePuxExampleFileJson);
|
|
expect(result != null).toBe(true);
|
|
|
|
const cipher = result.ciphers.shift();
|
|
expect(cipher.favorite).toBe(true);
|
|
});
|
|
|
|
it("should handle custom boolean fields", async () => {
|
|
const importer = new Importer();
|
|
const result = await importer.parse(LoginDataJson);
|
|
expect(result != null).toBe(true);
|
|
|
|
const ciphers = result.ciphers;
|
|
expect(ciphers.length).toEqual(1);
|
|
|
|
const cipher = ciphers.shift();
|
|
expect(cipher.fields[0].name).toEqual("terms");
|
|
expect(cipher.fields[0].value).toEqual("false");
|
|
expect(cipher.fields[0].type).toBe(FieldType.Boolean);
|
|
|
|
expect(cipher.fields[1].name).toEqual("policies");
|
|
expect(cipher.fields[1].value).toEqual("true");
|
|
expect(cipher.fields[1].type).toBe(FieldType.Boolean);
|
|
});
|
|
|
|
it("should add fields of type email as custom fields", async () => {
|
|
const importer = new Importer();
|
|
const EmailFieldDataJson = JSON.stringify(EmailFieldData);
|
|
const result = await importer.parse(EmailFieldDataJson);
|
|
expect(result != null).toBe(true);
|
|
|
|
const ciphers = result.ciphers;
|
|
expect(ciphers.length).toEqual(1);
|
|
const cipher = ciphers.shift();
|
|
|
|
expect(cipher.fields[0].name).toEqual("reg_email");
|
|
expect(cipher.fields[0].value).toEqual("kriddler@nullvalue.test");
|
|
expect(cipher.fields[0].type).toBe(FieldType.Text);
|
|
|
|
expect(cipher.fields[1].name).toEqual("provider");
|
|
expect(cipher.fields[1].value).toEqual("myEmailProvider");
|
|
expect(cipher.fields[1].type).toBe(FieldType.Text);
|
|
});
|
|
|
|
it('should create concealed field as "hidden" type', async () => {
|
|
const importer = new Importer();
|
|
const result = await importer.parse(OnePuxExampleFileJson);
|
|
expect(result != null).toBe(true);
|
|
|
|
const ciphers = result.ciphers;
|
|
expect(ciphers.length).toEqual(1);
|
|
|
|
const cipher = ciphers.shift();
|
|
const fields = cipher.fields;
|
|
expect(fields.length).toEqual(1);
|
|
|
|
const field = fields.shift();
|
|
expect(field.name).toEqual("PIN");
|
|
expect(field.value).toEqual("12345");
|
|
expect(field.type).toEqual(FieldType.Hidden);
|
|
});
|
|
|
|
it("should create password history", async () => {
|
|
const importer = new Importer();
|
|
const result = await importer.parse(OnePuxExampleFileJson);
|
|
const cipher = result.ciphers.shift();
|
|
|
|
expect(cipher.passwordHistory.length).toEqual(1);
|
|
const ph = cipher.passwordHistory.shift();
|
|
expect(ph.password).toEqual("12345password");
|
|
expect(ph.lastUsedDate.toISOString()).toEqual("2016-03-18T17:32:35.000Z");
|
|
});
|
|
|
|
it("should create credit card records", async () => {
|
|
const importer = new Importer();
|
|
const result = await importer.parse(CreditCardDataJson);
|
|
expect(result != null).toBe(true);
|
|
const cipher = result.ciphers.shift();
|
|
expect(cipher.name).toEqual("Parent's Credit Card");
|
|
expect(cipher.notes).toEqual("My parents' credit card.");
|
|
|
|
const card = cipher.card;
|
|
expect(card.cardholderName).toEqual("Fred Engels");
|
|
expect(card.number).toEqual("6011111111111117");
|
|
expect(card.code).toEqual("1312");
|
|
expect(card.brand).toEqual("Discover");
|
|
expect(card.expMonth).toEqual("12");
|
|
expect(card.expYear).toEqual("2099");
|
|
|
|
// remaining fields as custom fields
|
|
expect(cipher.fields.length).toEqual(12);
|
|
validateCustomField(cipher.fields, "txbzvwzpck7ejhfres3733rbpm", "card");
|
|
validateCustomField(cipher.fields, "cashLimit", "$500");
|
|
validateCustomField(cipher.fields, "creditLimit", "$1312");
|
|
validateCustomField(cipher.fields, "validFrom", "200101");
|
|
validateCustomField(cipher.fields, "bank", "Some bank");
|
|
validateCustomField(cipher.fields, "phoneLocal", "123456");
|
|
validateCustomField(cipher.fields, "phoneTollFree", "0800123456");
|
|
validateCustomField(cipher.fields, "phoneIntl", "+49123456");
|
|
validateCustomField(cipher.fields, "website", "somebank.com");
|
|
validateCustomField(cipher.fields, "pin", "1234");
|
|
validateCustomField(cipher.fields, "interest", "1%");
|
|
validateCustomField(cipher.fields, "issuenumber", "123456");
|
|
});
|
|
|
|
it("should create identity records", async () => {
|
|
const importer = new Importer();
|
|
const result = await importer.parse(IdentityDataJson);
|
|
expect(result != null).toBe(true);
|
|
const cipher = result.ciphers.shift();
|
|
expect(cipher.name).toEqual("George Engels");
|
|
|
|
const identity = cipher.identity;
|
|
expect(identity.firstName).toEqual("George");
|
|
expect(identity.middleName).toEqual("S");
|
|
expect(identity.lastName).toEqual("Engels");
|
|
expect(identity.company).toEqual("Acme Inc.");
|
|
expect(identity.address1).toEqual("1312 Main St.");
|
|
expect(identity.country).toEqual("US");
|
|
expect(identity.state).toEqual("California");
|
|
expect(identity.city).toEqual("Atlantis");
|
|
expect(identity.postalCode).toEqual("90210");
|
|
expect(identity.phone).toEqual("4565555555");
|
|
expect(identity.email).toEqual("gengels@nullvalue.test");
|
|
expect(identity.username).toEqual("gengels");
|
|
|
|
// remaining fields as custom fields
|
|
expect(cipher.fields.length).toEqual(17);
|
|
validateCustomField(cipher.fields, "sex", "male");
|
|
validateCustomField(cipher.fields, "birthdate", "Thu, 01 Jan 1981 12:01:00 GMT");
|
|
validateCustomField(cipher.fields, "occupation", "Steel Worker");
|
|
validateCustomField(cipher.fields, "department", "QA");
|
|
validateCustomField(cipher.fields, "jobtitle", "Quality Assurance Manager");
|
|
validateCustomField(cipher.fields, "homephone", "4575555555");
|
|
validateCustomField(cipher.fields, "cellphone", "4585555555");
|
|
validateCustomField(cipher.fields, "busphone", "4595555555");
|
|
validateCustomField(cipher.fields, "reminderq", "Who's a super cool guy?");
|
|
validateCustomField(cipher.fields, "remindera", "Me, buddy.");
|
|
validateCustomField(cipher.fields, "website", "cv.gengels.nullvalue.test");
|
|
validateCustomField(cipher.fields, "icq", "12345678");
|
|
validateCustomField(cipher.fields, "skype", "skypeisbad1619");
|
|
validateCustomField(cipher.fields, "aim", "aollol@lololol.aol.com");
|
|
validateCustomField(cipher.fields, "yahoo", "sk8rboi13@yah00.com");
|
|
validateCustomField(cipher.fields, "msn", "msnothankyou@msn&m&m.com");
|
|
validateCustomField(cipher.fields, "forumsig", "super cool guy");
|
|
});
|
|
|
|
it("emails fields on identity types should be added to the identity email field", async () => {
|
|
const importer = new Importer();
|
|
const EmailFieldOnIdentityDataJson = JSON.stringify(EmailFieldOnIdentityData);
|
|
const result = await importer.parse(EmailFieldOnIdentityDataJson);
|
|
expect(result != null).toBe(true);
|
|
|
|
const ciphers = result.ciphers;
|
|
expect(ciphers.length).toEqual(1);
|
|
const cipher = ciphers.shift();
|
|
|
|
const identity = cipher.identity;
|
|
expect(identity.email).toEqual("gengels@nullvalue.test");
|
|
|
|
expect(cipher.fields[0].name).toEqual("provider");
|
|
expect(cipher.fields[0].value).toEqual("myEmailProvider");
|
|
expect(cipher.fields[0].type).toBe(FieldType.Text);
|
|
});
|
|
|
|
it("emails fields on identity types should be added to custom fields if identity.email has been filled", async () => {
|
|
const importer = new Importer();
|
|
const EmailFieldOnIdentityPrefilledDataJson = JSON.stringify(EmailFieldOnIdentityPrefilledData);
|
|
const result = await importer.parse(EmailFieldOnIdentityPrefilledDataJson);
|
|
expect(result != null).toBe(true);
|
|
|
|
const ciphers = result.ciphers;
|
|
expect(ciphers.length).toEqual(1);
|
|
const cipher = ciphers.shift();
|
|
|
|
const identity = cipher.identity;
|
|
expect(identity.email).toEqual("gengels@nullvalue.test");
|
|
|
|
expect(cipher.fields[0].name).toEqual("2nd_email");
|
|
expect(cipher.fields[0].value).toEqual("kriddler@nullvalue.test");
|
|
expect(cipher.fields[0].type).toBe(FieldType.Text);
|
|
|
|
expect(cipher.fields[1].name).toEqual("provider");
|
|
expect(cipher.fields[1].value).toEqual("myEmailProvider");
|
|
expect(cipher.fields[1].type).toBe(FieldType.Text);
|
|
});
|
|
|
|
it("should parse category 005 - Password (Legacy)", async () => {
|
|
const importer = new Importer();
|
|
const jsonString = JSON.stringify(PasswordData);
|
|
const result = await importer.parse(jsonString);
|
|
expect(result != null).toBe(true);
|
|
const cipher = result.ciphers.shift();
|
|
expect(cipher.type).toEqual(CipherType.Login);
|
|
expect(cipher.name).toEqual("SuperSecret Password");
|
|
expect(cipher.notes).toEqual("SuperSecret Password Notes");
|
|
|
|
expect(cipher.login.password).toEqual("GBq[AGb]4*Si3tjwuab^");
|
|
expect(cipher.login.uri).toEqual("https://n0t.y0ur.n0rm4l.w3bs1t3");
|
|
});
|
|
|
|
it("should parse category 100 - SoftwareLicense", async () => {
|
|
const importer = new Importer();
|
|
const jsonString = JSON.stringify(SoftwareLicenseData);
|
|
const result = await importer.parse(jsonString);
|
|
expect(result != null).toBe(true);
|
|
const cipher = result.ciphers.shift();
|
|
expect(cipher.type).toEqual(CipherType.SecureNote);
|
|
expect(cipher.name).toEqual("Limux Product Key");
|
|
expect(cipher.notes).toEqual("My Software License");
|
|
|
|
expect(cipher.fields.length).toEqual(13);
|
|
validateCustomField(cipher.fields, "product_version", "5.10.1000");
|
|
validateCustomField(cipher.fields, "reg_code", "265453-13457355-847327");
|
|
validateCustomField(cipher.fields, "reg_name", "Kay Riddler");
|
|
validateCustomField(cipher.fields, "reg_email", "kriddler@nullvalue.test");
|
|
validateCustomField(cipher.fields, "company", "Riddles and Jigsaw Puzzles GmbH");
|
|
validateCustomField(
|
|
cipher.fields,
|
|
"download_link",
|
|
"https://limuxcompany.nullvalue.test/5.10.1000/isos"
|
|
);
|
|
validateCustomField(cipher.fields, "publisher_name", "Limux Software and Hardware");
|
|
validateCustomField(cipher.fields, "publisher_website", "https://limuxcompany.nullvalue.test/");
|
|
validateCustomField(cipher.fields, "retail_price", "$999");
|
|
validateCustomField(cipher.fields, "support_email", "support@nullvalue.test");
|
|
validateCustomField(cipher.fields, "order_date", "Thu, 01 Apr 2021 12:01:00 GMT");
|
|
validateCustomField(cipher.fields, "order_number", "594839");
|
|
validateCustomField(cipher.fields, "order_total", "$1086.59");
|
|
});
|
|
|
|
it("should parse category 101 - BankAccount", async () => {
|
|
const importer = new Importer();
|
|
const jsonString = JSON.stringify(BankAccountData);
|
|
const result = await importer.parse(jsonString);
|
|
expect(result != null).toBe(true);
|
|
const cipher = result.ciphers.shift();
|
|
expect(cipher.type).toEqual(CipherType.Card);
|
|
expect(cipher.name).toEqual("Bank Account");
|
|
expect(cipher.notes).toEqual("My Bank Account");
|
|
|
|
expect(cipher.card.cardholderName).toEqual("Cool Guy");
|
|
|
|
expect(cipher.fields.length).toEqual(9);
|
|
validateCustomField(cipher.fields, "bankName", "Super Credit Union");
|
|
validateCustomField(cipher.fields, "accountType", "checking");
|
|
validateCustomField(cipher.fields, "routingNo", "111000999");
|
|
validateCustomField(cipher.fields, "accountNo", "192837465918273645");
|
|
validateCustomField(cipher.fields, "swift", "123456");
|
|
validateCustomField(cipher.fields, "iban", "DE12 123456");
|
|
validateCustomField(cipher.fields, "telephonePin", "5555");
|
|
validateCustomField(cipher.fields, "branchPhone", "9399399933");
|
|
validateCustomField(cipher.fields, "branchAddress", "1 Fifth Avenue");
|
|
});
|
|
|
|
it("should parse category 102 - Database", async () => {
|
|
const importer = new Importer();
|
|
const jsonString = JSON.stringify(DatabaseData);
|
|
const result = await importer.parse(jsonString);
|
|
expect(result != null).toBe(true);
|
|
const cipher = result.ciphers.shift();
|
|
|
|
expect(cipher.type).toEqual(CipherType.Login);
|
|
expect(cipher.name).toEqual("Database");
|
|
expect(cipher.notes).toEqual("My Database");
|
|
|
|
const login = cipher.login;
|
|
expect(login.username).toEqual("cooldbuser");
|
|
expect(login.password).toEqual("^+kTjhLaN7wVPAhGU)*J");
|
|
|
|
expect(cipher.fields.length).toEqual(7);
|
|
validateCustomField(cipher.fields, "database_type", "postgresql");
|
|
validateCustomField(cipher.fields, "hostname", "my.secret.db.server");
|
|
validateCustomField(cipher.fields, "port", "1337");
|
|
validateCustomField(cipher.fields, "database", "user_database");
|
|
validateCustomField(cipher.fields, "sid", "ASDIUFU-283234");
|
|
validateCustomField(cipher.fields, "alias", "cdbu");
|
|
validateCustomField(cipher.fields, "options", "ssh");
|
|
});
|
|
|
|
it("should parse category 103 - Drivers license", async () => {
|
|
const importer = new Importer();
|
|
const jsonString = JSON.stringify(DriversLicenseData);
|
|
const result = await importer.parse(jsonString);
|
|
expect(result != null).toBe(true);
|
|
const cipher = result.ciphers.shift();
|
|
expect(cipher.name).toEqual("Michael Scarn");
|
|
expect(cipher.subTitle).toEqual("Michael Scarn");
|
|
expect(cipher.notes).toEqual("My Driver's License");
|
|
|
|
const identity = cipher.identity;
|
|
expect(identity.firstName).toEqual("Michael");
|
|
expect(identity.middleName).toBeNull();
|
|
expect(identity.lastName).toEqual("Scarn");
|
|
expect(identity.address1).toEqual("2120 Mifflin Rd.");
|
|
expect(identity.state).toEqual("Pennsylvania");
|
|
expect(identity.country).toEqual("United States");
|
|
expect(identity.licenseNumber).toEqual("12345678901");
|
|
|
|
expect(cipher.fields.length).toEqual(6);
|
|
validateCustomField(cipher.fields, "birthdate", "Sun, 01 Jan 1978 12:01:00 GMT");
|
|
validateCustomField(cipher.fields, "sex", "male");
|
|
validateCustomField(cipher.fields, "height", "5'11\"");
|
|
validateCustomField(cipher.fields, "class", "C");
|
|
validateCustomField(cipher.fields, "conditions", "B");
|
|
validateCustomField(cipher.fields, "expiry_date", "203012");
|
|
});
|
|
|
|
it("should parse category 104 - Outdoor License", async () => {
|
|
const importer = new Importer();
|
|
const jsonString = JSON.stringify(OutdoorLicenseData);
|
|
const result = await importer.parse(jsonString);
|
|
expect(result != null).toBe(true);
|
|
const cipher = result.ciphers.shift();
|
|
|
|
expect(cipher.type).toEqual(CipherType.Identity);
|
|
expect(cipher.name).toEqual("Harvest License");
|
|
expect(cipher.subTitle).toEqual("Cash Bandit");
|
|
expect(cipher.notes).toEqual("My Outdoor License");
|
|
|
|
const identity = cipher.identity;
|
|
expect(identity.firstName).toEqual("Cash");
|
|
expect(identity.middleName).toBeNull();
|
|
expect(identity.lastName).toEqual("Bandit");
|
|
expect(identity.state).toEqual("Washington");
|
|
expect(identity.country).toEqual("United States of America");
|
|
|
|
expect(cipher.fields.length).toEqual(4);
|
|
validateCustomField(cipher.fields, "valid_from", "Thu, 01 Apr 2021 12:01:00 GMT");
|
|
validateCustomField(cipher.fields, "expires", "Fri, 01 Apr 2044 12:01:00 GMT");
|
|
validateCustomField(cipher.fields, "game", "Bananas,blueberries,corn");
|
|
validateCustomField(cipher.fields, "quota", "100/each");
|
|
});
|
|
|
|
it("should parse category 105 - Membership", async () => {
|
|
const importer = new Importer();
|
|
const jsonString = JSON.stringify(MembershipData);
|
|
const result = await importer.parse(jsonString);
|
|
expect(result != null).toBe(true);
|
|
const cipher = result.ciphers.shift();
|
|
|
|
expect(cipher.type).toEqual(CipherType.Identity);
|
|
expect(cipher.name).toEqual("Library Card");
|
|
|
|
const identity = cipher.identity;
|
|
expect(identity.firstName).toEqual("George");
|
|
expect(identity.middleName).toBeNull();
|
|
expect(identity.lastName).toEqual("Engels");
|
|
expect(identity.company).toEqual("National Public Library");
|
|
expect(identity.phone).toEqual("9995555555");
|
|
|
|
expect(cipher.fields.length).toEqual(5);
|
|
validateCustomField(cipher.fields, "website", "https://npl.nullvalue.gov.test");
|
|
validateCustomField(cipher.fields, "member_since", "199901");
|
|
validateCustomField(cipher.fields, "expiry_date", "203412");
|
|
validateCustomField(cipher.fields, "membership_no", "64783862");
|
|
validateCustomField(cipher.fields, "pin", "19191");
|
|
});
|
|
|
|
it("should parse category 106 - Passport", async () => {
|
|
const importer = new Importer();
|
|
const jsonString = JSON.stringify(PassportData);
|
|
const result = await importer.parse(jsonString);
|
|
expect(result != null).toBe(true);
|
|
const cipher = result.ciphers.shift();
|
|
|
|
expect(cipher.type).toEqual(CipherType.Identity);
|
|
expect(cipher.name).toEqual("Mr. Globewide");
|
|
|
|
const identity = cipher.identity;
|
|
expect(identity.firstName).toEqual("David");
|
|
expect(identity.middleName).toBeNull();
|
|
expect(identity.lastName).toEqual("Global");
|
|
expect(identity.passportNumber).toEqual("76436847");
|
|
|
|
expect(cipher.fields.length).toEqual(8);
|
|
validateCustomField(cipher.fields, "type", "US Passport");
|
|
validateCustomField(cipher.fields, "sex", "female");
|
|
validateCustomField(cipher.fields, "nationality", "International");
|
|
validateCustomField(cipher.fields, "issuing_authority", "Department of State");
|
|
validateCustomField(cipher.fields, "birthdate", "Fri, 01 Apr 1983 12:01:00 GMT");
|
|
validateCustomField(cipher.fields, "birthplace", "A cave somewhere in Maine");
|
|
validateCustomField(cipher.fields, "issue_date", "Wed, 01 Jan 2020 12:01:00 GMT");
|
|
validateCustomField(cipher.fields, "expiry_date", "Sat, 01 Jan 2050 12:01:00 GMT");
|
|
});
|
|
|
|
it("should parse category 107 - RewardsProgram", async () => {
|
|
const importer = new Importer();
|
|
const jsonString = JSON.stringify(RewardsProgramData);
|
|
const result = await importer.parse(jsonString);
|
|
expect(result != null).toBe(true);
|
|
const cipher = result.ciphers.shift();
|
|
|
|
expect(cipher.type).toEqual(CipherType.Identity);
|
|
expect(cipher.name).toEqual("Retail Reward Thing");
|
|
|
|
const identity = cipher.identity;
|
|
expect(identity.firstName).toEqual("Chef");
|
|
expect(identity.middleName).toBeNull();
|
|
expect(identity.lastName).toEqual("Coldroom");
|
|
expect(identity.company).toEqual("Super Cool Store Co.");
|
|
|
|
expect(cipher.fields.length).toEqual(7);
|
|
validateCustomField(cipher.fields, "membership_no", "member-29813569");
|
|
validateCustomField(cipher.fields, "pin", "99913");
|
|
validateCustomField(cipher.fields, "additional_no", "additional member id");
|
|
validateCustomField(cipher.fields, "member_since", "202101");
|
|
validateCustomField(cipher.fields, "customer_service_phone", "123456");
|
|
validateCustomField(cipher.fields, "reservations_phone", "123456");
|
|
validateCustomField(cipher.fields, "website", "supercoolstore.com");
|
|
});
|
|
|
|
it("should parse category 108 - SSN", async () => {
|
|
const importer = new Importer();
|
|
const jsonString = JSON.stringify(SSNData);
|
|
const result = await importer.parse(jsonString);
|
|
expect(result != null).toBe(true);
|
|
const cipher = result.ciphers.shift();
|
|
expect(cipher.name).toEqual("SSN");
|
|
|
|
const identity = cipher.identity;
|
|
expect(identity.firstName).toEqual("Jack");
|
|
expect(identity.middleName).toBeNull();
|
|
expect(identity.lastName).toEqual("Judd");
|
|
expect(identity.ssn).toEqual("131-216-1900");
|
|
});
|
|
|
|
it("should parse category 109 - WirelessRouter", async () => {
|
|
const importer = new Importer();
|
|
const jsonString = JSON.stringify(WirelessRouterData);
|
|
const result = await importer.parse(jsonString);
|
|
expect(result != null).toBe(true);
|
|
const cipher = result.ciphers.shift();
|
|
|
|
expect(cipher.type).toEqual(CipherType.Login);
|
|
expect(cipher.name).toEqual("Wireless Router");
|
|
expect(cipher.notes).toEqual("My Wifi Router Config");
|
|
|
|
expect(cipher.login.password).toEqual("BqatGTVQ9TCN72tLbjrsHqkb");
|
|
|
|
expect(cipher.fields.length).toEqual(7);
|
|
validateCustomField(cipher.fields, "name", "pixel 2Xl");
|
|
validateCustomField(cipher.fields, "server", "127.0.0.1");
|
|
validateCustomField(cipher.fields, "airport_id", "some airportId");
|
|
validateCustomField(cipher.fields, "network_name", "some network name");
|
|
validateCustomField(cipher.fields, "wireless_security", "WPA");
|
|
validateCustomField(cipher.fields, "wireless_password", "wifipassword");
|
|
validateCustomField(cipher.fields, "disk_password", "diskpassword");
|
|
});
|
|
|
|
it("should parse category 110 - Server", async () => {
|
|
const importer = new Importer();
|
|
const jsonString = JSON.stringify(ServerData);
|
|
const result = await importer.parse(jsonString);
|
|
expect(result != null).toBe(true);
|
|
const cipher = result.ciphers.shift();
|
|
|
|
expect(cipher.type).toEqual(CipherType.Login);
|
|
expect(cipher.name).toEqual("Super Cool Server");
|
|
expect(cipher.notes).toEqual("My Server");
|
|
|
|
expect(cipher.login.username).toEqual("frankly-notsure");
|
|
expect(cipher.login.password).toEqual("*&YHJI87yjy78u");
|
|
expect(cipher.login.uri).toEqual("https://coolserver.nullvalue.test");
|
|
|
|
expect(cipher.fields.length).toEqual(7);
|
|
validateCustomField(
|
|
cipher.fields,
|
|
"admin_console_url",
|
|
"https://coolserver.nullvalue.test/admin"
|
|
);
|
|
validateCustomField(cipher.fields, "admin_console_username", "frankly-idontknowwhatimdoing");
|
|
validateCustomField(cipher.fields, "admin_console_password", "^%RY&^YUiju8iUYHJI(U");
|
|
validateCustomField(cipher.fields, "name", "Private Hosting Provider Inc.");
|
|
validateCustomField(cipher.fields, "website", "https://phpi.nullvalue.test");
|
|
validateCustomField(
|
|
cipher.fields,
|
|
"support_contact_url",
|
|
"https://phpi.nullvalue.test/support"
|
|
);
|
|
validateCustomField(cipher.fields, "support_contact_phone", "8882569382");
|
|
});
|
|
|
|
it("should parse category 111 - EmailAccount", async () => {
|
|
const importer = new Importer();
|
|
const jsonString = JSON.stringify(EmailAccountData);
|
|
const result = await importer.parse(jsonString);
|
|
expect(result != null).toBe(true);
|
|
const cipher = result.ciphers.shift();
|
|
|
|
expect(cipher.type).toEqual(CipherType.SecureNote);
|
|
expect(cipher.name).toEqual("Email Config");
|
|
expect(cipher.notes).toEqual("My Email Config");
|
|
|
|
expect(cipher.fields.length).toEqual(17);
|
|
validateCustomField(cipher.fields, "pop_type", "either");
|
|
validateCustomField(cipher.fields, "pop_username", "someuser@nullvalue.test");
|
|
validateCustomField(cipher.fields, "pop_server", "mailserver.nullvalue.test");
|
|
validateCustomField(cipher.fields, "pop_port", "587");
|
|
validateCustomField(cipher.fields, "pop_password", "u1jsf<UI*&YU&^T");
|
|
validateCustomField(cipher.fields, "pop_security", "TLS");
|
|
validateCustomField(cipher.fields, "pop_authentication", "kerberos_v5");
|
|
validateCustomField(cipher.fields, "smtp_server", "mailserver.nullvalue.test");
|
|
validateCustomField(cipher.fields, "smtp_port", "589");
|
|
validateCustomField(cipher.fields, "smtp_username", "someuser@nullvalue.test");
|
|
validateCustomField(cipher.fields, "smtp_password", "(*1674%^UIUJ*UI(IUI8u98uyy");
|
|
validateCustomField(cipher.fields, "smtp_security", "TLS");
|
|
validateCustomField(cipher.fields, "smtp_authentication", "password");
|
|
validateCustomField(cipher.fields, "provider", "Telum");
|
|
validateCustomField(cipher.fields, "provider_website", "https://telum.nullvalue.test");
|
|
validateCustomField(cipher.fields, "phone_local", "2346666666");
|
|
validateCustomField(cipher.fields, "phone_tollfree", "18005557777");
|
|
});
|
|
|
|
it("should parse category 112 - API Credentials", async () => {
|
|
const importer = new Importer();
|
|
const jsonString = JSON.stringify(APICredentialsData);
|
|
const result = await importer.parse(jsonString);
|
|
expect(result != null).toBe(true);
|
|
const cipher = result.ciphers.shift();
|
|
|
|
expect(cipher.type).toEqual(CipherType.Login);
|
|
expect(cipher.name).toEqual("API Credential");
|
|
expect(cipher.notes).toEqual("My API Credential");
|
|
|
|
expect(cipher.login.username).toEqual("apiuser@nullvalue.test");
|
|
expect(cipher.login.password).toEqual("apiapiapiapiapiapiappy");
|
|
expect(cipher.login.uri).toEqual("http://not.your.everyday.hostname");
|
|
|
|
expect(cipher.fields.length).toEqual(4);
|
|
validateCustomField(cipher.fields, "type", "jwt");
|
|
validateCustomField(cipher.fields, "filename", "filename.jwt");
|
|
validateCustomField(cipher.fields, "validFrom", "Mon, 04 Apr 2011 12:01:00 GMT");
|
|
validateCustomField(cipher.fields, "expires", "Tue, 01 Apr 2031 12:01:00 GMT");
|
|
});
|
|
|
|
it("should create secure notes", async () => {
|
|
const importer = new Importer();
|
|
const result = await importer.parse(SecureNoteDataJson);
|
|
expect(result != null).toBe(true);
|
|
const cipher = result.ciphers.shift();
|
|
|
|
expect(cipher.name).toEqual("Secure Note #1");
|
|
expect(cipher.notes).toEqual(
|
|
"This is my secure note. \n\nLorem ipsum expecto patronum. \nThe quick brown fox jumped over the lazy dog."
|
|
);
|
|
expect(cipher.secureNote.type).toEqual(SecureNoteType.Generic);
|
|
});
|
|
|
|
it("should parse category 113 - Medical Record", async () => {
|
|
const importer = new Importer();
|
|
const jsonString = JSON.stringify(MedicalRecordData);
|
|
const result = await importer.parse(jsonString);
|
|
expect(result != null).toBe(true);
|
|
const cipher = result.ciphers.shift();
|
|
expect(cipher.type).toEqual(CipherType.SecureNote);
|
|
expect(cipher.name).toEqual("Some Health Record");
|
|
expect(cipher.notes).toEqual("Some notes about my medical history");
|
|
expect(cipher.secureNote.type).toEqual(SecureNoteType.Generic);
|
|
|
|
expect(cipher.fields.length).toEqual(8);
|
|
validateCustomField(cipher.fields, "date", "Sat, 01 Jan 2022 12:01:00 GMT");
|
|
validateCustomField(cipher.fields, "location", "some hospital/clinic");
|
|
validateCustomField(cipher.fields, "healthcareprofessional", "Some Doctor");
|
|
validateCustomField(cipher.fields, "patient", "Me");
|
|
validateCustomField(cipher.fields, "reason", "unwell");
|
|
validateCustomField(cipher.fields, "medication", "Insuline");
|
|
validateCustomField(cipher.fields, "dosage", "1");
|
|
validateCustomField(cipher.fields, "notes", "multiple times a day");
|
|
});
|
|
|
|
it("should create folders", async () => {
|
|
const importer = new Importer();
|
|
const result = await importer.parse(SanitizedExportJson);
|
|
expect(result != null).toBe(true);
|
|
|
|
const folders = result.folders;
|
|
expect(folders.length).toBe(5);
|
|
expect(folders[0].name).toBe("Movies");
|
|
expect(folders[1].name).toBe("Finance");
|
|
expect(folders[2].name).toBe("Travel");
|
|
expect(folders[3].name).toBe("Education");
|
|
expect(folders[4].name).toBe("Starter Kit");
|
|
|
|
// Check that ciphers have a folder assigned to them
|
|
expect(result.ciphers.filter((c) => c.folderId === folders[0].id).length).toBeGreaterThan(0);
|
|
expect(result.ciphers.filter((c) => c.folderId === folders[1].id).length).toBeGreaterThan(0);
|
|
expect(result.ciphers.filter((c) => c.folderId === folders[2].id).length).toBeGreaterThan(0);
|
|
expect(result.ciphers.filter((c) => c.folderId === folders[3].id).length).toBeGreaterThan(0);
|
|
expect(result.ciphers.filter((c) => c.folderId === folders[4].id).length).toBeGreaterThan(0);
|
|
});
|
|
|
|
it("should create collections if part of an organization", async () => {
|
|
const importer = new Importer();
|
|
importer.organizationId = Utils.newGuid();
|
|
const result = await importer.parse(SanitizedExportJson);
|
|
expect(result != null).toBe(true);
|
|
|
|
const collections = result.collections;
|
|
expect(collections.length).toBe(5);
|
|
expect(collections[0].name).toBe("Movies");
|
|
expect(collections[1].name).toBe("Finance");
|
|
expect(collections[2].name).toBe("Travel");
|
|
expect(collections[3].name).toBe("Education");
|
|
expect(collections[4].name).toBe("Starter Kit");
|
|
});
|
|
});
|