mirror of
https://github.com/bitwarden/browser
synced 2026-01-01 08:03:20 +00:00
Merge master into feature/org-admin-refresh (#4072)
* 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>
This commit is contained in:
@@ -479,6 +479,7 @@ export abstract class ApiService {
|
||||
putDeviceVerificationSettings: (
|
||||
request: DeviceVerificationRequest
|
||||
) => Promise<DeviceVerificationResponse>;
|
||||
getKnownDevice: (email: string, deviceIdentifier: string) => Promise<boolean>;
|
||||
|
||||
getEmergencyAccessTrusted: () => Promise<ListResponse<EmergencyAccessGranteeDetailsResponse>>;
|
||||
getEmergencyAccessGranted: () => Promise<ListResponse<EmergencyAccessGrantorDetailsResponse>>;
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { IEncrypted } from "../interfaces/IEncrypted";
|
||||
import { Decryptable } from "../interfaces/decryptable.interface";
|
||||
import { InitializerMetadata } from "../interfaces/initializer-metadata.interface";
|
||||
import { EncArrayBuffer } from "../models/domain/enc-array-buffer";
|
||||
import { EncString } from "../models/domain/enc-string";
|
||||
import { SymmetricCryptoKey } from "../models/domain/symmetric-crypto-key";
|
||||
|
||||
export abstract class AbstractEncryptService {
|
||||
export abstract class EncryptService {
|
||||
abstract encrypt(plainValue: string | ArrayBuffer, key: SymmetricCryptoKey): Promise<EncString>;
|
||||
abstract encryptToBytes: (
|
||||
plainValue: ArrayBuffer,
|
||||
@@ -12,4 +14,8 @@ export abstract class AbstractEncryptService {
|
||||
abstract decryptToUtf8: (encString: EncString, key: SymmetricCryptoKey) => Promise<string>;
|
||||
abstract decryptToBytes: (encThing: IEncrypted, key: SymmetricCryptoKey) => Promise<ArrayBuffer>;
|
||||
abstract resolveLegacyKey: (key: SymmetricCryptoKey, encThing: IEncrypted) => SymmetricCryptoKey;
|
||||
abstract decryptItems: <T extends InitializerMetadata>(
|
||||
items: Decryptable<T>[],
|
||||
key: SymmetricCryptoKey
|
||||
) => Promise<T[]>;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ImportOption, ImportType } from "../enums/importOptions";
|
||||
import { ImportError } from "../importers/importError";
|
||||
import { ImportError } from "../importers/import-error";
|
||||
import { Importer } from "../importers/importer";
|
||||
|
||||
export abstract class ImportService {
|
||||
|
||||
7
libs/common/src/abstractions/login.service.ts
Normal file
7
libs/common/src/abstractions/login.service.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
export abstract class LoginService {
|
||||
getEmail: () => string;
|
||||
getRememberEmail: () => boolean;
|
||||
setEmail: (value: string) => void;
|
||||
setRememberEmail: (value: boolean) => void;
|
||||
clearValues: () => void;
|
||||
}
|
||||
@@ -4,8 +4,18 @@ import { Utils } from "../../misc/utils";
|
||||
import { Organization } from "../../models/domain/organization";
|
||||
import { I18nService } from "../i18n.service";
|
||||
|
||||
export function canAccessVaultTab(org: Organization): boolean {
|
||||
return org.isManager;
|
||||
}
|
||||
|
||||
export function canAccessSettingsTab(org: Organization): boolean {
|
||||
return org.isOwner;
|
||||
return (
|
||||
org.isOwner ||
|
||||
org.canManagePolicies ||
|
||||
org.canManageSso ||
|
||||
org.canManageScim ||
|
||||
org.canAccessImportExport
|
||||
);
|
||||
}
|
||||
|
||||
export function canAccessMembersTab(org: Organization): boolean {
|
||||
@@ -30,7 +40,8 @@ export function canAccessOrgAdmin(org: Organization): boolean {
|
||||
canAccessGroupsTab(org) ||
|
||||
canAccessReportingTab(org) ||
|
||||
canAccessBillingTab(org) ||
|
||||
canAccessSettingsTab(org)
|
||||
canAccessSettingsTab(org) ||
|
||||
canAccessVaultTab(org)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -50,6 +61,11 @@ export abstract class OrganizationService {
|
||||
get: (id: string) => Organization;
|
||||
getByIdentifier: (identifier: string) => Organization;
|
||||
getAll: (userId?: string) => Promise<Organization[]>;
|
||||
/**
|
||||
* @deprecated For the CLI only
|
||||
* @param id id of the organization
|
||||
*/
|
||||
getFromState: (id: string) => Promise<Organization>;
|
||||
canManageSponsorships: () => Promise<boolean>;
|
||||
hasOrganizations: () => boolean;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { BehaviorSubject, Observable } from "rxjs";
|
||||
import { Observable } from "rxjs";
|
||||
|
||||
import { KdfType } from "../enums/kdfType";
|
||||
import { ThemeType } from "../enums/themeType";
|
||||
@@ -27,7 +27,7 @@ import { CollectionView } from "../models/view/collection.view";
|
||||
import { SendView } from "../models/view/send.view";
|
||||
|
||||
export abstract class StateService<T extends Account = Account> {
|
||||
accounts: BehaviorSubject<{ [userId: string]: T }>;
|
||||
accounts$: Observable<{ [userId: string]: T }>;
|
||||
activeAccount$: Observable<string>;
|
||||
activeAccountUnlocked$: Observable<boolean>;
|
||||
|
||||
|
||||
4
libs/common/src/enums/event-system-user.ts
Normal file
4
libs/common/src/enums/event-system-user.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
// Note: the enum key is used to describe the EventSystemUser in the UI. Be careful about changing it.
|
||||
export enum EventSystemUser {
|
||||
SCIM = 1,
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ImportResult } from "../models/domain/import-result";
|
||||
|
||||
import { BaseImporter } from "./baseImporter";
|
||||
import { BaseImporter } from "./base-importer";
|
||||
import { Importer } from "./importer";
|
||||
|
||||
export class AscendoCsvImporter extends BaseImporter implements Importer {
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ImportResult } from "../models/domain/import-result";
|
||||
|
||||
import { BaseImporter } from "./baseImporter";
|
||||
import { BaseImporter } from "./base-importer";
|
||||
import { Importer } from "./importer";
|
||||
|
||||
export class AvastCsvImporter extends BaseImporter implements Importer {
|
||||
@@ -2,7 +2,7 @@ import { CipherType } from "../enums/cipherType";
|
||||
import { SecureNoteType } from "../enums/secureNoteType";
|
||||
import { ImportResult } from "../models/domain/import-result";
|
||||
|
||||
import { BaseImporter } from "./baseImporter";
|
||||
import { BaseImporter } from "./base-importer";
|
||||
import { Importer } from "./importer";
|
||||
|
||||
export class AvastJsonImporter extends BaseImporter implements Importer {
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ImportResult } from "../models/domain/import-result";
|
||||
|
||||
import { BaseImporter } from "./baseImporter";
|
||||
import { BaseImporter } from "./base-importer";
|
||||
import { Importer } from "./importer";
|
||||
|
||||
export class AviraCsvImporter extends BaseImporter implements Importer {
|
||||
@@ -9,7 +9,7 @@ import { FieldView } from "../models/view/field.view";
|
||||
import { LoginView } from "../models/view/login.view";
|
||||
import { SecureNoteView } from "../models/view/secure-note.view";
|
||||
|
||||
import { BaseImporter } from "./baseImporter";
|
||||
import { BaseImporter } from "./base-importer";
|
||||
import { Importer } from "./importer";
|
||||
|
||||
export class BitwardenCsvImporter extends BaseImporter implements Importer {
|
||||
@@ -6,7 +6,7 @@ import { CipherWithIdExport } from "../models/export/cipher-with-ids.export";
|
||||
import { CollectionWithIdExport } from "../models/export/collection-with-id.export";
|
||||
import { FolderWithIdExport } from "../models/export/folder-with-id.export";
|
||||
|
||||
import { BaseImporter } from "./baseImporter";
|
||||
import { BaseImporter } from "./base-importer";
|
||||
import { Importer } from "./importer";
|
||||
|
||||
export class BitwardenJsonImporter extends BaseImporter implements Importer {
|
||||
@@ -5,7 +5,7 @@ import { EncString } from "../models/domain/enc-string";
|
||||
import { ImportResult } from "../models/domain/import-result";
|
||||
import { SymmetricCryptoKey } from "../models/domain/symmetric-crypto-key";
|
||||
|
||||
import { BitwardenJsonImporter } from "./bitwardenJsonImporter";
|
||||
import { BitwardenJsonImporter } from "./bitwarden-json-importer";
|
||||
import { Importer } from "./importer";
|
||||
|
||||
interface BitwardenPasswordProtectedFileFormat {
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ImportResult } from "../models/domain/import-result";
|
||||
|
||||
import { BaseImporter } from "./baseImporter";
|
||||
import { BaseImporter } from "./base-importer";
|
||||
import { Importer } from "./importer";
|
||||
|
||||
export class BlackBerryCsvImporter extends BaseImporter implements Importer {
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ImportResult } from "../models/domain/import-result";
|
||||
|
||||
import { BaseImporter } from "./baseImporter";
|
||||
import { BaseImporter } from "./base-importer";
|
||||
import { Importer } from "./importer";
|
||||
|
||||
export class BlurCsvImporter extends BaseImporter implements Importer {
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ImportResult } from "../models/domain/import-result";
|
||||
|
||||
import { BaseImporter } from "./baseImporter";
|
||||
import { BaseImporter } from "./base-importer";
|
||||
import { Importer } from "./importer";
|
||||
|
||||
const OfficialProps = ["!group_id", "!group_name", "title", "username", "password", "URL", "id"];
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ImportResult } from "../models/domain/import-result";
|
||||
|
||||
import { BaseImporter } from "./baseImporter";
|
||||
import { BaseImporter } from "./base-importer";
|
||||
import { Importer } from "./importer";
|
||||
|
||||
export class ChromeCsvImporter extends BaseImporter implements Importer {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ImportResult } from "../models/domain/import-result";
|
||||
|
||||
import { BaseImporter } from "./baseImporter";
|
||||
import { BaseImporter } from "./base-importer";
|
||||
import { Importer } from "./importer";
|
||||
|
||||
export class ClipperzHtmlImporter extends BaseImporter implements Importer {
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ImportResult } from "../models/domain/import-result";
|
||||
|
||||
import { BaseImporter } from "./baseImporter";
|
||||
import { BaseImporter } from "./base-importer";
|
||||
import { Importer } from "./importer";
|
||||
|
||||
export class CodebookCsvImporter extends BaseImporter implements Importer {
|
||||
@@ -5,7 +5,7 @@ import { CardView } from "../../models/view/card.view";
|
||||
import { CipherView } from "../../models/view/cipher.view";
|
||||
import { IdentityView } from "../../models/view/identity.view";
|
||||
import { LoginView } from "../../models/view/login.view";
|
||||
import { BaseImporter } from "../baseImporter";
|
||||
import { BaseImporter } from "../base-importer";
|
||||
import { Importer } from "../importer";
|
||||
|
||||
import {
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
PaymentsRecord,
|
||||
PersonalInformationRecord,
|
||||
SecureNoteRecord,
|
||||
} from "./types/dashlaneCsvTypes";
|
||||
} from "./types/dashlane-csv-types";
|
||||
|
||||
const _mappedCredentialsColums = new Set([
|
||||
"title",
|
||||
@@ -5,7 +5,7 @@ import { CardView } from "../../models/view/card.view";
|
||||
import { CipherView } from "../../models/view/cipher.view";
|
||||
import { IdentityView } from "../../models/view/identity.view";
|
||||
import { SecureNoteView } from "../../models/view/secure-note.view";
|
||||
import { BaseImporter } from "../baseImporter";
|
||||
import { BaseImporter } from "../base-importer";
|
||||
import { Importer } from "../importer";
|
||||
|
||||
const HandledResults = new Set([
|
||||
@@ -2,7 +2,7 @@ import { CipherType } from "../enums/cipherType";
|
||||
import { ImportResult } from "../models/domain/import-result";
|
||||
import { CardView } from "../models/view/card.view";
|
||||
|
||||
import { BaseImporter } from "./baseImporter";
|
||||
import { BaseImporter } from "./base-importer";
|
||||
import { Importer } from "./importer";
|
||||
|
||||
export class EncryptrCsvImporter extends BaseImporter implements Importer {
|
||||
@@ -4,7 +4,7 @@ import { ImportResult } from "../models/domain/import-result";
|
||||
import { CardView } from "../models/view/card.view";
|
||||
import { SecureNoteView } from "../models/view/secure-note.view";
|
||||
|
||||
import { BaseImporter } from "./baseImporter";
|
||||
import { BaseImporter } from "./base-importer";
|
||||
import { Importer } from "./importer";
|
||||
|
||||
export class EnpassCsvImporter extends BaseImporter implements Importer {
|
||||
@@ -5,7 +5,7 @@ import { CardView } from "../models/view/card.view";
|
||||
import { CipherView } from "../models/view/cipher.view";
|
||||
import { FolderView } from "../models/view/folder.view";
|
||||
|
||||
import { BaseImporter } from "./baseImporter";
|
||||
import { BaseImporter } from "./base-importer";
|
||||
import { Importer } from "./importer";
|
||||
|
||||
export class EnpassJsonImporter extends BaseImporter implements Importer {
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ImportResult } from "../models/domain/import-result";
|
||||
|
||||
import { BaseImporter } from "./baseImporter";
|
||||
import { BaseImporter } from "./base-importer";
|
||||
import { Importer } from "./importer";
|
||||
|
||||
export class FirefoxCsvImporter extends BaseImporter implements Importer {
|
||||
@@ -2,7 +2,7 @@ import { CipherType } from "../enums/cipherType";
|
||||
import { ImportResult } from "../models/domain/import-result";
|
||||
import { CardView } from "../models/view/card.view";
|
||||
|
||||
import { BaseImporter } from "./baseImporter";
|
||||
import { BaseImporter } from "./base-importer";
|
||||
import { Importer } from "./importer";
|
||||
|
||||
export class FSecureFskImporter extends BaseImporter implements Importer {
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ImportResult } from "../models/domain/import-result";
|
||||
|
||||
import { BaseImporter } from "./baseImporter";
|
||||
import { BaseImporter } from "./base-importer";
|
||||
import { Importer } from "./importer";
|
||||
|
||||
export class GnomeJsonImporter extends BaseImporter implements Importer {
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ImportResult } from "../models/domain/import-result";
|
||||
|
||||
import { BaseImporter } from "./baseImporter";
|
||||
import { BaseImporter } from "./base-importer";
|
||||
import { Importer } from "./importer";
|
||||
|
||||
const NotesHeader = "Notes\n\n";
|
||||
@@ -2,7 +2,7 @@ import { FieldType } from "../enums/fieldType";
|
||||
import { ImportResult } from "../models/domain/import-result";
|
||||
import { FolderView } from "../models/view/folder.view";
|
||||
|
||||
import { BaseImporter } from "./baseImporter";
|
||||
import { BaseImporter } from "./base-importer";
|
||||
import { Importer } from "./importer";
|
||||
|
||||
export class KeePass2XmlImporter extends BaseImporter implements Importer {
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ImportResult } from "../models/domain/import-result";
|
||||
|
||||
import { BaseImporter } from "./baseImporter";
|
||||
import { BaseImporter } from "./base-importer";
|
||||
import { Importer } from "./importer";
|
||||
|
||||
export class KeePassXCsvImporter extends BaseImporter implements Importer {
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ImportResult } from "../../models/domain/import-result";
|
||||
import { BaseImporter } from "../baseImporter";
|
||||
import { BaseImporter } from "../base-importer";
|
||||
import { Importer } from "../importer";
|
||||
|
||||
export class KeeperCsvImporter extends BaseImporter implements Importer {
|
||||
@@ -1,8 +1,8 @@
|
||||
import { ImportResult } from "../../models/domain/import-result";
|
||||
import { BaseImporter } from "../baseImporter";
|
||||
import { BaseImporter } from "../base-importer";
|
||||
import { Importer } from "../importer";
|
||||
|
||||
import { KeeperJsonExport, RecordsEntity } from "./types/keeperJsonTypes";
|
||||
import { KeeperJsonExport, RecordsEntity } from "./types/keeper-json-types";
|
||||
|
||||
export class KeeperJsonImporter extends BaseImporter implements Importer {
|
||||
parse(data: string): Promise<ImportResult> {
|
||||
@@ -8,7 +8,7 @@ import { IdentityView } from "../models/view/identity.view";
|
||||
import { LoginView } from "../models/view/login.view";
|
||||
import { SecureNoteView } from "../models/view/secure-note.view";
|
||||
|
||||
import { BaseImporter } from "./baseImporter";
|
||||
import { BaseImporter } from "./base-importer";
|
||||
import { Importer } from "./importer";
|
||||
|
||||
export class LastPassCsvImporter extends BaseImporter implements Importer {
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ImportResult } from "../models/domain/import-result";
|
||||
|
||||
import { BaseImporter } from "./baseImporter";
|
||||
import { BaseImporter } from "./base-importer";
|
||||
import { Importer } from "./importer";
|
||||
|
||||
export class LogMeOnceCsvImporter extends BaseImporter implements Importer {
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ImportResult } from "../models/domain/import-result";
|
||||
|
||||
import { BaseImporter } from "./baseImporter";
|
||||
import { BaseImporter } from "./base-importer";
|
||||
import { Importer } from "./importer";
|
||||
|
||||
export class MeldiumCsvImporter extends BaseImporter implements Importer {
|
||||
@@ -3,7 +3,7 @@ import { SecureNoteType } from "../enums/secureNoteType";
|
||||
import { ImportResult } from "../models/domain/import-result";
|
||||
import { SecureNoteView } from "../models/view/secure-note.view";
|
||||
|
||||
import { BaseImporter } from "./baseImporter";
|
||||
import { BaseImporter } from "./base-importer";
|
||||
import { Importer } from "./importer";
|
||||
|
||||
export class MSecureCsvImporter extends BaseImporter implements Importer {
|
||||
@@ -6,7 +6,7 @@ import { CipherView } from "../models/view/cipher.view";
|
||||
import { IdentityView } from "../models/view/identity.view";
|
||||
import { SecureNoteView } from "../models/view/secure-note.view";
|
||||
|
||||
import { BaseImporter } from "./baseImporter";
|
||||
import { BaseImporter } from "./base-importer";
|
||||
import { Importer } from "./importer";
|
||||
|
||||
const mappedBaseColumns = ["nickname", "additionalInfo"];
|
||||
@@ -4,7 +4,7 @@ import { ImportResult } from "../models/domain/import-result";
|
||||
import { CipherView } from "../models/view/cipher.view";
|
||||
import { LoginView } from "../models/view/login.view";
|
||||
|
||||
import { BaseImporter } from "./baseImporter";
|
||||
import { BaseImporter } from "./base-importer";
|
||||
import { Importer } from "./importer";
|
||||
|
||||
type nodePassCsvParsed = {
|
||||
@@ -7,7 +7,7 @@ import { CipherView } from "../../models/view/cipher.view";
|
||||
import { IdentityView } from "../../models/view/identity.view";
|
||||
import { PasswordHistoryView } from "../../models/view/password-history.view";
|
||||
import { SecureNoteView } from "../../models/view/secure-note.view";
|
||||
import { BaseImporter } from "../baseImporter";
|
||||
import { BaseImporter } from "../base-importer";
|
||||
import { Importer } from "../importer";
|
||||
|
||||
export class OnePassword1PifImporter extends BaseImporter implements Importer {
|
||||
@@ -9,7 +9,7 @@ import { IdentityView } from "../../models/view/identity.view";
|
||||
import { LoginView } from "../../models/view/login.view";
|
||||
import { PasswordHistoryView } from "../../models/view/password-history.view";
|
||||
import { SecureNoteView } from "../../models/view/secure-note.view";
|
||||
import { BaseImporter } from "../baseImporter";
|
||||
import { BaseImporter } from "../base-importer";
|
||||
import { Importer } from "../importer";
|
||||
|
||||
import {
|
||||
@@ -25,7 +25,7 @@ import {
|
||||
UrlsEntity,
|
||||
Value,
|
||||
VaultsEntity,
|
||||
} from "./types/onepassword1PuxImporterTypes";
|
||||
} from "./types/onepassword-1pux-importer-types";
|
||||
|
||||
export class OnePassword1PuxImporter extends BaseImporter implements Importer {
|
||||
result = new ImportResult();
|
||||
@@ -2,10 +2,10 @@ import { CipherType } from "../../enums/cipherType";
|
||||
import { FieldType } from "../../enums/fieldType";
|
||||
import { ImportResult } from "../../models/domain/import-result";
|
||||
import { CipherView } from "../../models/view/cipher.view";
|
||||
import { BaseImporter } from "../baseImporter";
|
||||
import { BaseImporter } from "../base-importer";
|
||||
import { Importer } from "../importer";
|
||||
|
||||
import { CipherImportContext } from "./cipherImportContext";
|
||||
import { CipherImportContext } from "./cipher-import-context";
|
||||
|
||||
export const IgnoredProperties = [
|
||||
"ainfo",
|
||||
@@ -4,7 +4,7 @@ import { CipherView } from "../../models/view/cipher.view";
|
||||
import { IdentityView } from "../../models/view/identity.view";
|
||||
import { Importer } from "../importer";
|
||||
|
||||
import { IgnoredProperties, OnePasswordCsvImporter } from "./onepasswordCsvImporter";
|
||||
import { IgnoredProperties, OnePasswordCsvImporter } from "./onepassword-csv-importer";
|
||||
|
||||
export class OnePasswordMacCsvImporter extends OnePasswordCsvImporter implements Importer {
|
||||
setCipherType(value: any, cipher: CipherView) {
|
||||
@@ -5,8 +5,8 @@ import { IdentityView } from "../../models/view/identity.view";
|
||||
import { LoginView } from "../../models/view/login.view";
|
||||
import { Importer } from "../importer";
|
||||
|
||||
import { CipherImportContext } from "./cipherImportContext";
|
||||
import { OnePasswordCsvImporter } from "./onepasswordCsvImporter";
|
||||
import { CipherImportContext } from "./cipher-import-context";
|
||||
import { OnePasswordCsvImporter } from "./onepassword-csv-importer";
|
||||
|
||||
export class OnePasswordWinCsvImporter extends OnePasswordCsvImporter implements Importer {
|
||||
constructor() {
|
||||
@@ -1,7 +1,7 @@
|
||||
import { ImportResult } from "../models/domain/import-result";
|
||||
import { CollectionView } from "../models/view/collection.view";
|
||||
|
||||
import { BaseImporter } from "./baseImporter";
|
||||
import { BaseImporter } from "./base-importer";
|
||||
import { Importer } from "./importer";
|
||||
|
||||
export class PadlockCsvImporter extends BaseImporter implements Importer {
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ImportResult } from "../models/domain/import-result";
|
||||
|
||||
import { BaseImporter } from "./baseImporter";
|
||||
import { BaseImporter } from "./base-importer";
|
||||
import { Importer } from "./importer";
|
||||
|
||||
export class PassKeepCsvImporter extends BaseImporter implements Importer {
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ImportResult } from "../models/domain/import-result";
|
||||
|
||||
import { BaseImporter } from "./baseImporter";
|
||||
import { BaseImporter } from "./base-importer";
|
||||
import { Importer } from "./importer";
|
||||
|
||||
export class PassmanJsonImporter extends BaseImporter implements Importer {
|
||||
@@ -1,7 +1,7 @@
|
||||
import { ImportResult } from "../models/domain/import-result";
|
||||
import { CollectionView } from "../models/view/collection.view";
|
||||
|
||||
import { BaseImporter } from "./baseImporter";
|
||||
import { BaseImporter } from "./base-importer";
|
||||
import { Importer } from "./importer";
|
||||
|
||||
export class PasspackCsvImporter extends BaseImporter implements Importer {
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ImportResult } from "../models/domain/import-result";
|
||||
|
||||
import { BaseImporter } from "./baseImporter";
|
||||
import { BaseImporter } from "./base-importer";
|
||||
import { Importer } from "./importer";
|
||||
|
||||
export class PasswordAgentCsvImporter extends BaseImporter implements Importer {
|
||||
@@ -3,7 +3,7 @@ import { ImportResult } from "../models/domain/import-result";
|
||||
import { CardView } from "../models/view/card.view";
|
||||
import { FolderView } from "../models/view/folder.view";
|
||||
|
||||
import { BaseImporter } from "./baseImporter";
|
||||
import { BaseImporter } from "./base-importer";
|
||||
import { Importer } from "./importer";
|
||||
|
||||
export class PasswordBossJsonImporter extends BaseImporter implements Importer {
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ImportResult } from "../models/domain/import-result";
|
||||
|
||||
import { BaseImporter } from "./baseImporter";
|
||||
import { BaseImporter } from "./base-importer";
|
||||
import { Importer } from "./importer";
|
||||
|
||||
export class PasswordDragonXmlImporter extends BaseImporter implements Importer {
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ImportResult } from "../models/domain/import-result";
|
||||
|
||||
import { BaseImporter } from "./baseImporter";
|
||||
import { BaseImporter } from "./base-importer";
|
||||
import { Importer } from "./importer";
|
||||
|
||||
export class PasswordSafeXmlImporter extends BaseImporter implements Importer {
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ImportResult } from "../models/domain/import-result";
|
||||
|
||||
import { BaseImporter } from "./baseImporter";
|
||||
import { BaseImporter } from "./base-importer";
|
||||
import { Importer } from "./importer";
|
||||
|
||||
export class PasswordWalletTxtImporter extends BaseImporter implements Importer {
|
||||
@@ -2,7 +2,7 @@ import { CipherType } from "../enums/cipherType";
|
||||
import { ImportResult } from "../models/domain/import-result";
|
||||
import { CardView } from "../models/view/card.view";
|
||||
|
||||
import { BaseImporter } from "./baseImporter";
|
||||
import { BaseImporter } from "./base-importer";
|
||||
import { Importer } from "./importer";
|
||||
|
||||
export class RememBearCsvImporter extends BaseImporter implements Importer {
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ImportResult } from "../models/domain/import-result";
|
||||
|
||||
import { BaseImporter } from "./baseImporter";
|
||||
import { BaseImporter } from "./base-importer";
|
||||
import { Importer } from "./importer";
|
||||
|
||||
export class RoboFormCsvImporter extends BaseImporter implements Importer {
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ImportResult } from "../models/domain/import-result";
|
||||
|
||||
import { BaseImporter } from "./baseImporter";
|
||||
import { BaseImporter } from "./base-importer";
|
||||
import { Importer } from "./importer";
|
||||
|
||||
export class SafariCsvImporter extends BaseImporter implements Importer {
|
||||
@@ -7,7 +7,7 @@ import { FieldView } from "../models/view/field.view";
|
||||
import { FolderView } from "../models/view/folder.view";
|
||||
import { SecureNoteView } from "../models/view/secure-note.view";
|
||||
|
||||
import { BaseImporter } from "./baseImporter";
|
||||
import { BaseImporter } from "./base-importer";
|
||||
import { Importer } from "./importer";
|
||||
|
||||
export class SafeInCloudXmlImporter extends BaseImporter implements Importer {
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ImportResult } from "../models/domain/import-result";
|
||||
|
||||
import { BaseImporter } from "./baseImporter";
|
||||
import { BaseImporter } from "./base-importer";
|
||||
import { Importer } from "./importer";
|
||||
|
||||
export class SaferPassCsvImporter extends BaseImporter implements Importer {
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ImportResult } from "../models/domain/import-result";
|
||||
|
||||
import { BaseImporter } from "./baseImporter";
|
||||
import { BaseImporter } from "./base-importer";
|
||||
import { Importer } from "./importer";
|
||||
|
||||
export class SecureSafeCsvImporter extends BaseImporter implements Importer {
|
||||
@@ -1,7 +1,7 @@
|
||||
import { ImportResult } from "../models/domain/import-result";
|
||||
import { CipherView } from "../models/view/cipher.view";
|
||||
|
||||
import { BaseImporter } from "./baseImporter";
|
||||
import { BaseImporter } from "./base-importer";
|
||||
import { Importer } from "./importer";
|
||||
|
||||
export class SplashIdCsvImporter extends BaseImporter implements Importer {
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ImportResult } from "../models/domain/import-result";
|
||||
|
||||
import { BaseImporter } from "./baseImporter";
|
||||
import { BaseImporter } from "./base-importer";
|
||||
import { Importer } from "./importer";
|
||||
|
||||
export class StickyPasswordXmlImporter extends BaseImporter implements Importer {
|
||||
@@ -4,7 +4,7 @@ import { ImportResult } from "../models/domain/import-result";
|
||||
import { CardView } from "../models/view/card.view";
|
||||
import { SecureNoteView } from "../models/view/secure-note.view";
|
||||
|
||||
import { BaseImporter } from "./baseImporter";
|
||||
import { BaseImporter } from "./base-importer";
|
||||
import { Importer } from "./importer";
|
||||
|
||||
const PropertiesToIgnore = [
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ImportResult } from "../models/domain/import-result";
|
||||
|
||||
import { BaseImporter } from "./baseImporter";
|
||||
import { BaseImporter } from "./base-importer";
|
||||
import { Importer } from "./importer";
|
||||
|
||||
export class UpmCsvImporter extends BaseImporter implements Importer {
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ImportResult } from "../models/domain/import-result";
|
||||
|
||||
import { BaseImporter } from "./baseImporter";
|
||||
import { BaseImporter } from "./base-importer";
|
||||
import { Importer } from "./importer";
|
||||
|
||||
export class YotiCsvImporter extends BaseImporter implements Importer {
|
||||
@@ -1,7 +1,7 @@
|
||||
import { ImportResult } from "../models/domain/import-result";
|
||||
import { CipherView } from "../models/view/cipher.view";
|
||||
|
||||
import { BaseImporter } from "./baseImporter";
|
||||
import { BaseImporter } from "./base-importer";
|
||||
import { Importer } from "./importer";
|
||||
|
||||
export class ZohoVaultCsvImporter extends BaseImporter implements Importer {
|
||||
12
libs/common/src/interfaces/decryptable.interface.ts
Normal file
12
libs/common/src/interfaces/decryptable.interface.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { SymmetricCryptoKey } from "../models/domain/symmetric-crypto-key";
|
||||
|
||||
import { InitializerMetadata } from "./initializer-metadata.interface";
|
||||
|
||||
/**
|
||||
* An object that contains EncStrings and knows how to decrypt them. This is usually a domain object with the
|
||||
* corresponding view object as the type argument.
|
||||
* @example Cipher implements Decryptable<CipherView>
|
||||
*/
|
||||
export interface Decryptable<TDecrypted extends InitializerMetadata> extends InitializerMetadata {
|
||||
decrypt: (key?: SymmetricCryptoKey) => Promise<TDecrypted>;
|
||||
}
|
||||
11
libs/common/src/interfaces/initializer-metadata.interface.ts
Normal file
11
libs/common/src/interfaces/initializer-metadata.interface.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { InitializerKey } from "../services/cryptography/initializer-key";
|
||||
|
||||
/**
|
||||
* This interface enables deserialization of arbitrary objects by recording their class name as an enum, which
|
||||
* will survive serialization. The enum can then be matched to a constructor or factory method for deserialization.
|
||||
* See get-class-initializer.ts for the initializer map.
|
||||
*/
|
||||
export interface InitializerMetadata {
|
||||
initializerKey: InitializerKey;
|
||||
toJSON?: () => { initializerKey: InitializerKey };
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
// required to avoid linting errors when there are no flags
|
||||
/* eslint-disable @typescript-eslint/ban-types */
|
||||
export type SharedFlags = {};
|
||||
export type SharedFlags = {
|
||||
multithreadDecryption: boolean;
|
||||
};
|
||||
|
||||
// required to avoid linting errors when there are no flags
|
||||
/* eslint-disable @typescript-eslint/ban-types */
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/* eslint-disable no-useless-escape */
|
||||
import { getHostname, parse } from "tldts";
|
||||
|
||||
import { AbstractEncryptService } from "../abstractions/abstractEncrypt.service";
|
||||
import { CryptoService } from "../abstractions/crypto.service";
|
||||
import { EncryptService } from "../abstractions/encrypt.service";
|
||||
import { I18nService } from "../abstractions/i18n.service";
|
||||
|
||||
const nodeURL = typeof window === "undefined" ? require("url") : null;
|
||||
@@ -14,7 +14,7 @@ declare global {
|
||||
|
||||
interface BitwardenContainerService {
|
||||
getCryptoService: () => CryptoService;
|
||||
getEncryptService: () => AbstractEncryptService;
|
||||
getEncryptService: () => EncryptService;
|
||||
}
|
||||
|
||||
export class Utils {
|
||||
|
||||
@@ -2,6 +2,8 @@ import { Jsonify } from "type-fest";
|
||||
|
||||
import { CipherRepromptType } from "../../enums/cipherRepromptType";
|
||||
import { CipherType } from "../../enums/cipherType";
|
||||
import { Decryptable } from "../../interfaces/decryptable.interface";
|
||||
import { InitializerKey } from "../../services/cryptography/initializer-key";
|
||||
import { CipherData } from "../data/cipher.data";
|
||||
import { LocalData } from "../data/local.data";
|
||||
import { CipherView } from "../view/cipher.view";
|
||||
@@ -17,7 +19,9 @@ import { Password } from "./password";
|
||||
import { SecureNote } from "./secure-note";
|
||||
import { SymmetricCryptoKey } from "./symmetric-crypto-key";
|
||||
|
||||
export class Cipher extends Domain {
|
||||
export class Cipher extends Domain implements Decryptable<CipherView> {
|
||||
readonly initializerKey = InitializerKey.Cipher;
|
||||
|
||||
id: string;
|
||||
organizationId: string;
|
||||
folderId: string;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { DeviceType } from "../../enums/deviceType";
|
||||
import { EventSystemUser } from "../../enums/event-system-user";
|
||||
import { EventType } from "../../enums/eventType";
|
||||
|
||||
import { BaseResponse } from "./base.response";
|
||||
@@ -20,6 +21,7 @@ export class EventResponse extends BaseResponse {
|
||||
deviceType: DeviceType;
|
||||
ipAddress: string;
|
||||
installationId: string;
|
||||
systemUser: EventSystemUser;
|
||||
|
||||
constructor(response: any) {
|
||||
super(response);
|
||||
@@ -39,5 +41,6 @@ export class EventResponse extends BaseResponse {
|
||||
this.deviceType = this.getResponseProperty("DeviceType");
|
||||
this.ipAddress = this.getResponseProperty("IpAddress");
|
||||
this.installationId = this.getResponseProperty("InstallationId");
|
||||
this.systemUser = this.getResponseProperty("SystemUser");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,20 @@
|
||||
import { BaseResponse } from "./base.response";
|
||||
import { CipherResponse } from "./cipher.response";
|
||||
import { CollectionResponse } from "./collection.response";
|
||||
import { ListResponse } from "./list.response";
|
||||
|
||||
export class OrganizationExportResponse extends BaseResponse {
|
||||
collections: ListResponse<CollectionResponse>;
|
||||
ciphers: ListResponse<CipherResponse>;
|
||||
collections: CollectionResponse[];
|
||||
ciphers: CipherResponse[];
|
||||
|
||||
constructor(response: any) {
|
||||
super(response);
|
||||
this.collections = this.getResponseProperty("Collections");
|
||||
this.ciphers = this.getResponseProperty("Ciphers");
|
||||
const collections = this.getResponseProperty("Collections");
|
||||
if (collections != null) {
|
||||
this.collections = collections.map((c: any) => new CollectionResponse(c));
|
||||
}
|
||||
const ciphers = this.getResponseProperty("Ciphers");
|
||||
if (ciphers != null) {
|
||||
this.ciphers = ciphers.map((c: any) => new CipherResponse(c));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ import { Jsonify } from "type-fest";
|
||||
import { CipherRepromptType } from "../../enums/cipherRepromptType";
|
||||
import { CipherType } from "../../enums/cipherType";
|
||||
import { LinkedIdType } from "../../enums/linkedIdType";
|
||||
import { InitializerMetadata } from "../../interfaces/initializer-metadata.interface";
|
||||
import { InitializerKey } from "../../services/cryptography/initializer-key";
|
||||
import { LocalData } from "../data/local.data";
|
||||
import { Cipher } from "../domain/cipher";
|
||||
|
||||
@@ -15,7 +17,9 @@ import { PasswordHistoryView } from "./password-history.view";
|
||||
import { SecureNoteView } from "./secure-note.view";
|
||||
import { View } from "./view";
|
||||
|
||||
export class CipherView implements View {
|
||||
export class CipherView implements View, InitializerMetadata {
|
||||
readonly initializerKey = InitializerKey.CipherView;
|
||||
|
||||
id: string = null;
|
||||
organizationId: string = null;
|
||||
folderId: string = null;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { EventSystemUser } from "../../enums/event-system-user";
|
||||
import { EventType } from "../../enums/eventType";
|
||||
|
||||
export class EventView {
|
||||
@@ -12,6 +13,7 @@ export class EventView {
|
||||
ip: string;
|
||||
type: EventType;
|
||||
installationId: string;
|
||||
systemUser: EventSystemUser;
|
||||
|
||||
constructor(data: Required<EventView>) {
|
||||
this.message = data.message;
|
||||
@@ -25,5 +27,6 @@ export class EventView {
|
||||
this.ip = data.ip;
|
||||
this.type = data.type;
|
||||
this.installationId = data.installationId;
|
||||
this.systemUser = data.systemUser;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1518,6 +1518,12 @@ export class ApiService implements ApiServiceAbstraction {
|
||||
return new DeviceVerificationResponse(r);
|
||||
}
|
||||
|
||||
async getKnownDevice(email: string, deviceIdentifier: string): Promise<boolean> {
|
||||
const path = `/devices/knowndevice/${email}/${deviceIdentifier}`;
|
||||
const r = await this.send("GET", path, null, false, true);
|
||||
return r as boolean;
|
||||
}
|
||||
|
||||
// Emergency Access APIs
|
||||
|
||||
async getEmergencyAccessTrusted(): Promise<ListResponse<EmergencyAccessGranteeDetailsResponse>> {
|
||||
@@ -2354,16 +2360,6 @@ export class ApiService implements ApiServiceAbstraction {
|
||||
tokenError: boolean,
|
||||
authed: boolean
|
||||
): Promise<ErrorResponse> {
|
||||
if (
|
||||
authed &&
|
||||
((tokenError && response.status === 400) ||
|
||||
response.status === 401 ||
|
||||
response.status === 403)
|
||||
) {
|
||||
await this.logoutCallback(true);
|
||||
return null;
|
||||
}
|
||||
|
||||
let responseJson: any = null;
|
||||
if (this.isJsonResponse(response)) {
|
||||
responseJson = await response.json();
|
||||
@@ -2371,6 +2367,20 @@ export class ApiService implements ApiServiceAbstraction {
|
||||
responseJson = { Message: await response.text() };
|
||||
}
|
||||
|
||||
if (authed) {
|
||||
if (
|
||||
response.status === 401 ||
|
||||
response.status === 403 ||
|
||||
(tokenError &&
|
||||
response.status === 400 &&
|
||||
responseJson != null &&
|
||||
responseJson.error === "invalid_grant")
|
||||
) {
|
||||
await this.logoutCallback(true);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return new ErrorResponse(responseJson, response.status, tokenError);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import { firstValueFrom } from "rxjs";
|
||||
import { ApiService } from "../abstractions/api.service";
|
||||
import { CipherService as CipherServiceAbstraction } from "../abstractions/cipher.service";
|
||||
import { CryptoService } from "../abstractions/crypto.service";
|
||||
import { EncryptService } from "../abstractions/encrypt.service";
|
||||
import { FileUploadService } from "../abstractions/fileUpload.service";
|
||||
import { I18nService } from "../abstractions/i18n.service";
|
||||
import { LogService } from "../abstractions/log.service";
|
||||
@@ -65,7 +66,8 @@ export class CipherService implements CipherServiceAbstraction {
|
||||
private i18nService: I18nService,
|
||||
private searchService: () => SearchService,
|
||||
private logService: LogService,
|
||||
private stateService: StateService
|
||||
private stateService: StateService,
|
||||
private encryptService: EncryptService
|
||||
) {}
|
||||
|
||||
async getDecryptedCipherCache(): Promise<CipherView[]> {
|
||||
@@ -329,35 +331,50 @@ export class CipherService implements CipherServiceAbstraction {
|
||||
|
||||
@sequentialize(() => "getAllDecrypted")
|
||||
async getAllDecrypted(): Promise<CipherView[]> {
|
||||
const userId = await this.stateService.getUserId();
|
||||
if ((await this.getDecryptedCipherCache()) != null) {
|
||||
if (
|
||||
this.searchService != null &&
|
||||
(this.searchService().indexedEntityId ?? userId) !== userId
|
||||
) {
|
||||
await this.searchService().indexCiphers(userId, await this.getDecryptedCipherCache());
|
||||
}
|
||||
await this.reindexCiphers();
|
||||
return await this.getDecryptedCipherCache();
|
||||
}
|
||||
|
||||
const decCiphers: CipherView[] = [];
|
||||
const hasKey = await this.cryptoService.hasKey();
|
||||
if (!hasKey) {
|
||||
throw new Error("No key.");
|
||||
}
|
||||
|
||||
const promises: Promise<number>[] = [];
|
||||
const ciphers = await this.getAll();
|
||||
ciphers.forEach(async (cipher) => {
|
||||
promises.push(cipher.decrypt().then((c) => decCiphers.push(c)));
|
||||
});
|
||||
const orgKeys = await this.cryptoService.getOrgKeys();
|
||||
const userKey = await this.cryptoService.getKeyForUserEncryption();
|
||||
|
||||
// Group ciphers by orgId or under 'null' for the user's ciphers
|
||||
const grouped = ciphers.reduce((agg, c) => {
|
||||
agg[c.organizationId] ??= [];
|
||||
agg[c.organizationId].push(c);
|
||||
return agg;
|
||||
}, {} as Record<string, Cipher[]>);
|
||||
|
||||
const decCiphers = (
|
||||
await Promise.all(
|
||||
Object.entries(grouped).map(([orgId, groupedCiphers]) =>
|
||||
this.encryptService.decryptItems(groupedCiphers, orgKeys.get(orgId) ?? userKey)
|
||||
)
|
||||
)
|
||||
)
|
||||
.flat()
|
||||
.sort(this.getLocaleSortingFunction());
|
||||
|
||||
await Promise.all(promises);
|
||||
decCiphers.sort(this.getLocaleSortingFunction());
|
||||
await this.setDecryptedCipherCache(decCiphers);
|
||||
return decCiphers;
|
||||
}
|
||||
|
||||
private async reindexCiphers() {
|
||||
const userId = await this.stateService.getUserId();
|
||||
const reindexRequired =
|
||||
this.searchService != null && (this.searchService().indexedEntityId ?? userId) !== userId;
|
||||
if (reindexRequired) {
|
||||
await this.searchService().indexCiphers(userId, await this.getDecryptedCipherCache());
|
||||
}
|
||||
}
|
||||
|
||||
async getAllDecryptedForGrouping(groupingId: string, folder = true): Promise<CipherView[]> {
|
||||
const ciphers = await this.getAllDecrypted();
|
||||
|
||||
@@ -488,21 +505,17 @@ export class CipherService implements CipherServiceAbstraction {
|
||||
}
|
||||
|
||||
async getAllFromApiForOrganization(organizationId: string): Promise<CipherView[]> {
|
||||
const ciphers = await this.apiService.getCiphersOrganization(organizationId);
|
||||
if (ciphers != null && ciphers.data != null && ciphers.data.length) {
|
||||
const decCiphers: CipherView[] = [];
|
||||
const promises: any[] = [];
|
||||
ciphers.data.forEach((r) => {
|
||||
const data = new CipherData(r);
|
||||
const cipher = new Cipher(data);
|
||||
promises.push(cipher.decrypt().then((c) => decCiphers.push(c)));
|
||||
});
|
||||
await Promise.all(promises);
|
||||
decCiphers.sort(this.getLocaleSortingFunction());
|
||||
return decCiphers;
|
||||
} else {
|
||||
const response = await this.apiService.getCiphersOrganization(organizationId);
|
||||
if (response?.data == null || response.data.length < 1) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const ciphers = response.data.map((cr) => new Cipher(new CipherData(cr)));
|
||||
const key = await this.cryptoService.getOrgKey(organizationId);
|
||||
const decCiphers = await this.encryptService.decryptItems(ciphers, key);
|
||||
|
||||
decCiphers.sort(this.getLocaleSortingFunction());
|
||||
return decCiphers;
|
||||
}
|
||||
|
||||
async getLastUsedForUrl(url: string, autofillOnPageLoad = false): Promise<CipherView> {
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
import { AbstractEncryptService } from "../abstractions/abstractEncrypt.service";
|
||||
import { CryptoService } from "../abstractions/crypto.service";
|
||||
import { EncryptService } from "../abstractions/encrypt.service";
|
||||
|
||||
export class ContainerService {
|
||||
constructor(
|
||||
private cryptoService: CryptoService,
|
||||
private encryptService: AbstractEncryptService
|
||||
) {}
|
||||
constructor(private cryptoService: CryptoService, private encryptService: EncryptService) {}
|
||||
|
||||
attachToGlobal(global: any) {
|
||||
if (!global.bitwardenContainerService) {
|
||||
@@ -26,7 +23,7 @@ export class ContainerService {
|
||||
/**
|
||||
* @throws Will throw if EncryptService was not instantiated and provided to the ContainerService constructor
|
||||
*/
|
||||
getEncryptService(): AbstractEncryptService {
|
||||
getEncryptService(): EncryptService {
|
||||
if (this.encryptService == null) {
|
||||
throw new Error("ContainerService.encryptService not initialized.");
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import * as bigInt from "big-integer";
|
||||
|
||||
import { AbstractEncryptService } from "../abstractions/abstractEncrypt.service";
|
||||
import { CryptoService as CryptoServiceAbstraction } from "../abstractions/crypto.service";
|
||||
import { CryptoFunctionService } from "../abstractions/cryptoFunction.service";
|
||||
import { EncryptService } from "../abstractions/encrypt.service";
|
||||
import { LogService } from "../abstractions/log.service";
|
||||
import { PlatformUtilsService } from "../abstractions/platformUtils.service";
|
||||
import { StateService } from "../abstractions/state.service";
|
||||
@@ -25,7 +25,7 @@ import { ProfileProviderResponse } from "../models/response/profile-provider.res
|
||||
export class CryptoService implements CryptoServiceAbstraction {
|
||||
constructor(
|
||||
private cryptoFunctionService: CryptoFunctionService,
|
||||
private encryptService: AbstractEncryptService,
|
||||
private encryptService: EncryptService,
|
||||
protected platformUtilService: PlatformUtilsService,
|
||||
protected logService: LogService,
|
||||
protected stateService: StateService
|
||||
|
||||
@@ -1,19 +1,21 @@
|
||||
import { AbstractEncryptService } from "../abstractions/abstractEncrypt.service";
|
||||
import { CryptoFunctionService } from "../abstractions/cryptoFunction.service";
|
||||
import { LogService } from "../abstractions/log.service";
|
||||
import { EncryptionType } from "../enums/encryptionType";
|
||||
import { IEncrypted } from "../interfaces/IEncrypted";
|
||||
import { Utils } from "../misc/utils";
|
||||
import { EncArrayBuffer } from "../models/domain/enc-array-buffer";
|
||||
import { EncString } from "../models/domain/enc-string";
|
||||
import { EncryptedObject } from "../models/domain/encrypted-object";
|
||||
import { SymmetricCryptoKey } from "../models/domain/symmetric-crypto-key";
|
||||
import { CryptoFunctionService } from "../../abstractions/cryptoFunction.service";
|
||||
import { EncryptService } from "../../abstractions/encrypt.service";
|
||||
import { LogService } from "../../abstractions/log.service";
|
||||
import { EncryptionType } from "../../enums/encryptionType";
|
||||
import { IEncrypted } from "../../interfaces/IEncrypted";
|
||||
import { Decryptable } from "../../interfaces/decryptable.interface";
|
||||
import { InitializerMetadata } from "../../interfaces/initializer-metadata.interface";
|
||||
import { Utils } from "../../misc/utils";
|
||||
import { EncArrayBuffer } from "../../models/domain/enc-array-buffer";
|
||||
import { EncString } from "../../models/domain/enc-string";
|
||||
import { EncryptedObject } from "../../models/domain/encrypted-object";
|
||||
import { SymmetricCryptoKey } from "../../models/domain/symmetric-crypto-key";
|
||||
|
||||
export class EncryptService implements AbstractEncryptService {
|
||||
export class EncryptServiceImplementation implements EncryptService {
|
||||
constructor(
|
||||
private cryptoFunctionService: CryptoFunctionService,
|
||||
private logService: LogService,
|
||||
private logMacFailures: boolean
|
||||
protected cryptoFunctionService: CryptoFunctionService,
|
||||
protected logService: LogService,
|
||||
protected logMacFailures: boolean
|
||||
) {}
|
||||
|
||||
async encrypt(plainValue: string | ArrayBuffer, key: SymmetricCryptoKey): Promise<EncString> {
|
||||
@@ -148,6 +150,17 @@ export class EncryptService implements AbstractEncryptService {
|
||||
return result ?? null;
|
||||
}
|
||||
|
||||
async decryptItems<T extends InitializerMetadata>(
|
||||
items: Decryptable<T>[],
|
||||
key: SymmetricCryptoKey
|
||||
): Promise<T[]> {
|
||||
if (items == null || items.length < 1) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return await Promise.all(items.map((item) => item.decrypt(key)));
|
||||
}
|
||||
|
||||
private async aesEncrypt(data: ArrayBuffer, key: SymmetricCryptoKey): Promise<EncryptedObject> {
|
||||
const obj = new EncryptedObject();
|
||||
obj.key = key;
|
||||
56
libs/common/src/services/cryptography/encrypt.worker.ts
Normal file
56
libs/common/src/services/cryptography/encrypt.worker.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
import { Jsonify } from "type-fest";
|
||||
|
||||
import { Decryptable } from "../../interfaces/decryptable.interface";
|
||||
import { SymmetricCryptoKey } from "../../models/domain/symmetric-crypto-key";
|
||||
import { ConsoleLogService } from "../../services/consoleLog.service";
|
||||
import { ContainerService } from "../../services/container.service";
|
||||
import { WebCryptoFunctionService } from "../../services/webCryptoFunction.service";
|
||||
|
||||
import { EncryptServiceImplementation } from "./encrypt.service.implementation";
|
||||
import { getClassInitializer } from "./get-class-initializer";
|
||||
|
||||
const workerApi: Worker = self as any;
|
||||
|
||||
let inited = false;
|
||||
let encryptService: EncryptServiceImplementation;
|
||||
|
||||
/**
|
||||
* Bootstrap the worker environment with services required for decryption
|
||||
*/
|
||||
export function init() {
|
||||
const cryptoFunctionService = new WebCryptoFunctionService(self);
|
||||
const logService = new ConsoleLogService(false);
|
||||
encryptService = new EncryptServiceImplementation(cryptoFunctionService, logService, true);
|
||||
|
||||
const bitwardenContainerService = new ContainerService(null, encryptService);
|
||||
bitwardenContainerService.attachToGlobal(self);
|
||||
|
||||
inited = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Listen for messages and decrypt their contents
|
||||
*/
|
||||
workerApi.addEventListener("message", async (event: { data: string }) => {
|
||||
if (!inited) {
|
||||
init();
|
||||
}
|
||||
|
||||
const request: {
|
||||
id: string;
|
||||
items: Jsonify<Decryptable<any>>[];
|
||||
key: Jsonify<SymmetricCryptoKey>;
|
||||
} = JSON.parse(event.data);
|
||||
|
||||
const key = SymmetricCryptoKey.fromJSON(request.key);
|
||||
const items = request.items.map((jsonItem) => {
|
||||
const initializer = getClassInitializer<Decryptable<any>>(jsonItem.initializerKey);
|
||||
return initializer(jsonItem);
|
||||
});
|
||||
const result = await encryptService.decryptItems(items, key);
|
||||
|
||||
workerApi.postMessage({
|
||||
id: request.id,
|
||||
items: JSON.stringify(result),
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,22 @@
|
||||
import { Jsonify } from "type-fest";
|
||||
|
||||
import { InitializerMetadata } from "../../interfaces/initializer-metadata.interface";
|
||||
import { Cipher } from "../../models/domain/cipher";
|
||||
import { CipherView } from "../../models/view/cipher.view";
|
||||
|
||||
import { InitializerKey } from "./initializer-key";
|
||||
|
||||
/**
|
||||
* Internal reference of classes so we can reconstruct objects properly.
|
||||
* Each entry should be keyed using the Decryptable.initializerKey property
|
||||
*/
|
||||
const classInitializers: Record<InitializerKey, (obj: any) => any> = {
|
||||
[InitializerKey.Cipher]: Cipher.fromJSON,
|
||||
[InitializerKey.CipherView]: CipherView.fromJSON,
|
||||
};
|
||||
|
||||
export function getClassInitializer<T extends InitializerMetadata>(
|
||||
className: InitializerKey
|
||||
): (obj: Jsonify<T>) => T {
|
||||
return classInitializers[className];
|
||||
}
|
||||
4
libs/common/src/services/cryptography/initializer-key.ts
Normal file
4
libs/common/src/services/cryptography/initializer-key.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export enum InitializerKey {
|
||||
Cipher = 0,
|
||||
CipherView = 1,
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
import { defaultIfEmpty, filter, firstValueFrom, fromEvent, map, Subject, takeUntil } from "rxjs";
|
||||
import { Jsonify } from "type-fest";
|
||||
|
||||
import { Decryptable } from "../../interfaces/decryptable.interface";
|
||||
import { InitializerMetadata } from "../../interfaces/initializer-metadata.interface";
|
||||
import { Utils } from "../../misc/utils";
|
||||
import { SymmetricCryptoKey } from "../../models/domain/symmetric-crypto-key";
|
||||
|
||||
import { EncryptServiceImplementation } from "./encrypt.service.implementation";
|
||||
import { getClassInitializer } from "./get-class-initializer";
|
||||
|
||||
// TTL (time to live) is not strictly required but avoids tying up memory resources if inactive
|
||||
const workerTTL = 3 * 60000; // 3 minutes
|
||||
|
||||
export class MultithreadEncryptServiceImplementation extends EncryptServiceImplementation {
|
||||
private worker: Worker;
|
||||
private timeout: any;
|
||||
|
||||
private clear$ = new Subject<void>();
|
||||
|
||||
/**
|
||||
* Sends items to a web worker to decrypt them.
|
||||
* This utilises multithreading to decrypt items faster without interrupting other operations (e.g. updating UI).
|
||||
*/
|
||||
async decryptItems<T extends InitializerMetadata>(
|
||||
items: Decryptable<T>[],
|
||||
key: SymmetricCryptoKey
|
||||
): Promise<T[]> {
|
||||
if (items == null || items.length < 1) {
|
||||
return [];
|
||||
}
|
||||
|
||||
this.logService.info("Starting decryption using multithreading");
|
||||
|
||||
this.worker ??= new Worker(
|
||||
new URL(
|
||||
/* webpackChunkName: 'encrypt-worker' */
|
||||
"@bitwarden/common/services/cryptography/encrypt.worker.ts",
|
||||
import.meta.url
|
||||
)
|
||||
);
|
||||
|
||||
this.restartTimeout();
|
||||
|
||||
const request = {
|
||||
id: Utils.newGuid(),
|
||||
items: items,
|
||||
key: key,
|
||||
};
|
||||
|
||||
this.worker.postMessage(JSON.stringify(request));
|
||||
|
||||
return await firstValueFrom(
|
||||
fromEvent(this.worker, "message").pipe(
|
||||
filter((response: MessageEvent) => response.data?.id === request.id),
|
||||
map((response) => JSON.parse(response.data.items)),
|
||||
map((items) =>
|
||||
items.map((jsonItem: Jsonify<T>) => {
|
||||
const initializer = getClassInitializer<T>(jsonItem.initializerKey);
|
||||
return initializer(jsonItem);
|
||||
})
|
||||
),
|
||||
takeUntil(this.clear$),
|
||||
defaultIfEmpty([])
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private clear() {
|
||||
this.clear$.next();
|
||||
this.worker?.terminate();
|
||||
this.worker = null;
|
||||
this.clearTimeout();
|
||||
}
|
||||
|
||||
private restartTimeout() {
|
||||
this.clearTimeout();
|
||||
this.timeout = setTimeout(() => this.clear(), workerTTL);
|
||||
}
|
||||
|
||||
private clearTimeout() {
|
||||
if (this.timeout != null) {
|
||||
clearTimeout(this.timeout);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -248,12 +248,8 @@ export class ExportService implements ExportServiceAbstraction {
|
||||
this.apiService.getOrganizationExport(organizationId).then((exportData) => {
|
||||
const exportPromises: any = [];
|
||||
if (exportData != null) {
|
||||
if (
|
||||
exportData.collections != null &&
|
||||
exportData.collections.data != null &&
|
||||
exportData.collections.data.length > 0
|
||||
) {
|
||||
exportData.collections.data.forEach((c) => {
|
||||
if (exportData.collections != null && exportData.collections.length > 0) {
|
||||
exportData.collections.forEach((c) => {
|
||||
const collection = new Collection(new CollectionData(c as CollectionDetailsResponse));
|
||||
exportPromises.push(
|
||||
collection.decrypt().then((decCol) => {
|
||||
@@ -262,12 +258,8 @@ export class ExportService implements ExportServiceAbstraction {
|
||||
);
|
||||
});
|
||||
}
|
||||
if (
|
||||
exportData.ciphers != null &&
|
||||
exportData.ciphers.data != null &&
|
||||
exportData.ciphers.data.length > 0
|
||||
) {
|
||||
exportData.ciphers.data
|
||||
if (exportData.ciphers != null && exportData.ciphers.length > 0) {
|
||||
exportData.ciphers
|
||||
.filter((c) => c.deletedDate === null)
|
||||
.forEach((c) => {
|
||||
const cipher = new Cipher(new CipherData(c));
|
||||
|
||||
@@ -12,64 +12,64 @@ import {
|
||||
ImportType,
|
||||
regularImportOptions,
|
||||
} from "../enums/importOptions";
|
||||
import { AscendoCsvImporter } from "../importers/ascendoCsvImporter";
|
||||
import { AvastCsvImporter } from "../importers/avastCsvImporter";
|
||||
import { AvastJsonImporter } from "../importers/avastJsonImporter";
|
||||
import { AviraCsvImporter } from "../importers/aviraCsvImporter";
|
||||
import { BitwardenCsvImporter } from "../importers/bitwardenCsvImporter";
|
||||
import { BitwardenJsonImporter } from "../importers/bitwardenJsonImporter";
|
||||
import { BitwardenPasswordProtectedImporter } from "../importers/bitwardenPasswordProtectedImporter";
|
||||
import { BlackBerryCsvImporter } from "../importers/blackBerryCsvImporter";
|
||||
import { BlurCsvImporter } from "../importers/blurCsvImporter";
|
||||
import { ButtercupCsvImporter } from "../importers/buttercupCsvImporter";
|
||||
import { AscendoCsvImporter } from "../importers/ascendo-csv-importer";
|
||||
import { AvastCsvImporter } from "../importers/avast-csv-importer";
|
||||
import { AvastJsonImporter } from "../importers/avast-json-importer";
|
||||
import { AviraCsvImporter } from "../importers/avira-csv-importer";
|
||||
import { BitwardenCsvImporter } from "../importers/bitwarden-csv-importer";
|
||||
import { BitwardenJsonImporter } from "../importers/bitwarden-json-importer";
|
||||
import { BitwardenPasswordProtectedImporter } from "../importers/bitwarden-password-protected-importer";
|
||||
import { BlackBerryCsvImporter } from "../importers/blackberry-csv-importer";
|
||||
import { BlurCsvImporter } from "../importers/blur-csv-importer";
|
||||
import { ButtercupCsvImporter } from "../importers/buttercup-csv-importer";
|
||||
import { ChromeCsvImporter } from "../importers/chrome-csv-importer";
|
||||
import { ClipperzHtmlImporter } from "../importers/clipperzHtmlImporter";
|
||||
import { CodebookCsvImporter } from "../importers/codebookCsvImporter";
|
||||
import { DashlaneCsvImporter } from "../importers/dashlaneImporters/dashlaneCsvImporter";
|
||||
import { DashlaneJsonImporter } from "../importers/dashlaneImporters/dashlaneJsonImporter";
|
||||
import { EncryptrCsvImporter } from "../importers/encryptrCsvImporter";
|
||||
import { EnpassCsvImporter } from "../importers/enpassCsvImporter";
|
||||
import { EnpassJsonImporter } from "../importers/enpassJsonImporter";
|
||||
import { FirefoxCsvImporter } from "../importers/firefoxCsvImporter";
|
||||
import { FSecureFskImporter } from "../importers/fsecureFskImporter";
|
||||
import { GnomeJsonImporter } from "../importers/gnomeJsonImporter";
|
||||
import { ImportError } from "../importers/importError";
|
||||
import { ClipperzHtmlImporter } from "../importers/clipperz-html-importer";
|
||||
import { CodebookCsvImporter } from "../importers/codebook-csv-importer";
|
||||
import { DashlaneCsvImporter } from "../importers/dashlane/dashlane-csv-importer";
|
||||
import { DashlaneJsonImporter } from "../importers/dashlane/dashlane-json-importer";
|
||||
import { EncryptrCsvImporter } from "../importers/encryptr-csv-importer";
|
||||
import { EnpassCsvImporter } from "../importers/enpass-csv-importer";
|
||||
import { EnpassJsonImporter } from "../importers/enpass-json-importer";
|
||||
import { FirefoxCsvImporter } from "../importers/firefox-csv-importer";
|
||||
import { FSecureFskImporter } from "../importers/fsecure-fsk-importer";
|
||||
import { GnomeJsonImporter } from "../importers/gnome-json-importer";
|
||||
import { ImportError } from "../importers/import-error";
|
||||
import { Importer } from "../importers/importer";
|
||||
import { KasperskyTxtImporter } from "../importers/kasperskyTxtImporter";
|
||||
import { KeePass2XmlImporter } from "../importers/keepass2XmlImporter";
|
||||
import { KeePassXCsvImporter } from "../importers/keepassxCsvImporter";
|
||||
import { KeeperCsvImporter } from "../importers/keeperImporters/keeperCsvImporter";
|
||||
import { LastPassCsvImporter } from "../importers/lastpassCsvImporter";
|
||||
import { LogMeOnceCsvImporter } from "../importers/logMeOnceCsvImporter";
|
||||
import { MeldiumCsvImporter } from "../importers/meldiumCsvImporter";
|
||||
import { MSecureCsvImporter } from "../importers/msecureCsvImporter";
|
||||
import { MykiCsvImporter } from "../importers/mykiCsvImporter";
|
||||
import { NordPassCsvImporter } from "../importers/nordpassCsvImporter";
|
||||
import { OnePassword1PifImporter } from "../importers/onepasswordImporters/onepassword1PifImporter";
|
||||
import { OnePassword1PuxImporter } from "../importers/onepasswordImporters/onepassword1PuxImporter";
|
||||
import { OnePasswordMacCsvImporter } from "../importers/onepasswordImporters/onepasswordMacCsvImporter";
|
||||
import { OnePasswordWinCsvImporter } from "../importers/onepasswordImporters/onepasswordWinCsvImporter";
|
||||
import { PadlockCsvImporter } from "../importers/padlockCsvImporter";
|
||||
import { PassKeepCsvImporter } from "../importers/passkeepCsvImporter";
|
||||
import { PassmanJsonImporter } from "../importers/passmanJsonImporter";
|
||||
import { PasspackCsvImporter } from "../importers/passpackCsvImporter";
|
||||
import { PasswordAgentCsvImporter } from "../importers/passwordAgentCsvImporter";
|
||||
import { PasswordBossJsonImporter } from "../importers/passwordBossJsonImporter";
|
||||
import { PasswordDragonXmlImporter } from "../importers/passwordDragonXmlImporter";
|
||||
import { PasswordSafeXmlImporter } from "../importers/passwordSafeXmlImporter";
|
||||
import { PasswordWalletTxtImporter } from "../importers/passwordWalletTxtImporter";
|
||||
import { RememBearCsvImporter } from "../importers/rememBearCsvImporter";
|
||||
import { RoboFormCsvImporter } from "../importers/roboformCsvImporter";
|
||||
import { SafariCsvImporter } from "../importers/safariCsvImporter";
|
||||
import { SafeInCloudXmlImporter } from "../importers/safeInCloudXmlImporter";
|
||||
import { SaferPassCsvImporter } from "../importers/saferpassCsvImport";
|
||||
import { SecureSafeCsvImporter } from "../importers/secureSafeCsvImporter";
|
||||
import { SplashIdCsvImporter } from "../importers/splashIdCsvImporter";
|
||||
import { StickyPasswordXmlImporter } from "../importers/stickyPasswordXmlImporter";
|
||||
import { TrueKeyCsvImporter } from "../importers/truekeyCsvImporter";
|
||||
import { UpmCsvImporter } from "../importers/upmCsvImporter";
|
||||
import { YotiCsvImporter } from "../importers/yotiCsvImporter";
|
||||
import { ZohoVaultCsvImporter } from "../importers/zohoVaultCsvImporter";
|
||||
import { KasperskyTxtImporter } from "../importers/kaspersky-txt-importer";
|
||||
import { KeePass2XmlImporter } from "../importers/keepass2-xml-importer";
|
||||
import { KeePassXCsvImporter } from "../importers/keepassx-csv-importer";
|
||||
import { KeeperCsvImporter } from "../importers/keeper/keeper-csv-importer";
|
||||
import { LastPassCsvImporter } from "../importers/lastpass-csv-importer";
|
||||
import { LogMeOnceCsvImporter } from "../importers/logmeonce-csv-importer";
|
||||
import { MeldiumCsvImporter } from "../importers/meldium-csv-importer";
|
||||
import { MSecureCsvImporter } from "../importers/msecure-csv-importer";
|
||||
import { MykiCsvImporter } from "../importers/myki-csv-importer";
|
||||
import { NordPassCsvImporter } from "../importers/nordpass-csv-importer";
|
||||
import { OnePassword1PifImporter } from "../importers/onepassword/onepassword-1pif-importer";
|
||||
import { OnePassword1PuxImporter } from "../importers/onepassword/onepassword-1pux-importer";
|
||||
import { OnePasswordMacCsvImporter } from "../importers/onepassword/onepassword-mac-csv-importer";
|
||||
import { OnePasswordWinCsvImporter } from "../importers/onepassword/onepassword-win-csv-importer";
|
||||
import { PadlockCsvImporter } from "../importers/padlock-csv-importer";
|
||||
import { PassKeepCsvImporter } from "../importers/passkeep-csv-importer";
|
||||
import { PassmanJsonImporter } from "../importers/passman-json-importer";
|
||||
import { PasspackCsvImporter } from "../importers/passpack-csv-importer";
|
||||
import { PasswordAgentCsvImporter } from "../importers/passwordagent-csv-importer";
|
||||
import { PasswordBossJsonImporter } from "../importers/passwordboss-json-importer";
|
||||
import { PasswordDragonXmlImporter } from "../importers/passworddragon-xml-importer";
|
||||
import { PasswordSafeXmlImporter } from "../importers/passwordsafe-xml-importer";
|
||||
import { PasswordWalletTxtImporter } from "../importers/passwordwallet-txt-importer";
|
||||
import { RememBearCsvImporter } from "../importers/remembear-csv-importer";
|
||||
import { RoboFormCsvImporter } from "../importers/roboform-csv-importer";
|
||||
import { SafariCsvImporter } from "../importers/safari-csv-importer";
|
||||
import { SafeInCloudXmlImporter } from "../importers/safeincloud-xml-importer";
|
||||
import { SaferPassCsvImporter } from "../importers/saferpass-csv-importer";
|
||||
import { SecureSafeCsvImporter } from "../importers/securesafe-csv-importer";
|
||||
import { SplashIdCsvImporter } from "../importers/splashid-csv-importer";
|
||||
import { StickyPasswordXmlImporter } from "../importers/stickypassword-xml-importer";
|
||||
import { TrueKeyCsvImporter } from "../importers/truekey-csv-importer";
|
||||
import { UpmCsvImporter } from "../importers/upm-csv-importer";
|
||||
import { YotiCsvImporter } from "../importers/yoti-csv-importer";
|
||||
import { ZohoVaultCsvImporter } from "../importers/zohovault-csv-importer";
|
||||
import { Utils } from "../misc/utils";
|
||||
import { ImportResult } from "../models/domain/import-result";
|
||||
import { CipherRequest } from "../models/request/cipher.request";
|
||||
|
||||
27
libs/common/src/services/login.service.ts
Normal file
27
libs/common/src/services/login.service.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { LoginService as LoginServiceAbstraction } from "../abstractions/login.service";
|
||||
|
||||
export class LoginService implements LoginServiceAbstraction {
|
||||
private _email: string;
|
||||
private _rememberEmail: boolean;
|
||||
|
||||
getEmail() {
|
||||
return this._email;
|
||||
}
|
||||
|
||||
getRememberEmail() {
|
||||
return this._rememberEmail;
|
||||
}
|
||||
|
||||
setEmail(value: string) {
|
||||
this._email = value;
|
||||
}
|
||||
|
||||
setRememberEmail(value: boolean) {
|
||||
this._rememberEmail = value;
|
||||
}
|
||||
|
||||
clearValues() {
|
||||
this._email = null;
|
||||
this._rememberEmail = null;
|
||||
}
|
||||
}
|
||||
@@ -101,6 +101,20 @@ export class OrganizationService implements OrganizationServiceAbstraction {
|
||||
return organizations.find((organization) => organization.id === id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated For the CLI only
|
||||
* @param id id of the organization
|
||||
*/
|
||||
async getFromState(id: string): Promise<Organization> {
|
||||
const organizationsMap = await this.stateService.getOrganizations();
|
||||
const organization = organizationsMap[id];
|
||||
if (organization == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new Organization(organization);
|
||||
}
|
||||
|
||||
getByIdentifier(identifier: string): Organization {
|
||||
const organizations = this._organizations.getValue();
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { firstValueFrom, map } from "rxjs";
|
||||
import * as zxcvbn from "zxcvbn";
|
||||
|
||||
import { CryptoService } from "../abstractions/crypto.service";
|
||||
@@ -11,7 +10,6 @@ import { EncString } from "../models/domain/enc-string";
|
||||
import { GeneratedPasswordHistory } from "../models/domain/generated-password-history";
|
||||
import { PasswordGeneratorOptions } from "../models/domain/password-generator-options";
|
||||
import { PasswordGeneratorPolicyOptions } from "../models/domain/password-generator-policy-options";
|
||||
import { Policy } from "../models/domain/policy";
|
||||
|
||||
const DefaultOptions: PasswordGeneratorOptions = {
|
||||
length: 14,
|
||||
@@ -257,14 +255,7 @@ export class PasswordGenerationService implements PasswordGenerationServiceAbstr
|
||||
}
|
||||
|
||||
async getPasswordGeneratorPolicyOptions(): Promise<PasswordGeneratorPolicyOptions> {
|
||||
const policies: Policy[] =
|
||||
this.policyService == null
|
||||
? null
|
||||
: await firstValueFrom(
|
||||
this.policyService.policies$.pipe(
|
||||
map((p) => p.filter((policy) => policy.type === PolicyType.PasswordGenerator))
|
||||
)
|
||||
);
|
||||
const policies = await this.policyService?.getAll(PolicyType.PasswordGenerator);
|
||||
let enforcedOptions: PasswordGeneratorPolicyOptions = null;
|
||||
|
||||
if (policies == null || policies.length === 0) {
|
||||
|
||||
@@ -124,10 +124,7 @@ export class PolicyService implements InternalPolicyServiceAbstraction {
|
||||
);
|
||||
}
|
||||
|
||||
policyAppliesToActiveUser$(
|
||||
policyType: PolicyType,
|
||||
policyFilter: (policy: Policy) => boolean = (p) => true
|
||||
) {
|
||||
policyAppliesToActiveUser$(policyType: PolicyType, policyFilter?: (policy: Policy) => boolean) {
|
||||
return this.policies$.pipe(
|
||||
concatMap(async (policies) => {
|
||||
const userId = await this.stateService.getUserId();
|
||||
@@ -225,11 +222,13 @@ export class PolicyService implements InternalPolicyServiceAbstraction {
|
||||
policies[policy.id] = policy;
|
||||
|
||||
await this.updateObservables(policies);
|
||||
await this.stateService.setDecryptedPolicies(null);
|
||||
await this.stateService.setEncryptedPolicies(policies);
|
||||
}
|
||||
|
||||
async replace(policies: { [id: string]: PolicyData }): Promise<void> {
|
||||
await this.updateObservables(policies);
|
||||
await this.stateService.setDecryptedPolicies(null);
|
||||
await this.stateService.setEncryptedPolicies(policies);
|
||||
}
|
||||
|
||||
@@ -237,6 +236,7 @@ export class PolicyService implements InternalPolicyServiceAbstraction {
|
||||
if (userId == null || userId == (await this.stateService.getUserId())) {
|
||||
this._policies.next([]);
|
||||
}
|
||||
await this.stateService.setDecryptedPolicies(null, { userId: userId });
|
||||
await this.stateService.setEncryptedPolicies(null, { userId: userId });
|
||||
}
|
||||
|
||||
@@ -257,12 +257,12 @@ export class PolicyService implements InternalPolicyServiceAbstraction {
|
||||
private async checkPoliciesThatApplyToUser(
|
||||
policies: Policy[],
|
||||
policyType: PolicyType,
|
||||
policyFilter: (policy: Policy) => boolean = (p) => true,
|
||||
policyFilter?: (policy: Policy) => boolean,
|
||||
userId?: string
|
||||
) {
|
||||
const organizations = await this.organizationService.getAll(userId);
|
||||
const filteredPolicies = policies.filter(
|
||||
(p) => p.type === policyType && p.enabled && policyFilter(p)
|
||||
(p) => p.type === policyType && p.enabled && (policyFilter == null || policyFilter(p))
|
||||
);
|
||||
const policySet = new Set(filteredPolicies.map((p) => p.organizationId));
|
||||
|
||||
|
||||
@@ -65,8 +65,10 @@ export class StateService<
|
||||
TAccount extends Account = Account
|
||||
> implements StateServiceAbstraction<TAccount>
|
||||
{
|
||||
accounts = new BehaviorSubject<{ [userId: string]: TAccount }>({});
|
||||
private activeAccountSubject = new BehaviorSubject<string>(null);
|
||||
private accountsSubject = new BehaviorSubject<{ [userId: string]: TAccount }>({});
|
||||
accounts$ = this.accountsSubject.asObservable();
|
||||
|
||||
private activeAccountSubject = new BehaviorSubject<string | null>(null);
|
||||
activeAccount$ = this.activeAccountSubject.asObservable();
|
||||
|
||||
private activeAccountUnlockedSubject = new BehaviorSubject<boolean>(false);
|
||||
@@ -2530,11 +2532,11 @@ export class StateService<
|
||||
await this.pruneInMemoryAccounts();
|
||||
await this.state().then((state) => {
|
||||
if (state.accounts == null || Object.keys(state.accounts).length < 1) {
|
||||
this.accounts.next(null);
|
||||
this.accountsSubject.next({});
|
||||
return;
|
||||
}
|
||||
|
||||
this.accounts.next(state.accounts);
|
||||
this.accountsSubject.next(state.accounts);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { firstValueFrom } from "rxjs";
|
||||
|
||||
import { AuthService } from "../abstractions/auth.service";
|
||||
import { MessagingService } from "../abstractions/messaging.service";
|
||||
import { PlatformUtilsService } from "../abstractions/platformUtils.service";
|
||||
@@ -19,7 +21,7 @@ export class SystemService implements SystemServiceAbstraction {
|
||||
) {}
|
||||
|
||||
async startProcessReload(authService: AuthService): Promise<void> {
|
||||
const accounts = this.stateService.accounts.getValue();
|
||||
const accounts = await firstValueFrom(this.stateService.accounts$);
|
||||
if (accounts != null) {
|
||||
const keys = Object.keys(accounts);
|
||||
if (keys.length > 0) {
|
||||
@@ -56,7 +58,7 @@ export class SystemService implements SystemServiceAbstraction {
|
||||
}
|
||||
|
||||
private async executeProcessReload() {
|
||||
const accounts = this.stateService.accounts.getValue();
|
||||
const accounts = await firstValueFrom(this.stateService.accounts$);
|
||||
const doRefresh =
|
||||
accounts == null ||
|
||||
Object.keys(accounts).length == 0 ||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { firstValueFrom } from "rxjs";
|
||||
|
||||
import { AuthService } from "../../abstractions/auth.service";
|
||||
import { CipherService } from "../../abstractions/cipher.service";
|
||||
import { CollectionService } from "../../abstractions/collection.service";
|
||||
@@ -52,7 +54,8 @@ export class VaultTimeoutService implements VaultTimeoutServiceAbstraction {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const userId in this.stateService.accounts.getValue()) {
|
||||
const accounts = await firstValueFrom(this.stateService.accounts$);
|
||||
for (const userId in accounts) {
|
||||
if (userId != null && (await this.shouldLock(userId))) {
|
||||
await this.executeTimeoutAction(userId);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user