mirror of
https://github.com/bitwarden/browser
synced 2025-12-29 06:33:40 +00:00
* Remove DDG forwarder from SH (#3888) * [EC-272] Web workers using EncryptionService (#3532) * Add item decryption to encryptService * Create multithreadEncryptService subclass to handle web workers * Create encryption web worker * Refactor cipherService to use new interface * Update dependencies * Don't refresh org vault on filter change (#3879) * Autosync the updated translations (#3914) Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com> * Autosync the updated translations (#3915) Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com> * Autosync the updated translations (#3916) Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com> * Revert "[PS-1465] Fix #2806 - The "Import Data" page's file selector button cannot be translated (#3502)" (#3900) This reverts commit768de03269. * Autosync the updated translations (#3919) Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com> * [SM-260] Hide email verification prompt if already verified (#3922) Co-authored-by: Sammy Chang <sammychang2185@gmail.com> * Two-Step Login (#3852) * [SG-163] Two step login flow web (#3648) * two step login flow * moved code from old branch and reafctored * fixed review comments * [SG-164] Two Step Login Flow - Browser (#3793) * Add new messages * Remove SSO button from home component * Change create account button to text * Add top padding to create account link * Add email input to HomeComponent * Add continue button to email input * Add form to home component * Retreive email from state service * Redirect to login after submit * Add error message for invalid email * Remove email input from login component * Remove loggingInTo from under MP input * Style the MP hint link * Add self hosted domain to email form * Made the mp hint link bold * Add the new login button * Style app-private-mode-warning in its component * Bitwarden -> Login text change * Remove the old login button * Cancel -> Close text change * Add avatar to login header * Login -> LoginWithMasterPassword text change * Add SSO button to login screen * Add not you button * Allow all clients to use the email query param on the login component * Introduct HomeGuard * Clear remembered email when clicking Not You * Make remember email opt-in * Use formGroup.patchValue instead of directly patching individual controls * [SG-165] Desktop login flow changes (#3814) * two step login flow * moved code from old branch and reafctored * fixed review comments * Make toggleValidateEmail in base class public * Add desktop login messages * Desktop login flow changes * Fix known device api error * Only submit if email has been validated * Clear remembered email when switching accounts * Fix merge issue * Add 'login with another device' button * Remove 'log in with another device' button for now * Pin login pag content to top instead of center justified * Leave email if 'Not you?' is clicked * Continue when enter is hit on email input Co-authored-by: gbubemismith <gsmithwalter@gmail.com> * [SG-750] and [SG-751] Web two step login bug fixes (#3843) * Continue when enter is hit on email input * Mark email input as touched on 'continue' so field is validated * disable login with device on self-hosted (#3895) * [SG-753] Keep email after hint component is launched in browser (#3883) * Keep email after hint component is launched in browser * Use query params instead of state for consistency * Send email and rememberEmail to home component on navigation (#3897) * removed avatar and close button from the password screen (#3901) * [SG-781] Remove extra login page and remove rememberEmail code (#3902) * Remove browser home guard * Always remember email for browser * Remove login landing page button * [SG-782] Add login service to streamline login form data persistence (#3911) * Add login service and abstraction * Inject login service into apps * Inject and use new service in login component * Use service in hint component to prefill email * Add method in LoginService to clear service values * Add LoginService to two-factor component to clear values * make login.service variables private Co-authored-by: Gbubemi Smith <gsmith@bitwarden.com> Co-authored-by: Addison Beck <addisonbeck1@gmail.com> Co-authored-by: Robyn MacCallum <robyntmaccallum@gmail.com> Co-authored-by: gbubemismith <gsmithwalter@gmail.com> * 400s only log out on invalid grant error (#3924) * Fix rust tests apt-get install (#3933) * Added focus to the email and master password fields (#3934) * Ps 1754 community pr reviewed (#3929) * community PR reviewed, Update search cancel button to be visible in all themes * community PR reviewed, Update search cancel button to be visible in all themes 2 * Update search cancel button to be visible in all themes (#3876) * Adding the 'libs/**' directory back to the Desktop build pipeline PR trigger list (#3938) * Re-\added the focusInput method to allow desktop build run (#3937) * [EC-522] Improve handling of rxjs subjects (#3772) * [EC-522] feat: no public rxjs subjects * [EC-522] feat: improve null handling * [EC-552] fix: init subject with empty set instead of null * [EC-552] fix: don't push null into account subject * [EC-522] feat: remove null filter * [EC-641] Browser Ext UI Update (#3842) * more css changes * add icon button hover * Update apps/browser/src/popup/scss/box.scss Co-authored-by: Oscar Hinton <Hinton@users.noreply.github.com> * Update apps/desktop/src/scss/box.scss Co-authored-by: Oscar Hinton <Hinton@users.noreply.github.com> * feedback updates * restore desktop pseudo rule * update to include some variable fixes and deletions * updates per oscar * feedback updates more universal variable, adjusted box padding (per Kyle), and aligned footer text * changes per product design added border for selects, border around generator, and hover for solarizeddark * add more helper text space below for visual separation * group new variable * login page button fix Dflinn found an odd margin on the login page * Revert "Merge branch 'master' into browser-ext-ui-update-test" This reverts commitb8007102f9, reversing changes made to246768cb12. * fix button height * revert file changes * test adjustments Co-authored-by: Oscar Hinton <Hinton@users.noreply.github.com> Co-authored-by: Kyle Spearrin <kyle.spearrin@gmail.com> * [SG-792] Added focus to master password field on browser and desktop (#3939) * Added focus to master password field on browser client * Added focus to master password field on desktop client * Tell eslint & prettier to ignore storybook-static (#3946) * [SG-792] Fixed focus on master password when enter key is pressed (#3948) * Added focus to master password field on browser client * Added focus to master password field on desktop client * fixed focus on master password when enter is pressed * [EC-7] Org Admin Vault Refresh Client V1 (#3925) * [EC-8] Restructure Tabs (#3109) * Cherry pick pending PR for tabs component [CL-17] Tabs - Routing * Update organization tabs from 4 to 6 * Create initial 'Members' tab * Create initial 'Groups' tab * Add initial "Reporting" tab * Use correct report label/layout by product type * Create initial 'Billing' tab * Breakup billing payment and billing history pages * Cleanup org routing and nav permission service * More org tab permission cleanup * Refactor organization billing to use a module * Refactor organization reporting to use module * Cherry pick finished/merged tabs component [CL-17] Tabs - Router (#2952) * This partially reverts commit24bb775to fix tracking of people.component.html rename. * Fix people component file rename * Recover lost member page changes * Undo members component rename as it was causing difficult merge conflicts * Fix member and group page container * Remove unnecessary organization lookup * [EC-8] Some PR suggestions * [EC-8] Reuse user billing history for orgs * [EC-8] Renamed user billing history component * [EC-8] Repurpose payment method component Update end user payment method component to be usable for organizations. * [EC-8] Fix missing verify bank condition * [EC-8] Remove org payment method component * [EC-8] Use CL in payment method component * [EC-8] Extend maxWidth Tailwind theme config * [EC-8] Add lazy loading to org reports * [EC-8] Add lazy loading to org billing * [EC-8] Prettier * [EC-8] Cleanup org reporting component redundancy * [EC-8] Use different class for negative margin * [EC-8] Make billing history component "dumb" * Revert "[EC-8] Cleanup org reporting component redundancy" This reverts commiteca337e89b. * [EC-8] Create and export shared reports module * [EC-8] Use shared reports module in orgs * [EC-8] Use takeUntil pattern * [EC-8] Move org reporting module out of old modules folder * [EC-8] Move org billing module out of old modules folder * [EC-8] Fix some remaining merge conflicts * [EC-8] Move maxWidth into 'extend' key for Tailwind config * [EC-8] Remove unused module * [EC-8] Rename org report list component * Prettier Co-authored-by: Vincent Salucci <vincesalucci21@gmail.com> * [EC-451] Org Admin Refresh Permissions Refactor (#3320) * [EC-451] Update new org permissions for new tabs * [EC-451] Remove redudant route guards * [EC-451] Remove canAccessManageTab() * [EC-451] Use canAccess* callbacks in org routing module * Fix org api service refactor and linting after pulling in master * Fix broken org people and group pages after merge * [EC-18] Reporting side nav direction (#3420) * [EC-18] Re-order side nav for org reports according to Figma * [EC-18] Fix rxjs linter errors and redundant org flag * [EC-526] Default to Event Logs page for Reporting Tab (#3470) * [EC-526] Default to the Events Logs page when navigating to the Reporting tab * [EC-526] Undo default routing redirect when the child path is missing. Avoids defaulting to "/events" in case a user/org doesn't have access to event logs. * [EC-19] Update Organization Settings Page (#3251) * [EC-19] Refactor existing organization settings components to its own module * [EC-19] Move SSO page to settings tab * [EC-19] Move Policies page to Settings tab Refactor Policy components into its own module * [EC-19] Move ImageSubscriptionHiddenComponent * [EC-19] Lazy load org settings module * [EC-19] Add SSO Id to SSO config view * [EC-19] Remove SSO identfier from org info page * [EC-19] Update org settings/policies to follow ADR-0011 * [EC-19] Update two-step login setup description * [EC-19] Revert nested policy components folder * [EC-19] Revert nested org setting components folder * [EC-19] Remove left over image component * [EC-19] Prettier * [EC-19] Fix missing i18n * [EC-19] Update SSO form to use CL * [EC-19] Remove unused SSO input components * [EC-19] Fix bad SSO locale identifier * [EC-19] Fix import order linting * [EC-19] Add explicit whitespace check for launch click directive * [EC-19] Add restricted import paths to eslint config * [EC-19] Tag deprecated field with Jira issue to cleanup in future release * [EC-19] Remove out of date comment * [EC-19] Move policy components to policies module * [EC-19] Remove dityRequired validator * [EC-19] Use explicit type for SSO config form * [EC-19] Fix rxjs linter errors * [EC-19] Fix RxJS eslint comments in org settings component * [EC-19] Use explicit ControlsOf<T> helper for nested SSO form groups. * [EC-19] Attribute source of ControlsOf<T> helper * [EC-19] Fix missing settings side nav links * [EC-19] Fix member/user language for policy modals * [EC-551] Update Event Logs Client Column (#3572) * [EC-551] Fix RxJS warnings * [EC-551] Update page to use CL components and Tailwind classes * [EC-551] Update Client column to use text instead of icon. Update language and i18n. * [EC-14] Refactor vault filter (#3440) * [EC-14] initial refactoring of vault filter * [EC-14] return observable trees for all filters with head node * [EC-14] Remove bindings on callbacks * [EC-14] fix formatting on disabled orgs * [EC-14] hide MyVault if personal org policy * [EC-14] add check for single org policy * [EC-14] add policies to org and change node constructor * [EC-14] don't show options if personal vault policy * [EC-14] default to all vaults * [EC-14] add default selection to filters * [EC-14] finish filter model callbacks * [EC-14] finish filter functionality and begin cleaning up * [EC-14] clean up old components and start on org vault * [EC-14] loop through filters for presentation * [EC-14] refactor VaultFilterService and put filter presentation data back into Vault Filter component. Remove VaultService * [EC-14] begin refactoring org vault * [EC-14] Refactor Vault Filter Service to use observables * [EC-14] finish org vault filter * [EC-14] fix vault model tests * [EC-14] fix org service calls * [EC-14] pull refactor out of shared code * [EC-14] include head node for collections even if collections aren't loaded yet * [EC-14] fix url params for vaults * [EC-14] remove comments * [EC-14] Remove unnecesary getter for org on vault filter * [EC-14] fix linter * [EC-14] fix prettier * [EC-14] add deprecated methods to collection service for desktop and browser * [EC-14] simplify cipher type node check * [EC-14] add getters to vault filter model * [EC-14] refactor how we build the filter list into methods * [EC-14] add getters to build filter method * [EC-14] remove param ids if false * [EC-14] fix collapsing nodes * [EC-14] add specific type to search placeholder * [EC-14] remove extra constructor and comment from org vault filter * [EC-14] extract subscription callback to methods * [EC-14] Remove unecessary await * [EC-14] Remove ternary operators while building org filter * [EC-14] remove unnecessary deps array in vault filter service declaration * [EC-14] consolidate new models into one file * [EC-14] initialize nested observable inside of service Signed-off-by: Jacob Fink <jfink@bitwarden.com> * [EC-14] change how we load orgs into the vault filter and select the default filter * [EC-14] remove get from getters name * [EC-14] remove eslint-disable comment * [EC-14] move vault filter service abstraction to angular folder and separate * [EC-14] rename filter types and delete VaultFilterLabel * [EC-14] remove changes to workspace file * [EC-14] remove deprecated service from jslib module * [EC-14] remove any remaining files from common code * [EC-14] consolidate vault filter components into components folder * [EC-14] simplify method call * [EC-14] refactor the vault filter service - orgs now have observable property - BehaviorSubjects have been migrated to ReplaySubjects if they don't need starting value - added unit tests - fix small error when selecting org badge of personal vault - renamed some properties * [EC-14] replace mergeMap with switchMap in vault filter service * [EC-14] early return to prevent nesting * [EC-14] clean up filterCollections method * [EC-14] use isDeleted helper in html * [EC-14] add jsdoc comments to ServiceUtils * [EC-14] fix linter * [EC-14] use array.slice instead of setting length * Update apps/web/src/app/vault/vault-filter/services/vault-filter.service.ts Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com> * [EC-14] add missing high level jsdoc description * [EC-14] fix storybook absolute imports * [EC-14] delete vault-shared.module * [EC-14] change search placeholder text to getter and add missing strings * [EC-14] remove two way binding from search text in vault filter * [EC-14] removed all binding from search text and just use input event * [EC-14] remove async from apply vault filter * [EC-14] remove circular observable calls in vault filter service Co-authored-by: Thomas Rittson <eliykat@users.noreply.github.com> * [EC-14] move collapsed nodes to vault filter section * [EC-14] deconstruct filter section inside component * [EC-14] fix merge conflicts and introduce refactored organization service to vault filter service * [EC-14] remove mutation from filter builders * [EC-14] fix styling on buildFolderTree * [EC-14] remove leftover folder-filters reference and use ternary for collapse icon * [EC-14] remove unecessary checks * [EC-14] stop rebuilding filters when the organization changes * [EC-14] Move subscription out of setter in vault filter section * [EC-14] remove extra policy service methods from vault filter service * [EC-14] remove new methods from old vault-filter.service * [EC-14] Use vault filter service in vault components * [EC-14] reload collections from vault now that we have vault filter service * [EC-14] remove currentFilterCollections in vault filter component * [EC-14] change VaultFilterType to more specific OrganizationFilter in organization-options * [EC-14] include org check in isNodeSelected * [EC-14] add getters to filter function, fix storybook, and add test for All Collections * [EC-14] show org options even if there's a personal vault policy * [EC-14] use !"AllCollections" instead of just !null * [EC-14] Remove extra org Subject in vault filter service * [EC-14] remove null check from vault search text * [EC-14] replace store/build names with set/get. Remove extra call to setOrganizationFilter * [EC-14] add take(1) to subscribe in test * [EC-14] move init logic in org vault filter component to ngOnInit * [EC-14] Fix linter * [EC-14] revert change to vault filter model * [EC-14] be specific about ignoring All Collections * [EC-14] move observable init logic to beforeEach in test * [EC-14] make buildAllFilters return something to reduce side effects Signed-off-by: Jacob Fink <jfink@bitwarden.com> Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com> Co-authored-by: Thomas Rittson <eliykat@users.noreply.github.com> * [EC-97] Organization Billing Language / RxJS Warnings (#3688) * [EC-97] Update copy to use the word members in a few places * [EC-97] Cleanup RxJS warnings and unused properties in org billing components * [EC-599] Access Selector Component (#3717) * Add Access Selector Component and Stories * Cherry pick FormSelectionList * Fix some problems caused from cherry-pick * Fix some Web module problems caused from cherry-pick * Move AccessSelector out of the root components directory. Move UserType pipe to AccessSelectorModule * Fix broken member access selector story * Add organization feature module * Undo changes to messages.json * Fix messages.json * Remove redundant CommonModule * [EC-599] Fix avatar/icon sizing * [EC-599] Remove padding in permission column * [EC-599] Make FormSelectionList operations immutable * [EC-599] Integrate the multi-select component * [EC-599] Handle readonly/access all edge cases * [EC-599] Add initial unit tests Also cleans up public interface for the AccessSelectorComponent. Fixes a bug found during unit test creation. * [EC-599] Include item name in control labels * [EC-599] Cleanup member email display * [EC-599] Review suggestions - Change PermissionMode to Enum - Rename permControl to permissionControl to be more clear - Rename FormSelectionList file to kebab case. - Move permission row boolean logic to named function for readability * [EC-599] Cleanup AccessSelectorComponent tests - Clarify test states - Add tests for column rendering - Add tests for permission mode - Add id to column headers for testing - Fix small permissionControl bug found during testing * [EC-599] Add FormSelectionList unit tests * [EC-599] Fix unit test and linter * [EC-599] Update Enums to Pascal case * [EC-599] Undo change to Enum values * [EC-7] fix: broken build * [EC-646] Org Admin Vault Refresh November Release Prep (#3913) * [EC-646] Remove links from Manage component These links are no longer necessary as they are now located in the new OAVR tabs. * [EC-646] Re-introduce the canAccessManageTab helper * [EC-646] Re-introduce /manage route in Organization routing module - Add the parent /manage route - Add child routes for collections, people, and groups * [EC-646] Adjust Org admin tabs Re-introduce the Manage tab and remove Groups and Members tabs. * [EC-646] Change Members title back to People * [EC-646] Move missing billing components Some billing components were in the org settings module and needed to be moved the org billing module * [EC-646] Fix import file upload button -Update to use click event handler and tailwind class to hide input. Avoids inline styles/js blocked by CSP - Fix broken async pipe * [EC-646] Fix groups and people page overflow Remove the container and page-content wrapper as the pages are no longer on their own tab * [EC-646] Change People to Members Change the text regarding managing members from People to Members to more closely follow changes coming later in the OAVR. Also update the URL to use /manage/members * [EC-646] Cherry-pickae39afeto fix tab text color * [EC-646] Fix org routing permissions helpers - Add canAccessVaultTab helper - Update canAccessOrgAdmin include check for vault tab access - Simplify canManageCollections * [EC-646] Fix Manage tab conditional logic - Add *ngIf condition for rendering Manage tab - Re-introduce dynamic route for Manage tab * Revert "[EC-14] Refactor vault filter (#3440)" (#3926) This reverts commit4d83b81d82. * Remove old reference to bit-submit-button that no longer exists (#3927) * [EC-593] Top align event logs row content (#3813) * [EC-593] Top align event log row contents * [EC-593] Prevent event log timestamp from wrapping * [EC-593] Add alignContent input to bitRow directive * [EC-593] Remove ineffective inline styles (CSP) * [EC-593] Remove templated tailwind classes Tailwind minimizes the bundled stylesheet by removing classes that aren't used in code. Using a string template for the classes causes those classes to be ignored. * [EC-593] Introduce alignContent input to table story * [EC-657] Hide Billing History and Payment Method for selfhosted orgs (#3935) Signed-off-by: Jacob Fink <jfink@bitwarden.com> Co-authored-by: Vincent Salucci <vincesalucci21@gmail.com> Co-authored-by: Andreas Coroiu <andreas.coroiu@gmail.com> Co-authored-by: Jake Fink <jfink@bitwarden.com> Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com> Co-authored-by: Thomas Rittson <eliykat@users.noreply.github.com> * Add padding to top of Safari extension (#3949) * Use correct provider icon instead of bank icon (#3950) * Fix undefined property error in event logs (#3947) EventService.policies was undefined because the service was erroneously using ngOnInit to subscribe to the policies observable * PS-1763 - handle undefined locale value that exists before a user sets their language (#3952) * Autosync the updated translations (#3968) Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com> * Autosync the updated translations (#3967) Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com> * fixed typo in event log (#3962) * Org admin refresh translation nitpicks (#3971) * Fix use of personal in favor of individual vault * Fix capitalization according to #3577 * Fix capitalization on organizationInfo * Autosync the updated translations (#3974) Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com> * Autosync the updated translations (#3973) Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com> * add csp and only pass hostname to duo init (#3972) * add csp and only pass hostname to duo init * expand style-src * Update apps/web/src/connectors/duo.html Co-authored-by: Oscar Hinton <Hinton@users.noreply.github.com> Co-authored-by: Oscar Hinton <Hinton@users.noreply.github.com> * Move hint button out of the formfield (#3960) * [PS-1734] Send saved urls to autofill script (#3861) * Send all saved url to autofill script * Handle array of matched urls in content script * Prompt at most once to override insecure autofill * Do not send never match URIs to content script We know these URIs did not cause the autofill match, so we can safely remove these from the list of potential matches. * [PS-1804] Display Organization tab for users with custom permissions (#3980) * [EC-584] Fixed OrganizationExportResponse to correctly parse data (#3641) * [EC-584] Fixed OrganizationExportResponse to correctly parse data and use CollectionResponse and CipherResponse constructors * [EC-584] Removed ListResponse from OrganizationExportResponse properties * Bumped web version to 2022.10.3 (#3957) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Revert "Bumped web version to 2022.10.3 (#3957)" This reverts commit5d8d547cd2. * Web version bump to 2022.11.0 for QA testing * Revert "Web version bump to 2022.11.0 for QA testing" This reverts commit484db431ed. Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Joseph Flinn <joseph.s.flinn@gmail.com> * [EC-678] [EC-673] Fix active tab not showing selected while in child route (#3964) * [PS-1114] hide reporting sidebar if only events * [PS-1114] add orgRedirectGuard * [PS-1114] highlight tabs based on route subset * [PS-1114] redirect to correct child route on tab - Use new OrgRedirectGuard * [PS-1114] add settings redirect using guard - refactored guard to accept array of strings * [EC-678] [EC-673] remove remaining methods * [EC-678][EC-673] address PR feedback - change switch to if statements - remove ternary * [EC-672] Update SSO login page language (#3997) - Replace 'Organization Identifier' with 'SSO identifier' - Sentence case 'SSO identifier' - Add 'SSO' to SSO login page helper text * Autosync the updated translations (#3969) Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com> * [EC-661] Add web worker code bundles to Safari browser extension (#3986) * Make browser bundle encrypt-worker.ts into a single named file * Add encrypt-worker bundle to xcode proj * Fixed EC reported event log copy bugs (#3977) * [EC-645] fix: web payment component breaking storybook compilation (#3906) * add run-name for releases to include their workflow trigger (#3996) * add run-name for releases to include their workflow trigger * add edit for linter error * Update .github/workflows/release-web.yml Co-authored-by: Vince Grassia <593223+vgrassia@users.noreply.github.com> Co-authored-by: Vince Grassia <593223+vgrassia@users.noreply.github.com> * Extract and fix trigger for PR auto responses (Translation-PRs) (#3992) * Extract and fix trigger for PR auto responses * Fix permission used for job * [EC-650] Revert observable usage from ImportComponent (#4010) * Run enforce labels workflow on version bump in clients repo (#4006) * Fix version bump to run enforce labels workflow * Add login to Azure * Trigger enforce labels manually from bump version workflow * Update .github/workflows/enforce-labels.yml Co-authored-by: Vince Grassia <593223+vgrassia@users.noreply.github.com> * Update .github/workflows/version-bump.yml Co-authored-by: Vince Grassia <593223+vgrassia@users.noreply.github.com> Co-authored-by: Vince Grassia <593223+vgrassia@users.noreply.github.com> * [EC-670] Update Members tab to support flex wrap (#4003) Use tailwind classes to style the Members page header so that it supports wrapping the controls to a new line should they exceed the width of the container. * [PS-1841] Fix org-* commands for CLI (#4013) * Add getFromState method * Added a method for CLI to get an org from state * Converted all CLI calls to `.get()` * Used `.getFromState` instead of `.get` * Deprecate getFromState method * Remove local vaultFilter (#4014) * Use vault filter item from vaultFilterService * [PS-1843] Sort organizations in `buildOrganizations` (#4015) * Sort organizations in buildOrganizations * Add sort by name to Organization Switcher * [EC-675] Display the Event for “Viewed Card Number for item item-identifier” (#3976) * [EC-675] Add missing Event capture for viewing item Card Number * [EC-675] Fix correct event type for viewing item Card Number * Update apps/web/src/locales/en/messages.json Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com> Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com> * [EC-449] Event log user for SCIM events (#3643) * [EC-449] Added EventSystemUser Enum and added systemUser property to eventResponse * [EC-449] Add systemUser property to BaseEventsComponent, EventExport and EventView * [EC-449] Set EventSystemUser as string on EventExport * [EC-449] Remove systemUser from EventExport * [EC-449] Rename EventSystemUser file to lowercase * [EC-449] Force git to rename EventSystemUser file * [EC-449] Rename EventSystemUser file to event-system-user.ts * [EC-449] Fix EventSystemUser reference on EventsComponent * [EC-449] Move installationId username logic to BaseEventsComponent * Update libs/common/src/enums/event-system-user.ts Add a note to warn about using the Enum key in the UI. Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com> * [EC-449] Remove EventSystemUser from provider events. Remove nested condition on events component Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com> * [PS-1840] - fix for covered dropdown on empty vault (#4019) * fix for covered dropdown on empty vault This could be done one of 2-3 ways. I think this might be the least problematic, but could also be done with just changing "position: absolute" to "relative on the ".no-items" class - base.css:461 For some reason, I'm unable to load the spinner to test. * rename class * Remove uses of rxjs in CLI (#4028) * [SM-327] Electron hard reset (#3988) * Add folders to whitelist (#3994) * Defect/sg 650 desktop pw/passphrase gen not auto updating on min value change (#4032) * SG-650 - Desktop - Pw Generation - Min value ctrls now use (change) instead of (blur) for better responsiveness when using arrows on input or arrow keys. Note: (input) has change detection issues for resetting the value to either max pw length or max value of 9 + passwordGeneration.service logic possibly needs refactoring to either enforce max of 9 or not * SG-650 - Desktop - Passphrase Gen - min words now uses (change) instead of (blur) for better responsiveness * Autosync the updated translations (#4035) Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com> * Autosync the updated translations (#4036) Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com> * Autosync the updated translations (#4037) Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com> * Expand serve origin protection warning (#4024) This warning was kept vague during fix rollout, but now that we're more than a release past, we can expand the explanation. * [SM-340] Fix share modal not closing on cancel (#4041) * [EC-739 / EC-740] Add null check to policyFilter on PolicyService (#4039) * [EC-739 / EC-740] Add null check to policyFilter on PolicyService * [EC-739 / EC-740] Add unit tests for policy filter * [PS-1805] BEEEP: Renamed importers based on agreed naming-convention (#3978) * Rename all importer related files Renamed all files based on our naming convention which we decided on with https://github.com/bitwarden/adr/blob/master/decisions/0012-angular-filename-convention.md * Removed entries from whitelist-capital-letters.txt * Rename missing safeInCloud test data * Fix broken import * Renamed folders (removed capital letters) * Fix filename of BitwardenCsvImporter * Fix imports of onepassword mac/win importer tests * Remove already renamed folders from whitelist * Rename dashlaneImporters to dashlane Rename the folder Fix all the imports Remove dashlaneImporters from white-list * Rename keeperImporters to keeper Rename the folder Fix all the imports Remove keeperImporters from white-list * Rename onepasswordImporters to onepassword Rename the folder Fix all the imports Remove onepasswordImporters from white-list * Rename safeinCloud test data folder * Fix onepassword importer type imports * [EC-744] Revert PolicyService back to clearing DecryptedPolicies on StateService (#4042) * [EC-746] Call BaseAddEditComponent.ngOnInit on Desktop AddEditComponent (#4044) * PS-1798 - ensure admin users can edit ciphers (#4025) * Use loginService to get and set remember email values (#3941) * SG-428 - Browser Extension - Send - Expiration / Deletion date calendar icon +… (#4034) * Browser Extension - Send - Expiration / Deletion date calendar icon + datepicker pop up now respect theme better in Chrome / Chromium based browsers and Safari (Firefox datepicker pop up doesn't seem to have an easy mechanism for theming) * SG-428 - Extension - Iconography for date inputs for Chromium browsers now reflects theme colors properly + hover states; icon not shown on non-Chromium browsers * Variables.scss - ran prettier locally after tweaking comments to pass eslint checks * [EC-743] Call super to ngOnInit to include policy observable changes (#4047) * Hide My Vault if Remove Individual Vault is on (#4052) * Devops 1039 update release flow dry run step names (#4016) * Updated workflows to not create Github deployment on Dry Run. (#4049) * Add organization-options menu to single org (#3678) (#4051) Re-apply commit7c3255d(#3678) which was accidentally reverted by the Org Admin Refresh changes in commit09c3bc8(#3925) * SG-725 - Desktop - Moved DuckDuckGo setting down so that the Biometric browser settings are not separated (#4059) * [EC-750] Specify organizationId for credit and adjust payment components (#4061) * [SM-330] Disable managed environments for safari (#3953) * [EC-665] Fix biometrics button style (#3979) * fix biometrics button style * expand button to fill space this is a result of it being used outside the box-content * remove padding from box-footer * Added Mastodon to follow us menu (#4029) * Add branch check for Staged Rollout Desktop workflow (#4062) * [PS-1783] Fix file selector input bug from PS-1465 ( #3502 ) (#3928) * Fix file selector input * Add file selector state changes back * Remove async pipe * Revert "[EC-646] Org Admin Vault Refresh November Release Prep (#3913)" This reverts commit4b57d28e28. * [EC-646] Move missing billing components Some billing components were in the org settings module and needed to be moved the org billing module (cherry picked from commit1c11695f46) * [EC-646] Cherry-pickae39afeto fix tab text color (cherry picked from commit467f584b9e) * Make destroy$ protected to fix linting error Signed-off-by: Jacob Fink <jfink@bitwarden.com> Co-authored-by: Justin Baur <19896123+justindbaur@users.noreply.github.com> Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com> Co-authored-by: Daniel James Smith <djsmith85@users.noreply.github.com> Co-authored-by: Oscar Hinton <Hinton@users.noreply.github.com> Co-authored-by: Sammy Chang <sammychang2185@gmail.com> Co-authored-by: Todd Martin <106564991+trmartin4@users.noreply.github.com> Co-authored-by: Gbubemi Smith <gsmith@bitwarden.com> Co-authored-by: Addison Beck <addisonbeck1@gmail.com> Co-authored-by: Robyn MacCallum <robyntmaccallum@gmail.com> Co-authored-by: gbubemismith <gsmithwalter@gmail.com> Co-authored-by: Kyle Spearrin <kspearrin@users.noreply.github.com> Co-authored-by: Michał Chęciński <mchecinski@bitwarden.com> Co-authored-by: cd-bitwarden <106776772+cd-bitwarden@users.noreply.github.com> Co-authored-by: Scott McFarlane <91044021+scottmondo@users.noreply.github.com> Co-authored-by: Joseph Flinn <58369717+joseph-flinn@users.noreply.github.com> Co-authored-by: Andreas Coroiu <acoroiu@bitwarden.com> Co-authored-by: DanHillesheim <79476558+DanHillesheim@users.noreply.github.com> Co-authored-by: Kyle Spearrin <kyle.spearrin@gmail.com> Co-authored-by: Vincent Salucci <vincesalucci21@gmail.com> Co-authored-by: Andreas Coroiu <andreas.coroiu@gmail.com> Co-authored-by: Jake Fink <jfink@bitwarden.com> Co-authored-by: Thomas Rittson <eliykat@users.noreply.github.com> Co-authored-by: dgoodman-bw <109169446+dgoodman-bw@users.noreply.github.com> Co-authored-by: Danielle Flinn <43477473+danielleflinn@users.noreply.github.com> Co-authored-by: Matt Gibson <mgibson@bitwarden.com> Co-authored-by: Rui Tomé <108268980+r-tome@users.noreply.github.com> Co-authored-by: Joseph Flinn <joseph.s.flinn@gmail.com> Co-authored-by: Opeyemi <54288773+Eebru-gzy@users.noreply.github.com> Co-authored-by: Vince Grassia <593223+vgrassia@users.noreply.github.com> Co-authored-by: Jared Snider <116684653+JaredSnider-Bitwarden@users.noreply.github.com> Co-authored-by: Vincent Salucci <26154748+vincentsalucci@users.noreply.github.com> Co-authored-by: Ash Leece <ash@leece.im>
2427 lines
79 KiB
TypeScript
2427 lines
79 KiB
TypeScript
import { ApiService as ApiServiceAbstraction } from "../abstractions/api.service";
|
|
import { AppIdService } from "../abstractions/appId.service";
|
|
import { EnvironmentService } from "../abstractions/environment.service";
|
|
import { PlatformUtilsService } from "../abstractions/platformUtils.service";
|
|
import { TokenService } from "../abstractions/token.service";
|
|
import { DeviceType } from "../enums/deviceType";
|
|
import { OrganizationConnectionType } from "../enums/organizationConnectionType";
|
|
import { Utils } from "../misc/utils";
|
|
import { SetKeyConnectorKeyRequest } from "../models/request/account/set-key-connector-key.request";
|
|
import { AttachmentRequest } from "../models/request/attachment.request";
|
|
import { BitPayInvoiceRequest } from "../models/request/bit-pay-invoice.request";
|
|
import { CipherBulkDeleteRequest } from "../models/request/cipher-bulk-delete.request";
|
|
import { CipherBulkMoveRequest } from "../models/request/cipher-bulk-move.request";
|
|
import { CipherBulkShareRequest } from "../models/request/cipher-bulk-share.request";
|
|
import { CipherCollectionsRequest } from "../models/request/cipher-collections.request";
|
|
import { CipherCreateRequest } from "../models/request/cipher-create.request";
|
|
import { CipherPartialRequest } from "../models/request/cipher-partial.request";
|
|
import { CipherShareRequest } from "../models/request/cipher-share.request";
|
|
import { CipherRequest } from "../models/request/cipher.request";
|
|
import { CollectionRequest } from "../models/request/collection.request";
|
|
import { DeleteRecoverRequest } from "../models/request/delete-recover.request";
|
|
import { DeviceVerificationRequest } from "../models/request/device-verification.request";
|
|
import { DeviceRequest } from "../models/request/device.request";
|
|
import { EmailTokenRequest } from "../models/request/email-token.request";
|
|
import { EmailRequest } from "../models/request/email.request";
|
|
import { EmergencyAccessAcceptRequest } from "../models/request/emergency-access-accept.request";
|
|
import { EmergencyAccessConfirmRequest } from "../models/request/emergency-access-confirm.request";
|
|
import { EmergencyAccessInviteRequest } from "../models/request/emergency-access-invite.request";
|
|
import { EmergencyAccessPasswordRequest } from "../models/request/emergency-access-password.request";
|
|
import { EmergencyAccessUpdateRequest } from "../models/request/emergency-access-update.request";
|
|
import { EventRequest } from "../models/request/event.request";
|
|
import { GroupRequest } from "../models/request/group.request";
|
|
import { IapCheckRequest } from "../models/request/iap-check.request";
|
|
import { ApiTokenRequest } from "../models/request/identity-token/api-token.request";
|
|
import { PasswordTokenRequest } from "../models/request/identity-token/password-token.request";
|
|
import { SsoTokenRequest } from "../models/request/identity-token/sso-token.request";
|
|
import { TokenTwoFactorRequest } from "../models/request/identity-token/token-two-factor.request";
|
|
import { ImportCiphersRequest } from "../models/request/import-ciphers.request";
|
|
import { ImportOrganizationCiphersRequest } from "../models/request/import-organization-ciphers.request";
|
|
import { KdfRequest } from "../models/request/kdf.request";
|
|
import { KeyConnectorUserKeyRequest } from "../models/request/key-connector-user-key.request";
|
|
import { KeysRequest } from "../models/request/keys.request";
|
|
import { OrganizationConnectionRequest } from "../models/request/organization-connection.request";
|
|
import { OrganizationImportRequest } from "../models/request/organization-import.request";
|
|
import { OrganizationUserAcceptRequest } from "../models/request/organization-user-accept.request";
|
|
import { OrganizationUserBulkConfirmRequest } from "../models/request/organization-user-bulk-confirm.request";
|
|
import { OrganizationUserBulkRequest } from "../models/request/organization-user-bulk.request";
|
|
import { OrganizationUserConfirmRequest } from "../models/request/organization-user-confirm.request";
|
|
import { OrganizationUserInviteRequest } from "../models/request/organization-user-invite.request";
|
|
import { OrganizationUserResetPasswordEnrollmentRequest } from "../models/request/organization-user-reset-password-enrollment.request";
|
|
import { OrganizationUserResetPasswordRequest } from "../models/request/organization-user-reset-password.request";
|
|
import { OrganizationUserUpdateGroupsRequest } from "../models/request/organization-user-update-groups.request";
|
|
import { OrganizationUserUpdateRequest } from "../models/request/organization-user-update.request";
|
|
import { OrganizationSponsorshipCreateRequest } from "../models/request/organization/organization-sponsorship-create.request";
|
|
import { OrganizationSponsorshipRedeemRequest } from "../models/request/organization/organization-sponsorship-redeem.request";
|
|
import { PasswordHintRequest } from "../models/request/password-hint.request";
|
|
import { PasswordRequest } from "../models/request/password.request";
|
|
import { PasswordlessCreateAuthRequest } from "../models/request/passwordless-create-auth.request";
|
|
import { PaymentRequest } from "../models/request/payment.request";
|
|
import { PreloginRequest } from "../models/request/prelogin.request";
|
|
import { ProviderAddOrganizationRequest } from "../models/request/provider/provider-add-organization.request";
|
|
import { ProviderOrganizationCreateRequest } from "../models/request/provider/provider-organization-create.request";
|
|
import { ProviderSetupRequest } from "../models/request/provider/provider-setup.request";
|
|
import { ProviderUpdateRequest } from "../models/request/provider/provider-update.request";
|
|
import { ProviderUserAcceptRequest } from "../models/request/provider/provider-user-accept.request";
|
|
import { ProviderUserBulkConfirmRequest } from "../models/request/provider/provider-user-bulk-confirm.request";
|
|
import { ProviderUserBulkRequest } from "../models/request/provider/provider-user-bulk.request";
|
|
import { ProviderUserConfirmRequest } from "../models/request/provider/provider-user-confirm.request";
|
|
import { ProviderUserInviteRequest } from "../models/request/provider/provider-user-invite.request";
|
|
import { ProviderUserUpdateRequest } from "../models/request/provider/provider-user-update.request";
|
|
import { RegisterRequest } from "../models/request/register.request";
|
|
import { SecretVerificationRequest } from "../models/request/secret-verification.request";
|
|
import { SelectionReadOnlyRequest } from "../models/request/selection-read-only.request";
|
|
import { SendAccessRequest } from "../models/request/send-access.request";
|
|
import { SendRequest } from "../models/request/send.request";
|
|
import { SetPasswordRequest } from "../models/request/set-password.request";
|
|
import { StorageRequest } from "../models/request/storage.request";
|
|
import { TaxInfoUpdateRequest } from "../models/request/tax-info-update.request";
|
|
import { TwoFactorEmailRequest } from "../models/request/two-factor-email.request";
|
|
import { TwoFactorProviderRequest } from "../models/request/two-factor-provider.request";
|
|
import { TwoFactorRecoveryRequest } from "../models/request/two-factor-recovery.request";
|
|
import { UpdateDomainsRequest } from "../models/request/update-domains.request";
|
|
import { UpdateKeyRequest } from "../models/request/update-key.request";
|
|
import { UpdateProfileRequest } from "../models/request/update-profile.request";
|
|
import { UpdateTempPasswordRequest } from "../models/request/update-temp-password.request";
|
|
import { UpdateTwoFactorAuthenticatorRequest } from "../models/request/update-two-factor-authenticator.request";
|
|
import { UpdateTwoFactorDuoRequest } from "../models/request/update-two-factor-duo.request";
|
|
import { UpdateTwoFactorEmailRequest } from "../models/request/update-two-factor-email.request";
|
|
import { UpdateTwoFactorWebAuthnDeleteRequest } from "../models/request/update-two-factor-web-authn-delete.request";
|
|
import { UpdateTwoFactorWebAuthnRequest } from "../models/request/update-two-factor-web-authn.request";
|
|
import { UpdateTwoFactorYubioOtpRequest } from "../models/request/update-two-factor-yubio-otp.request";
|
|
import { VerifyDeleteRecoverRequest } from "../models/request/verify-delete-recover.request";
|
|
import { VerifyEmailRequest } from "../models/request/verify-email.request";
|
|
import { ApiKeyResponse } from "../models/response/api-key.response";
|
|
import { AttachmentUploadDataResponse } from "../models/response/attachment-upload-data.response";
|
|
import { AttachmentResponse } from "../models/response/attachment.response";
|
|
import { AuthRequestResponse } from "../models/response/auth-request.response";
|
|
import { RegisterResponse } from "../models/response/authentication/register.response";
|
|
import { BillingHistoryResponse } from "../models/response/billing-history.response";
|
|
import { BillingPaymentResponse } from "../models/response/billing-payment.response";
|
|
import { BreachAccountResponse } from "../models/response/breach-account.response";
|
|
import { CipherResponse } from "../models/response/cipher.response";
|
|
import {
|
|
CollectionGroupDetailsResponse,
|
|
CollectionResponse,
|
|
} from "../models/response/collection.response";
|
|
import { DeviceVerificationResponse } from "../models/response/device-verification.response";
|
|
import { DomainsResponse } from "../models/response/domains.response";
|
|
import {
|
|
EmergencyAccessGranteeDetailsResponse,
|
|
EmergencyAccessGrantorDetailsResponse,
|
|
EmergencyAccessTakeoverResponse,
|
|
EmergencyAccessViewResponse,
|
|
} from "../models/response/emergency-access.response";
|
|
import { ErrorResponse } from "../models/response/error.response";
|
|
import { EventResponse } from "../models/response/event.response";
|
|
import { GroupDetailsResponse, GroupResponse } from "../models/response/group.response";
|
|
import { IdentityCaptchaResponse } from "../models/response/identity-captcha.response";
|
|
import { IdentityTokenResponse } from "../models/response/identity-token.response";
|
|
import { IdentityTwoFactorResponse } from "../models/response/identity-two-factor.response";
|
|
import { KeyConnectorUserKeyResponse } from "../models/response/key-connector-user-key.response";
|
|
import { ListResponse } from "../models/response/list.response";
|
|
import {
|
|
OrganizationConnectionConfigApis,
|
|
OrganizationConnectionResponse,
|
|
} from "../models/response/organization-connection.response";
|
|
import { OrganizationExportResponse } from "../models/response/organization-export.response";
|
|
import { OrganizationSponsorshipSyncStatusResponse } from "../models/response/organization-sponsorship-sync-status.response";
|
|
import { OrganizationUserBulkPublicKeyResponse } from "../models/response/organization-user-bulk-public-key.response";
|
|
import { OrganizationUserBulkResponse } from "../models/response/organization-user-bulk.response";
|
|
import {
|
|
OrganizationUserDetailsResponse,
|
|
OrganizationUserUserDetailsResponse,
|
|
OrganizationUserResetPasswordDetailsReponse,
|
|
} from "../models/response/organization-user.response";
|
|
import { PaymentResponse } from "../models/response/payment.response";
|
|
import { PlanResponse } from "../models/response/plan.response";
|
|
import { PolicyResponse } from "../models/response/policy.response";
|
|
import { PreloginResponse } from "../models/response/prelogin.response";
|
|
import { ProfileResponse } from "../models/response/profile.response";
|
|
import {
|
|
ProviderOrganizationOrganizationDetailsResponse,
|
|
ProviderOrganizationResponse,
|
|
} from "../models/response/provider/provider-organization.response";
|
|
import { ProviderUserBulkPublicKeyResponse } from "../models/response/provider/provider-user-bulk-public-key.response";
|
|
import { ProviderUserBulkResponse } from "../models/response/provider/provider-user-bulk.response";
|
|
import {
|
|
ProviderUserResponse,
|
|
ProviderUserUserDetailsResponse,
|
|
} from "../models/response/provider/provider-user.response";
|
|
import { ProviderResponse } from "../models/response/provider/provider.response";
|
|
import { SelectionReadOnlyResponse } from "../models/response/selection-read-only.response";
|
|
import { SendAccessResponse } from "../models/response/send-access.response";
|
|
import { SendFileDownloadDataResponse } from "../models/response/send-file-download-data.response";
|
|
import { SendFileUploadDataResponse } from "../models/response/send-file-upload-data.response";
|
|
import { SendResponse } from "../models/response/send.response";
|
|
import { SsoPreValidateResponse } from "../models/response/sso-pre-validate.response";
|
|
import { SubscriptionResponse } from "../models/response/subscription.response";
|
|
import { SyncResponse } from "../models/response/sync.response";
|
|
import { TaxInfoResponse } from "../models/response/tax-info.response";
|
|
import { TaxRateResponse } from "../models/response/tax-rate.response";
|
|
import { TwoFactorAuthenticatorResponse } from "../models/response/two-factor-authenticator.response";
|
|
import { TwoFactorDuoResponse } from "../models/response/two-factor-duo.response";
|
|
import { TwoFactorEmailResponse } from "../models/response/two-factor-email.response";
|
|
import { TwoFactorProviderResponse } from "../models/response/two-factor-provider.response";
|
|
import { TwoFactorRecoverResponse } from "../models/response/two-factor-recover.response";
|
|
import {
|
|
TwoFactorWebAuthnResponse,
|
|
ChallengeResponse,
|
|
} from "../models/response/two-factor-web-authn.response";
|
|
import { TwoFactorYubiKeyResponse } from "../models/response/two-factor-yubi-key.response";
|
|
import { UserKeyResponse } from "../models/response/user-key.response";
|
|
import { SendAccessView } from "../models/view/send-access.view";
|
|
|
|
export class ApiService implements ApiServiceAbstraction {
|
|
private device: DeviceType;
|
|
private deviceType: string;
|
|
private isWebClient = false;
|
|
private isDesktopClient = false;
|
|
|
|
constructor(
|
|
private tokenService: TokenService,
|
|
private platformUtilsService: PlatformUtilsService,
|
|
private environmentService: EnvironmentService,
|
|
private appIdService: AppIdService,
|
|
private logoutCallback: (expired: boolean) => Promise<void>,
|
|
private customUserAgent: string = null
|
|
) {
|
|
this.device = platformUtilsService.getDevice();
|
|
this.deviceType = this.device.toString();
|
|
this.isWebClient =
|
|
this.device === DeviceType.IEBrowser ||
|
|
this.device === DeviceType.ChromeBrowser ||
|
|
this.device === DeviceType.EdgeBrowser ||
|
|
this.device === DeviceType.FirefoxBrowser ||
|
|
this.device === DeviceType.OperaBrowser ||
|
|
this.device === DeviceType.SafariBrowser ||
|
|
this.device === DeviceType.UnknownBrowser ||
|
|
this.device === DeviceType.VivaldiBrowser;
|
|
this.isDesktopClient =
|
|
this.device === DeviceType.WindowsDesktop ||
|
|
this.device === DeviceType.MacOsDesktop ||
|
|
this.device === DeviceType.LinuxDesktop;
|
|
}
|
|
|
|
// Auth APIs
|
|
|
|
async postIdentityToken(
|
|
request: ApiTokenRequest | PasswordTokenRequest | SsoTokenRequest
|
|
): Promise<IdentityTokenResponse | IdentityTwoFactorResponse | IdentityCaptchaResponse> {
|
|
const headers = new Headers({
|
|
"Content-Type": "application/x-www-form-urlencoded; charset=utf-8",
|
|
Accept: "application/json",
|
|
"Device-Type": this.deviceType,
|
|
});
|
|
if (this.customUserAgent != null) {
|
|
headers.set("User-Agent", this.customUserAgent);
|
|
}
|
|
request.alterIdentityTokenHeaders(headers);
|
|
|
|
const identityToken =
|
|
request instanceof ApiTokenRequest
|
|
? request.toIdentityToken()
|
|
: request.toIdentityToken(this.platformUtilsService.getClientType());
|
|
|
|
const response = await this.fetch(
|
|
new Request(this.environmentService.getIdentityUrl() + "/connect/token", {
|
|
body: this.qsStringify(identityToken),
|
|
credentials: this.getCredentials(),
|
|
cache: "no-store",
|
|
headers: headers,
|
|
method: "POST",
|
|
})
|
|
);
|
|
|
|
let responseJson: any = null;
|
|
if (this.isJsonResponse(response)) {
|
|
responseJson = await response.json();
|
|
}
|
|
|
|
if (responseJson != null) {
|
|
if (response.status === 200) {
|
|
return new IdentityTokenResponse(responseJson);
|
|
} else if (
|
|
response.status === 400 &&
|
|
responseJson.TwoFactorProviders2 &&
|
|
Object.keys(responseJson.TwoFactorProviders2).length
|
|
) {
|
|
await this.tokenService.clearTwoFactorToken();
|
|
return new IdentityTwoFactorResponse(responseJson);
|
|
} else if (
|
|
response.status === 400 &&
|
|
responseJson.HCaptcha_SiteKey &&
|
|
Object.keys(responseJson.HCaptcha_SiteKey).length
|
|
) {
|
|
return new IdentityCaptchaResponse(responseJson);
|
|
}
|
|
}
|
|
|
|
return Promise.reject(new ErrorResponse(responseJson, response.status, true));
|
|
}
|
|
|
|
async refreshIdentityToken(): Promise<any> {
|
|
try {
|
|
await this.doAuthRefresh();
|
|
} catch (e) {
|
|
return Promise.reject(null);
|
|
}
|
|
}
|
|
|
|
async postAuthRequest(request: PasswordlessCreateAuthRequest): Promise<AuthRequestResponse> {
|
|
const r = await this.send("POST", "/auth-requests/", request, false, true);
|
|
return new AuthRequestResponse(r);
|
|
}
|
|
|
|
async getAuthResponse(id: string, accessCode: string): Promise<AuthRequestResponse> {
|
|
const path = `/auth-requests/${id}/response?code=${accessCode}`;
|
|
const r = await this.send("GET", path, null, false, true);
|
|
return new AuthRequestResponse(r);
|
|
}
|
|
|
|
// Account APIs
|
|
|
|
async getProfile(): Promise<ProfileResponse> {
|
|
const r = await this.send("GET", "/accounts/profile", null, true, true);
|
|
return new ProfileResponse(r);
|
|
}
|
|
|
|
async getUserSubscription(): Promise<SubscriptionResponse> {
|
|
const r = await this.send("GET", "/accounts/subscription", null, true, true);
|
|
return new SubscriptionResponse(r);
|
|
}
|
|
|
|
async getTaxInfo(): Promise<TaxInfoResponse> {
|
|
const r = await this.send("GET", "/accounts/tax", null, true, true);
|
|
return new TaxInfoResponse(r);
|
|
}
|
|
|
|
async putProfile(request: UpdateProfileRequest): Promise<ProfileResponse> {
|
|
const r = await this.send("PUT", "/accounts/profile", request, true, true);
|
|
return new ProfileResponse(r);
|
|
}
|
|
|
|
putTaxInfo(request: TaxInfoUpdateRequest): Promise<any> {
|
|
return this.send("PUT", "/accounts/tax", request, true, false);
|
|
}
|
|
|
|
async postPrelogin(request: PreloginRequest): Promise<PreloginResponse> {
|
|
const r = await this.send(
|
|
"POST",
|
|
"/accounts/prelogin",
|
|
request,
|
|
false,
|
|
true,
|
|
this.environmentService.getIdentityUrl()
|
|
);
|
|
return new PreloginResponse(r);
|
|
}
|
|
|
|
postEmailToken(request: EmailTokenRequest): Promise<any> {
|
|
return this.send("POST", "/accounts/email-token", request, true, false);
|
|
}
|
|
|
|
postEmail(request: EmailRequest): Promise<any> {
|
|
return this.send("POST", "/accounts/email", request, true, false);
|
|
}
|
|
|
|
postPassword(request: PasswordRequest): Promise<any> {
|
|
return this.send("POST", "/accounts/password", request, true, false);
|
|
}
|
|
|
|
setPassword(request: SetPasswordRequest): Promise<any> {
|
|
return this.send("POST", "/accounts/set-password", request, true, false);
|
|
}
|
|
|
|
postSetKeyConnectorKey(request: SetKeyConnectorKeyRequest): Promise<any> {
|
|
return this.send("POST", "/accounts/set-key-connector-key", request, true, false);
|
|
}
|
|
|
|
postSecurityStamp(request: SecretVerificationRequest): Promise<any> {
|
|
return this.send("POST", "/accounts/security-stamp", request, true, false);
|
|
}
|
|
|
|
async getAccountRevisionDate(): Promise<number> {
|
|
const r = await this.send("GET", "/accounts/revision-date", null, true, true);
|
|
return r as number;
|
|
}
|
|
|
|
postPasswordHint(request: PasswordHintRequest): Promise<any> {
|
|
return this.send("POST", "/accounts/password-hint", request, false, false);
|
|
}
|
|
|
|
async postRegister(request: RegisterRequest): Promise<RegisterResponse> {
|
|
const r = await this.send(
|
|
"POST",
|
|
"/accounts/register",
|
|
request,
|
|
false,
|
|
true,
|
|
this.environmentService.getIdentityUrl()
|
|
);
|
|
return new RegisterResponse(r);
|
|
}
|
|
|
|
async postPremium(data: FormData): Promise<PaymentResponse> {
|
|
const r = await this.send("POST", "/accounts/premium", data, true, true);
|
|
return new PaymentResponse(r);
|
|
}
|
|
|
|
async postIapCheck(request: IapCheckRequest): Promise<any> {
|
|
return this.send("POST", "/accounts/iap-check", request, true, false);
|
|
}
|
|
|
|
postReinstatePremium(): Promise<any> {
|
|
return this.send("POST", "/accounts/reinstate-premium", null, true, false);
|
|
}
|
|
|
|
postCancelPremium(): Promise<any> {
|
|
return this.send("POST", "/accounts/cancel-premium", null, true, false);
|
|
}
|
|
|
|
async postAccountStorage(request: StorageRequest): Promise<PaymentResponse> {
|
|
const r = await this.send("POST", "/accounts/storage", request, true, true);
|
|
return new PaymentResponse(r);
|
|
}
|
|
|
|
postAccountPayment(request: PaymentRequest): Promise<void> {
|
|
return this.send("POST", "/accounts/payment", request, true, false);
|
|
}
|
|
|
|
postAccountLicense(data: FormData): Promise<any> {
|
|
return this.send("POST", "/accounts/license", data, true, false);
|
|
}
|
|
|
|
postAccountKeys(request: KeysRequest): Promise<any> {
|
|
return this.send("POST", "/accounts/keys", request, true, false);
|
|
}
|
|
|
|
postAccountKey(request: UpdateKeyRequest): Promise<any> {
|
|
return this.send("POST", "/accounts/key", request, true, false);
|
|
}
|
|
|
|
postAccountVerifyEmail(): Promise<any> {
|
|
return this.send("POST", "/accounts/verify-email", null, true, false);
|
|
}
|
|
|
|
postAccountVerifyEmailToken(request: VerifyEmailRequest): Promise<any> {
|
|
return this.send("POST", "/accounts/verify-email-token", request, false, false);
|
|
}
|
|
|
|
postAccountVerifyPassword(request: SecretVerificationRequest): Promise<any> {
|
|
return this.send("POST", "/accounts/verify-password", request, true, false);
|
|
}
|
|
|
|
postAccountRecoverDelete(request: DeleteRecoverRequest): Promise<any> {
|
|
return this.send("POST", "/accounts/delete-recover", request, false, false);
|
|
}
|
|
|
|
postAccountRecoverDeleteToken(request: VerifyDeleteRecoverRequest): Promise<any> {
|
|
return this.send("POST", "/accounts/delete-recover-token", request, false, false);
|
|
}
|
|
|
|
postAccountKdf(request: KdfRequest): Promise<any> {
|
|
return this.send("POST", "/accounts/kdf", request, true, false);
|
|
}
|
|
|
|
async deleteSsoUser(organizationId: string): Promise<void> {
|
|
return this.send("DELETE", "/accounts/sso/" + organizationId, null, true, false);
|
|
}
|
|
|
|
async getSsoUserIdentifier(): Promise<string> {
|
|
return this.send("GET", "/accounts/sso/user-identifier", null, true, true);
|
|
}
|
|
|
|
async postUserApiKey(id: string, request: SecretVerificationRequest): Promise<ApiKeyResponse> {
|
|
const r = await this.send("POST", "/accounts/api-key", request, true, true);
|
|
return new ApiKeyResponse(r);
|
|
}
|
|
|
|
async postUserRotateApiKey(
|
|
id: string,
|
|
request: SecretVerificationRequest
|
|
): Promise<ApiKeyResponse> {
|
|
const r = await this.send("POST", "/accounts/rotate-api-key", request, true, true);
|
|
return new ApiKeyResponse(r);
|
|
}
|
|
|
|
putUpdateTempPassword(request: UpdateTempPasswordRequest): Promise<any> {
|
|
return this.send("PUT", "/accounts/update-temp-password", request, true, false);
|
|
}
|
|
|
|
postConvertToKeyConnector(): Promise<void> {
|
|
return this.send("POST", "/accounts/convert-to-key-connector", null, true, false);
|
|
}
|
|
|
|
// Account Billing APIs
|
|
|
|
async getUserBillingHistory(): Promise<BillingHistoryResponse> {
|
|
const r = await this.send("GET", "/accounts/billing/history", null, true, true);
|
|
return new BillingHistoryResponse(r);
|
|
}
|
|
|
|
async getUserBillingPayment(): Promise<BillingPaymentResponse> {
|
|
const r = await this.send("GET", "/accounts/billing/payment-method", null, true, true);
|
|
return new BillingPaymentResponse(r);
|
|
}
|
|
|
|
// Send APIs
|
|
|
|
async getSend(id: string): Promise<SendResponse> {
|
|
const r = await this.send("GET", "/sends/" + id, null, true, true);
|
|
return new SendResponse(r);
|
|
}
|
|
|
|
async postSendAccess(
|
|
id: string,
|
|
request: SendAccessRequest,
|
|
apiUrl?: string
|
|
): Promise<SendAccessResponse> {
|
|
const addSendIdHeader = (headers: Headers) => {
|
|
headers.set("Send-Id", id);
|
|
};
|
|
const r = await this.send(
|
|
"POST",
|
|
"/sends/access/" + id,
|
|
request,
|
|
false,
|
|
true,
|
|
apiUrl,
|
|
addSendIdHeader
|
|
);
|
|
return new SendAccessResponse(r);
|
|
}
|
|
|
|
async getSendFileDownloadData(
|
|
send: SendAccessView,
|
|
request: SendAccessRequest,
|
|
apiUrl?: string
|
|
): Promise<SendFileDownloadDataResponse> {
|
|
const addSendIdHeader = (headers: Headers) => {
|
|
headers.set("Send-Id", send.id);
|
|
};
|
|
const r = await this.send(
|
|
"POST",
|
|
"/sends/" + send.id + "/access/file/" + send.file.id,
|
|
request,
|
|
false,
|
|
true,
|
|
apiUrl,
|
|
addSendIdHeader
|
|
);
|
|
return new SendFileDownloadDataResponse(r);
|
|
}
|
|
|
|
async getSends(): Promise<ListResponse<SendResponse>> {
|
|
const r = await this.send("GET", "/sends", null, true, true);
|
|
return new ListResponse(r, SendResponse);
|
|
}
|
|
|
|
async postSend(request: SendRequest): Promise<SendResponse> {
|
|
const r = await this.send("POST", "/sends", request, true, true);
|
|
return new SendResponse(r);
|
|
}
|
|
|
|
async postFileTypeSend(request: SendRequest): Promise<SendFileUploadDataResponse> {
|
|
const r = await this.send("POST", "/sends/file/v2", request, true, true);
|
|
return new SendFileUploadDataResponse(r);
|
|
}
|
|
|
|
async renewSendFileUploadUrl(
|
|
sendId: string,
|
|
fileId: string
|
|
): Promise<SendFileUploadDataResponse> {
|
|
const r = await this.send("GET", "/sends/" + sendId + "/file/" + fileId, null, true, true);
|
|
return new SendFileUploadDataResponse(r);
|
|
}
|
|
|
|
postSendFile(sendId: string, fileId: string, data: FormData): Promise<any> {
|
|
return this.send("POST", "/sends/" + sendId + "/file/" + fileId, data, true, false);
|
|
}
|
|
|
|
/**
|
|
* @deprecated Mar 25 2021: This method has been deprecated in favor of direct uploads.
|
|
* This method still exists for backward compatibility with old server versions.
|
|
*/
|
|
async postSendFileLegacy(data: FormData): Promise<SendResponse> {
|
|
const r = await this.send("POST", "/sends/file", data, true, true);
|
|
return new SendResponse(r);
|
|
}
|
|
|
|
async putSend(id: string, request: SendRequest): Promise<SendResponse> {
|
|
const r = await this.send("PUT", "/sends/" + id, request, true, true);
|
|
return new SendResponse(r);
|
|
}
|
|
|
|
async putSendRemovePassword(id: string): Promise<SendResponse> {
|
|
const r = await this.send("PUT", "/sends/" + id + "/remove-password", null, true, true);
|
|
return new SendResponse(r);
|
|
}
|
|
|
|
deleteSend(id: string): Promise<any> {
|
|
return this.send("DELETE", "/sends/" + id, null, true, false);
|
|
}
|
|
|
|
// Cipher APIs
|
|
|
|
async getCipher(id: string): Promise<CipherResponse> {
|
|
const r = await this.send("GET", "/ciphers/" + id, null, true, true);
|
|
return new CipherResponse(r);
|
|
}
|
|
|
|
async getFullCipherDetails(id: string): Promise<CipherResponse> {
|
|
const r = await this.send("GET", "/ciphers/" + id + "/details", null, true, true);
|
|
return new CipherResponse(r);
|
|
}
|
|
|
|
async getCipherAdmin(id: string): Promise<CipherResponse> {
|
|
const r = await this.send("GET", "/ciphers/" + id + "/admin", null, true, true);
|
|
return new CipherResponse(r);
|
|
}
|
|
|
|
async getCiphersOrganization(organizationId: string): Promise<ListResponse<CipherResponse>> {
|
|
const r = await this.send(
|
|
"GET",
|
|
"/ciphers/organization-details?organizationId=" + organizationId,
|
|
null,
|
|
true,
|
|
true
|
|
);
|
|
return new ListResponse(r, CipherResponse);
|
|
}
|
|
|
|
async postCipher(request: CipherRequest): Promise<CipherResponse> {
|
|
const r = await this.send("POST", "/ciphers", request, true, true);
|
|
return new CipherResponse(r);
|
|
}
|
|
|
|
async postCipherCreate(request: CipherCreateRequest): Promise<CipherResponse> {
|
|
const r = await this.send("POST", "/ciphers/create", request, true, true);
|
|
return new CipherResponse(r);
|
|
}
|
|
|
|
async postCipherAdmin(request: CipherCreateRequest): Promise<CipherResponse> {
|
|
const r = await this.send("POST", "/ciphers/admin", request, true, true);
|
|
return new CipherResponse(r);
|
|
}
|
|
|
|
async putCipher(id: string, request: CipherRequest): Promise<CipherResponse> {
|
|
const r = await this.send("PUT", "/ciphers/" + id, request, true, true);
|
|
return new CipherResponse(r);
|
|
}
|
|
|
|
async putPartialCipher(id: string, request: CipherPartialRequest): Promise<CipherResponse> {
|
|
const r = await this.send("PUT", "/ciphers/" + id + "/partial", request, true, true);
|
|
return new CipherResponse(r);
|
|
}
|
|
|
|
async putCipherAdmin(id: string, request: CipherRequest): Promise<CipherResponse> {
|
|
const r = await this.send("PUT", "/ciphers/" + id + "/admin", request, true, true);
|
|
return new CipherResponse(r);
|
|
}
|
|
|
|
deleteCipher(id: string): Promise<any> {
|
|
return this.send("DELETE", "/ciphers/" + id, null, true, false);
|
|
}
|
|
|
|
deleteCipherAdmin(id: string): Promise<any> {
|
|
return this.send("DELETE", "/ciphers/" + id + "/admin", null, true, false);
|
|
}
|
|
|
|
deleteManyCiphers(request: CipherBulkDeleteRequest): Promise<any> {
|
|
return this.send("DELETE", "/ciphers", request, true, false);
|
|
}
|
|
|
|
deleteManyCiphersAdmin(request: CipherBulkDeleteRequest): Promise<any> {
|
|
return this.send("DELETE", "/ciphers/admin", request, true, false);
|
|
}
|
|
|
|
putMoveCiphers(request: CipherBulkMoveRequest): Promise<any> {
|
|
return this.send("PUT", "/ciphers/move", request, true, false);
|
|
}
|
|
|
|
async putShareCipher(id: string, request: CipherShareRequest): Promise<CipherResponse> {
|
|
const r = await this.send("PUT", "/ciphers/" + id + "/share", request, true, true);
|
|
return new CipherResponse(r);
|
|
}
|
|
|
|
putShareCiphers(request: CipherBulkShareRequest): Promise<any> {
|
|
return this.send("PUT", "/ciphers/share", request, true, false);
|
|
}
|
|
|
|
putCipherCollections(id: string, request: CipherCollectionsRequest): Promise<any> {
|
|
return this.send("PUT", "/ciphers/" + id + "/collections", request, true, false);
|
|
}
|
|
|
|
putCipherCollectionsAdmin(id: string, request: CipherCollectionsRequest): Promise<any> {
|
|
return this.send("PUT", "/ciphers/" + id + "/collections-admin", request, true, false);
|
|
}
|
|
|
|
postPurgeCiphers(
|
|
request: SecretVerificationRequest,
|
|
organizationId: string = null
|
|
): Promise<any> {
|
|
let path = "/ciphers/purge";
|
|
if (organizationId != null) {
|
|
path += "?organizationId=" + organizationId;
|
|
}
|
|
return this.send("POST", path, request, true, false);
|
|
}
|
|
|
|
postImportCiphers(request: ImportCiphersRequest): Promise<any> {
|
|
return this.send("POST", "/ciphers/import", request, true, false);
|
|
}
|
|
|
|
postImportOrganizationCiphers(
|
|
organizationId: string,
|
|
request: ImportOrganizationCiphersRequest
|
|
): Promise<any> {
|
|
return this.send(
|
|
"POST",
|
|
"/ciphers/import-organization?organizationId=" + organizationId,
|
|
request,
|
|
true,
|
|
false
|
|
);
|
|
}
|
|
|
|
putDeleteCipher(id: string): Promise<any> {
|
|
return this.send("PUT", "/ciphers/" + id + "/delete", null, true, false);
|
|
}
|
|
|
|
putDeleteCipherAdmin(id: string): Promise<any> {
|
|
return this.send("PUT", "/ciphers/" + id + "/delete-admin", null, true, false);
|
|
}
|
|
|
|
putDeleteManyCiphers(request: CipherBulkDeleteRequest): Promise<any> {
|
|
return this.send("PUT", "/ciphers/delete", request, true, false);
|
|
}
|
|
|
|
putDeleteManyCiphersAdmin(request: CipherBulkDeleteRequest): Promise<any> {
|
|
return this.send("PUT", "/ciphers/delete-admin", request, true, false);
|
|
}
|
|
|
|
async putRestoreCipher(id: string): Promise<CipherResponse> {
|
|
const r = await this.send("PUT", "/ciphers/" + id + "/restore", null, true, true);
|
|
return new CipherResponse(r);
|
|
}
|
|
|
|
async putRestoreCipherAdmin(id: string): Promise<CipherResponse> {
|
|
const r = await this.send("PUT", "/ciphers/" + id + "/restore-admin", null, true, true);
|
|
return new CipherResponse(r);
|
|
}
|
|
|
|
async putRestoreManyCiphers(
|
|
request: CipherBulkDeleteRequest
|
|
): Promise<ListResponse<CipherResponse>> {
|
|
const r = await this.send("PUT", "/ciphers/restore", request, true, true);
|
|
return new ListResponse<CipherResponse>(r, CipherResponse);
|
|
}
|
|
|
|
// Attachments APIs
|
|
|
|
async getAttachmentData(
|
|
cipherId: string,
|
|
attachmentId: string,
|
|
emergencyAccessId?: string
|
|
): Promise<AttachmentResponse> {
|
|
const path =
|
|
(emergencyAccessId != null ? "/emergency-access/" + emergencyAccessId + "/" : "/ciphers/") +
|
|
cipherId +
|
|
"/attachment/" +
|
|
attachmentId;
|
|
const r = await this.send("GET", path, null, true, true);
|
|
return new AttachmentResponse(r);
|
|
}
|
|
|
|
async postCipherAttachment(
|
|
id: string,
|
|
request: AttachmentRequest
|
|
): Promise<AttachmentUploadDataResponse> {
|
|
const r = await this.send("POST", "/ciphers/" + id + "/attachment/v2", request, true, true);
|
|
return new AttachmentUploadDataResponse(r);
|
|
}
|
|
|
|
/**
|
|
* @deprecated Mar 25 2021: This method has been deprecated in favor of direct uploads.
|
|
* This method still exists for backward compatibility with old server versions.
|
|
*/
|
|
async postCipherAttachmentLegacy(id: string, data: FormData): Promise<CipherResponse> {
|
|
const r = await this.send("POST", "/ciphers/" + id + "/attachment", data, true, true);
|
|
return new CipherResponse(r);
|
|
}
|
|
|
|
/**
|
|
* @deprecated Mar 25 2021: This method has been deprecated in favor of direct uploads.
|
|
* This method still exists for backward compatibility with old server versions.
|
|
*/
|
|
async postCipherAttachmentAdminLegacy(id: string, data: FormData): Promise<CipherResponse> {
|
|
const r = await this.send("POST", "/ciphers/" + id + "/attachment-admin", data, true, true);
|
|
return new CipherResponse(r);
|
|
}
|
|
|
|
deleteCipherAttachment(id: string, attachmentId: string): Promise<any> {
|
|
return this.send("DELETE", "/ciphers/" + id + "/attachment/" + attachmentId, null, true, false);
|
|
}
|
|
|
|
deleteCipherAttachmentAdmin(id: string, attachmentId: string): Promise<any> {
|
|
return this.send(
|
|
"DELETE",
|
|
"/ciphers/" + id + "/attachment/" + attachmentId + "/admin",
|
|
null,
|
|
true,
|
|
false
|
|
);
|
|
}
|
|
|
|
postShareCipherAttachment(
|
|
id: string,
|
|
attachmentId: string,
|
|
data: FormData,
|
|
organizationId: string
|
|
): Promise<any> {
|
|
return this.send(
|
|
"POST",
|
|
"/ciphers/" + id + "/attachment/" + attachmentId + "/share?organizationId=" + organizationId,
|
|
data,
|
|
true,
|
|
false
|
|
);
|
|
}
|
|
|
|
async renewAttachmentUploadUrl(
|
|
id: string,
|
|
attachmentId: string
|
|
): Promise<AttachmentUploadDataResponse> {
|
|
const r = await this.send(
|
|
"GET",
|
|
"/ciphers/" + id + "/attachment/" + attachmentId + "/renew",
|
|
null,
|
|
true,
|
|
true
|
|
);
|
|
return new AttachmentUploadDataResponse(r);
|
|
}
|
|
|
|
postAttachmentFile(id: string, attachmentId: string, data: FormData): Promise<any> {
|
|
return this.send("POST", "/ciphers/" + id + "/attachment/" + attachmentId, data, true, false);
|
|
}
|
|
|
|
// Collections APIs
|
|
|
|
async getCollectionDetails(
|
|
organizationId: string,
|
|
id: string
|
|
): Promise<CollectionGroupDetailsResponse> {
|
|
const r = await this.send(
|
|
"GET",
|
|
"/organizations/" + organizationId + "/collections/" + id + "/details",
|
|
null,
|
|
true,
|
|
true
|
|
);
|
|
return new CollectionGroupDetailsResponse(r);
|
|
}
|
|
|
|
async getUserCollections(): Promise<ListResponse<CollectionResponse>> {
|
|
const r = await this.send("GET", "/collections", null, true, true);
|
|
return new ListResponse(r, CollectionResponse);
|
|
}
|
|
|
|
async getCollections(organizationId: string): Promise<ListResponse<CollectionResponse>> {
|
|
const r = await this.send(
|
|
"GET",
|
|
"/organizations/" + organizationId + "/collections",
|
|
null,
|
|
true,
|
|
true
|
|
);
|
|
return new ListResponse(r, CollectionResponse);
|
|
}
|
|
|
|
async getCollectionUsers(
|
|
organizationId: string,
|
|
id: string
|
|
): Promise<SelectionReadOnlyResponse[]> {
|
|
const r = await this.send(
|
|
"GET",
|
|
"/organizations/" + organizationId + "/collections/" + id + "/users",
|
|
null,
|
|
true,
|
|
true
|
|
);
|
|
return r.map((dr: any) => new SelectionReadOnlyResponse(dr));
|
|
}
|
|
|
|
async postCollection(
|
|
organizationId: string,
|
|
request: CollectionRequest
|
|
): Promise<CollectionResponse> {
|
|
const r = await this.send(
|
|
"POST",
|
|
"/organizations/" + organizationId + "/collections",
|
|
request,
|
|
true,
|
|
true
|
|
);
|
|
return new CollectionResponse(r);
|
|
}
|
|
|
|
async putCollection(
|
|
organizationId: string,
|
|
id: string,
|
|
request: CollectionRequest
|
|
): Promise<CollectionResponse> {
|
|
const r = await this.send(
|
|
"PUT",
|
|
"/organizations/" + organizationId + "/collections/" + id,
|
|
request,
|
|
true,
|
|
true
|
|
);
|
|
return new CollectionResponse(r);
|
|
}
|
|
|
|
async putCollectionUsers(
|
|
organizationId: string,
|
|
id: string,
|
|
request: SelectionReadOnlyRequest[]
|
|
): Promise<any> {
|
|
await this.send(
|
|
"PUT",
|
|
"/organizations/" + organizationId + "/collections/" + id + "/users",
|
|
request,
|
|
true,
|
|
false
|
|
);
|
|
}
|
|
|
|
deleteCollection(organizationId: string, id: string): Promise<any> {
|
|
return this.send(
|
|
"DELETE",
|
|
"/organizations/" + organizationId + "/collections/" + id,
|
|
null,
|
|
true,
|
|
false
|
|
);
|
|
}
|
|
|
|
deleteCollectionUser(
|
|
organizationId: string,
|
|
id: string,
|
|
organizationUserId: string
|
|
): Promise<any> {
|
|
return this.send(
|
|
"DELETE",
|
|
"/organizations/" + organizationId + "/collections/" + id + "/user/" + organizationUserId,
|
|
null,
|
|
true,
|
|
false
|
|
);
|
|
}
|
|
|
|
// Groups APIs
|
|
|
|
async getGroupDetails(organizationId: string, id: string): Promise<GroupDetailsResponse> {
|
|
const r = await this.send(
|
|
"GET",
|
|
"/organizations/" + organizationId + "/groups/" + id + "/details",
|
|
null,
|
|
true,
|
|
true
|
|
);
|
|
return new GroupDetailsResponse(r);
|
|
}
|
|
|
|
async getGroups(organizationId: string): Promise<ListResponse<GroupResponse>> {
|
|
const r = await this.send(
|
|
"GET",
|
|
"/organizations/" + organizationId + "/groups",
|
|
null,
|
|
true,
|
|
true
|
|
);
|
|
return new ListResponse(r, GroupResponse);
|
|
}
|
|
|
|
async getGroupUsers(organizationId: string, id: string): Promise<string[]> {
|
|
const r = await this.send(
|
|
"GET",
|
|
"/organizations/" + organizationId + "/groups/" + id + "/users",
|
|
null,
|
|
true,
|
|
true
|
|
);
|
|
return r;
|
|
}
|
|
|
|
async postGroup(organizationId: string, request: GroupRequest): Promise<GroupResponse> {
|
|
const r = await this.send(
|
|
"POST",
|
|
"/organizations/" + organizationId + "/groups",
|
|
request,
|
|
true,
|
|
true
|
|
);
|
|
return new GroupResponse(r);
|
|
}
|
|
|
|
async putGroup(
|
|
organizationId: string,
|
|
id: string,
|
|
request: GroupRequest
|
|
): Promise<GroupResponse> {
|
|
const r = await this.send(
|
|
"PUT",
|
|
"/organizations/" + organizationId + "/groups/" + id,
|
|
request,
|
|
true,
|
|
true
|
|
);
|
|
return new GroupResponse(r);
|
|
}
|
|
|
|
async putGroupUsers(organizationId: string, id: string, request: string[]): Promise<any> {
|
|
await this.send(
|
|
"PUT",
|
|
"/organizations/" + organizationId + "/groups/" + id + "/users",
|
|
request,
|
|
true,
|
|
false
|
|
);
|
|
}
|
|
|
|
deleteGroup(organizationId: string, id: string): Promise<any> {
|
|
return this.send(
|
|
"DELETE",
|
|
"/organizations/" + organizationId + "/groups/" + id,
|
|
null,
|
|
true,
|
|
false
|
|
);
|
|
}
|
|
|
|
deleteGroupUser(organizationId: string, id: string, organizationUserId: string): Promise<any> {
|
|
return this.send(
|
|
"DELETE",
|
|
"/organizations/" + organizationId + "/groups/" + id + "/user/" + organizationUserId,
|
|
null,
|
|
true,
|
|
false
|
|
);
|
|
}
|
|
|
|
// Organization User APIs
|
|
|
|
async getOrganizationUser(
|
|
organizationId: string,
|
|
id: string
|
|
): Promise<OrganizationUserDetailsResponse> {
|
|
const r = await this.send(
|
|
"GET",
|
|
"/organizations/" + organizationId + "/users/" + id,
|
|
null,
|
|
true,
|
|
true
|
|
);
|
|
return new OrganizationUserDetailsResponse(r);
|
|
}
|
|
|
|
async getOrganizationUserGroups(organizationId: string, id: string): Promise<string[]> {
|
|
const r = await this.send(
|
|
"GET",
|
|
"/organizations/" + organizationId + "/users/" + id + "/groups",
|
|
null,
|
|
true,
|
|
true
|
|
);
|
|
return r;
|
|
}
|
|
|
|
async getOrganizationUsers(
|
|
organizationId: string
|
|
): Promise<ListResponse<OrganizationUserUserDetailsResponse>> {
|
|
const r = await this.send(
|
|
"GET",
|
|
"/organizations/" + organizationId + "/users",
|
|
null,
|
|
true,
|
|
true
|
|
);
|
|
return new ListResponse(r, OrganizationUserUserDetailsResponse);
|
|
}
|
|
|
|
async getOrganizationUserResetPasswordDetails(
|
|
organizationId: string,
|
|
id: string
|
|
): Promise<OrganizationUserResetPasswordDetailsReponse> {
|
|
const r = await this.send(
|
|
"GET",
|
|
"/organizations/" + organizationId + "/users/" + id + "/reset-password-details",
|
|
null,
|
|
true,
|
|
true
|
|
);
|
|
return new OrganizationUserResetPasswordDetailsReponse(r);
|
|
}
|
|
|
|
postOrganizationUserInvite(
|
|
organizationId: string,
|
|
request: OrganizationUserInviteRequest
|
|
): Promise<any> {
|
|
return this.send(
|
|
"POST",
|
|
"/organizations/" + organizationId + "/users/invite",
|
|
request,
|
|
true,
|
|
false
|
|
);
|
|
}
|
|
|
|
postOrganizationUserReinvite(organizationId: string, id: string): Promise<any> {
|
|
return this.send(
|
|
"POST",
|
|
"/organizations/" + organizationId + "/users/" + id + "/reinvite",
|
|
null,
|
|
true,
|
|
false
|
|
);
|
|
}
|
|
|
|
async postManyOrganizationUserReinvite(
|
|
organizationId: string,
|
|
request: OrganizationUserBulkRequest
|
|
): Promise<ListResponse<OrganizationUserBulkResponse>> {
|
|
const r = await this.send(
|
|
"POST",
|
|
"/organizations/" + organizationId + "/users/reinvite",
|
|
request,
|
|
true,
|
|
true
|
|
);
|
|
return new ListResponse(r, OrganizationUserBulkResponse);
|
|
}
|
|
|
|
postOrganizationUserAccept(
|
|
organizationId: string,
|
|
id: string,
|
|
request: OrganizationUserAcceptRequest
|
|
): Promise<any> {
|
|
return this.send(
|
|
"POST",
|
|
"/organizations/" + organizationId + "/users/" + id + "/accept",
|
|
request,
|
|
true,
|
|
false
|
|
);
|
|
}
|
|
|
|
postOrganizationUserConfirm(
|
|
organizationId: string,
|
|
id: string,
|
|
request: OrganizationUserConfirmRequest
|
|
): Promise<any> {
|
|
return this.send(
|
|
"POST",
|
|
"/organizations/" + organizationId + "/users/" + id + "/confirm",
|
|
request,
|
|
true,
|
|
false
|
|
);
|
|
}
|
|
|
|
async postOrganizationUsersPublicKey(
|
|
organizationId: string,
|
|
request: OrganizationUserBulkRequest
|
|
): Promise<ListResponse<OrganizationUserBulkPublicKeyResponse>> {
|
|
const r = await this.send(
|
|
"POST",
|
|
"/organizations/" + organizationId + "/users/public-keys",
|
|
request,
|
|
true,
|
|
true
|
|
);
|
|
return new ListResponse(r, OrganizationUserBulkPublicKeyResponse);
|
|
}
|
|
|
|
async postOrganizationUserBulkConfirm(
|
|
organizationId: string,
|
|
request: OrganizationUserBulkConfirmRequest
|
|
): Promise<ListResponse<OrganizationUserBulkResponse>> {
|
|
const r = await this.send(
|
|
"POST",
|
|
"/organizations/" + organizationId + "/users/confirm",
|
|
request,
|
|
true,
|
|
true
|
|
);
|
|
return new ListResponse(r, OrganizationUserBulkResponse);
|
|
}
|
|
|
|
putOrganizationUser(
|
|
organizationId: string,
|
|
id: string,
|
|
request: OrganizationUserUpdateRequest
|
|
): Promise<any> {
|
|
return this.send(
|
|
"PUT",
|
|
"/organizations/" + organizationId + "/users/" + id,
|
|
request,
|
|
true,
|
|
false
|
|
);
|
|
}
|
|
|
|
putOrganizationUserGroups(
|
|
organizationId: string,
|
|
id: string,
|
|
request: OrganizationUserUpdateGroupsRequest
|
|
): Promise<any> {
|
|
return this.send(
|
|
"PUT",
|
|
"/organizations/" + organizationId + "/users/" + id + "/groups",
|
|
request,
|
|
true,
|
|
false
|
|
);
|
|
}
|
|
|
|
putOrganizationUserResetPasswordEnrollment(
|
|
organizationId: string,
|
|
userId: string,
|
|
request: OrganizationUserResetPasswordEnrollmentRequest
|
|
): Promise<void> {
|
|
return this.send(
|
|
"PUT",
|
|
"/organizations/" + organizationId + "/users/" + userId + "/reset-password-enrollment",
|
|
request,
|
|
true,
|
|
false
|
|
);
|
|
}
|
|
|
|
putOrganizationUserResetPassword(
|
|
organizationId: string,
|
|
id: string,
|
|
request: OrganizationUserResetPasswordRequest
|
|
): Promise<any> {
|
|
return this.send(
|
|
"PUT",
|
|
"/organizations/" + organizationId + "/users/" + id + "/reset-password",
|
|
request,
|
|
true,
|
|
false
|
|
);
|
|
}
|
|
|
|
deleteOrganizationUser(organizationId: string, id: string): Promise<any> {
|
|
return this.send(
|
|
"DELETE",
|
|
"/organizations/" + organizationId + "/users/" + id,
|
|
null,
|
|
true,
|
|
false
|
|
);
|
|
}
|
|
|
|
async deleteManyOrganizationUsers(
|
|
organizationId: string,
|
|
request: OrganizationUserBulkRequest
|
|
): Promise<ListResponse<OrganizationUserBulkResponse>> {
|
|
const r = await this.send(
|
|
"DELETE",
|
|
"/organizations/" + organizationId + "/users",
|
|
request,
|
|
true,
|
|
true
|
|
);
|
|
return new ListResponse(r, OrganizationUserBulkResponse);
|
|
}
|
|
|
|
revokeOrganizationUser(organizationId: string, id: string): Promise<any> {
|
|
return this.send(
|
|
"PUT",
|
|
"/organizations/" + organizationId + "/users/" + id + "/revoke",
|
|
null,
|
|
true,
|
|
false
|
|
);
|
|
}
|
|
|
|
async revokeManyOrganizationUsers(
|
|
organizationId: string,
|
|
request: OrganizationUserBulkRequest
|
|
): Promise<ListResponse<OrganizationUserBulkResponse>> {
|
|
const r = await this.send(
|
|
"PUT",
|
|
"/organizations/" + organizationId + "/users/revoke",
|
|
request,
|
|
true,
|
|
true
|
|
);
|
|
return new ListResponse(r, OrganizationUserBulkResponse);
|
|
}
|
|
|
|
restoreOrganizationUser(organizationId: string, id: string): Promise<any> {
|
|
return this.send(
|
|
"PUT",
|
|
"/organizations/" + organizationId + "/users/" + id + "/restore",
|
|
null,
|
|
true,
|
|
false
|
|
);
|
|
}
|
|
|
|
async restoreManyOrganizationUsers(
|
|
organizationId: string,
|
|
request: OrganizationUserBulkRequest
|
|
): Promise<ListResponse<OrganizationUserBulkResponse>> {
|
|
const r = await this.send(
|
|
"PUT",
|
|
"/organizations/" + organizationId + "/users/restore",
|
|
request,
|
|
true,
|
|
true
|
|
);
|
|
return new ListResponse(r, OrganizationUserBulkResponse);
|
|
}
|
|
|
|
// Plan APIs
|
|
|
|
async getPlans(): Promise<ListResponse<PlanResponse>> {
|
|
const r = await this.send("GET", "/plans/", null, false, true);
|
|
return new ListResponse(r, PlanResponse);
|
|
}
|
|
|
|
async postPublicImportDirectory(request: OrganizationImportRequest): Promise<any> {
|
|
return this.send("POST", "/public/organization/import", request, true, false);
|
|
}
|
|
|
|
async getTaxRates(): Promise<ListResponse<TaxRateResponse>> {
|
|
const r = await this.send("GET", "/plans/sales-tax-rates/", null, true, true);
|
|
return new ListResponse(r, TaxRateResponse);
|
|
}
|
|
|
|
// Settings APIs
|
|
|
|
async getSettingsDomains(): Promise<DomainsResponse> {
|
|
const r = await this.send("GET", "/settings/domains", null, true, true);
|
|
return new DomainsResponse(r);
|
|
}
|
|
|
|
async putSettingsDomains(request: UpdateDomainsRequest): Promise<DomainsResponse> {
|
|
const r = await this.send("PUT", "/settings/domains", request, true, true);
|
|
return new DomainsResponse(r);
|
|
}
|
|
|
|
// Sync APIs
|
|
|
|
async getSync(): Promise<SyncResponse> {
|
|
const path = this.isDesktopClient || this.isWebClient ? "/sync?excludeDomains=true" : "/sync";
|
|
const r = await this.send("GET", path, null, true, true);
|
|
return new SyncResponse(r);
|
|
}
|
|
|
|
// Two-factor APIs
|
|
|
|
async getTwoFactorProviders(): Promise<ListResponse<TwoFactorProviderResponse>> {
|
|
const r = await this.send("GET", "/two-factor", null, true, true);
|
|
return new ListResponse(r, TwoFactorProviderResponse);
|
|
}
|
|
|
|
async getTwoFactorOrganizationProviders(
|
|
organizationId: string
|
|
): Promise<ListResponse<TwoFactorProviderResponse>> {
|
|
const r = await this.send(
|
|
"GET",
|
|
"/organizations/" + organizationId + "/two-factor",
|
|
null,
|
|
true,
|
|
true
|
|
);
|
|
return new ListResponse(r, TwoFactorProviderResponse);
|
|
}
|
|
|
|
async getTwoFactorAuthenticator(
|
|
request: SecretVerificationRequest
|
|
): Promise<TwoFactorAuthenticatorResponse> {
|
|
const r = await this.send("POST", "/two-factor/get-authenticator", request, true, true);
|
|
return new TwoFactorAuthenticatorResponse(r);
|
|
}
|
|
|
|
async getTwoFactorEmail(request: SecretVerificationRequest): Promise<TwoFactorEmailResponse> {
|
|
const r = await this.send("POST", "/two-factor/get-email", request, true, true);
|
|
return new TwoFactorEmailResponse(r);
|
|
}
|
|
|
|
async getTwoFactorDuo(request: SecretVerificationRequest): Promise<TwoFactorDuoResponse> {
|
|
const r = await this.send("POST", "/two-factor/get-duo", request, true, true);
|
|
return new TwoFactorDuoResponse(r);
|
|
}
|
|
|
|
async getTwoFactorOrganizationDuo(
|
|
organizationId: string,
|
|
request: SecretVerificationRequest
|
|
): Promise<TwoFactorDuoResponse> {
|
|
const r = await this.send(
|
|
"POST",
|
|
"/organizations/" + organizationId + "/two-factor/get-duo",
|
|
request,
|
|
true,
|
|
true
|
|
);
|
|
return new TwoFactorDuoResponse(r);
|
|
}
|
|
|
|
async getTwoFactorYubiKey(request: SecretVerificationRequest): Promise<TwoFactorYubiKeyResponse> {
|
|
const r = await this.send("POST", "/two-factor/get-yubikey", request, true, true);
|
|
return new TwoFactorYubiKeyResponse(r);
|
|
}
|
|
|
|
async getTwoFactorWebAuthn(
|
|
request: SecretVerificationRequest
|
|
): Promise<TwoFactorWebAuthnResponse> {
|
|
const r = await this.send("POST", "/two-factor/get-webauthn", request, true, true);
|
|
return new TwoFactorWebAuthnResponse(r);
|
|
}
|
|
|
|
async getTwoFactorWebAuthnChallenge(
|
|
request: SecretVerificationRequest
|
|
): Promise<ChallengeResponse> {
|
|
const r = await this.send("POST", "/two-factor/get-webauthn-challenge", request, true, true);
|
|
return new ChallengeResponse(r);
|
|
}
|
|
|
|
async getTwoFactorRecover(request: SecretVerificationRequest): Promise<TwoFactorRecoverResponse> {
|
|
const r = await this.send("POST", "/two-factor/get-recover", request, true, true);
|
|
return new TwoFactorRecoverResponse(r);
|
|
}
|
|
|
|
async putTwoFactorAuthenticator(
|
|
request: UpdateTwoFactorAuthenticatorRequest
|
|
): Promise<TwoFactorAuthenticatorResponse> {
|
|
const r = await this.send("PUT", "/two-factor/authenticator", request, true, true);
|
|
return new TwoFactorAuthenticatorResponse(r);
|
|
}
|
|
|
|
async putTwoFactorEmail(request: UpdateTwoFactorEmailRequest): Promise<TwoFactorEmailResponse> {
|
|
const r = await this.send("PUT", "/two-factor/email", request, true, true);
|
|
return new TwoFactorEmailResponse(r);
|
|
}
|
|
|
|
async putTwoFactorDuo(request: UpdateTwoFactorDuoRequest): Promise<TwoFactorDuoResponse> {
|
|
const r = await this.send("PUT", "/two-factor/duo", request, true, true);
|
|
return new TwoFactorDuoResponse(r);
|
|
}
|
|
|
|
async putTwoFactorOrganizationDuo(
|
|
organizationId: string,
|
|
request: UpdateTwoFactorDuoRequest
|
|
): Promise<TwoFactorDuoResponse> {
|
|
const r = await this.send(
|
|
"PUT",
|
|
"/organizations/" + organizationId + "/two-factor/duo",
|
|
request,
|
|
true,
|
|
true
|
|
);
|
|
return new TwoFactorDuoResponse(r);
|
|
}
|
|
|
|
async putTwoFactorYubiKey(
|
|
request: UpdateTwoFactorYubioOtpRequest
|
|
): Promise<TwoFactorYubiKeyResponse> {
|
|
const r = await this.send("PUT", "/two-factor/yubikey", request, true, true);
|
|
return new TwoFactorYubiKeyResponse(r);
|
|
}
|
|
|
|
async putTwoFactorWebAuthn(
|
|
request: UpdateTwoFactorWebAuthnRequest
|
|
): Promise<TwoFactorWebAuthnResponse> {
|
|
const response = request.deviceResponse.response as AuthenticatorAttestationResponse;
|
|
const data: any = Object.assign({}, request);
|
|
|
|
data.deviceResponse = {
|
|
id: request.deviceResponse.id,
|
|
rawId: btoa(request.deviceResponse.id),
|
|
type: request.deviceResponse.type,
|
|
extensions: request.deviceResponse.getClientExtensionResults(),
|
|
response: {
|
|
AttestationObject: Utils.fromBufferToB64(response.attestationObject),
|
|
clientDataJson: Utils.fromBufferToB64(response.clientDataJSON),
|
|
},
|
|
};
|
|
|
|
const r = await this.send("PUT", "/two-factor/webauthn", data, true, true);
|
|
return new TwoFactorWebAuthnResponse(r);
|
|
}
|
|
|
|
async deleteTwoFactorWebAuthn(
|
|
request: UpdateTwoFactorWebAuthnDeleteRequest
|
|
): Promise<TwoFactorWebAuthnResponse> {
|
|
const r = await this.send("DELETE", "/two-factor/webauthn", request, true, true);
|
|
return new TwoFactorWebAuthnResponse(r);
|
|
}
|
|
|
|
async putTwoFactorDisable(request: TwoFactorProviderRequest): Promise<TwoFactorProviderResponse> {
|
|
const r = await this.send("PUT", "/two-factor/disable", request, true, true);
|
|
return new TwoFactorProviderResponse(r);
|
|
}
|
|
|
|
async putTwoFactorOrganizationDisable(
|
|
organizationId: string,
|
|
request: TwoFactorProviderRequest
|
|
): Promise<TwoFactorProviderResponse> {
|
|
const r = await this.send(
|
|
"PUT",
|
|
"/organizations/" + organizationId + "/two-factor/disable",
|
|
request,
|
|
true,
|
|
true
|
|
);
|
|
return new TwoFactorProviderResponse(r);
|
|
}
|
|
|
|
postTwoFactorRecover(request: TwoFactorRecoveryRequest): Promise<any> {
|
|
return this.send("POST", "/two-factor/recover", request, false, false);
|
|
}
|
|
|
|
postTwoFactorEmailSetup(request: TwoFactorEmailRequest): Promise<any> {
|
|
return this.send("POST", "/two-factor/send-email", request, true, false);
|
|
}
|
|
|
|
postTwoFactorEmail(request: TwoFactorEmailRequest): Promise<any> {
|
|
return this.send("POST", "/two-factor/send-email-login", request, false, false);
|
|
}
|
|
|
|
async getDeviceVerificationSettings(): Promise<DeviceVerificationResponse> {
|
|
const r = await this.send(
|
|
"GET",
|
|
"/two-factor/get-device-verification-settings",
|
|
null,
|
|
true,
|
|
true
|
|
);
|
|
return new DeviceVerificationResponse(r);
|
|
}
|
|
|
|
async putDeviceVerificationSettings(
|
|
request: DeviceVerificationRequest
|
|
): Promise<DeviceVerificationResponse> {
|
|
const r = await this.send(
|
|
"PUT",
|
|
"/two-factor/device-verification-settings",
|
|
request,
|
|
true,
|
|
true
|
|
);
|
|
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>> {
|
|
const r = await this.send("GET", "/emergency-access/trusted", null, true, true);
|
|
return new ListResponse(r, EmergencyAccessGranteeDetailsResponse);
|
|
}
|
|
|
|
async getEmergencyAccessGranted(): Promise<ListResponse<EmergencyAccessGrantorDetailsResponse>> {
|
|
const r = await this.send("GET", "/emergency-access/granted", null, true, true);
|
|
return new ListResponse(r, EmergencyAccessGrantorDetailsResponse);
|
|
}
|
|
|
|
async getEmergencyAccess(id: string): Promise<EmergencyAccessGranteeDetailsResponse> {
|
|
const r = await this.send("GET", "/emergency-access/" + id, null, true, true);
|
|
return new EmergencyAccessGranteeDetailsResponse(r);
|
|
}
|
|
|
|
async getEmergencyGrantorPolicies(id: string): Promise<ListResponse<PolicyResponse>> {
|
|
const r = await this.send("GET", "/emergency-access/" + id + "/policies", null, true, true);
|
|
return new ListResponse(r, PolicyResponse);
|
|
}
|
|
|
|
putEmergencyAccess(id: string, request: EmergencyAccessUpdateRequest): Promise<any> {
|
|
return this.send("PUT", "/emergency-access/" + id, request, true, false);
|
|
}
|
|
|
|
deleteEmergencyAccess(id: string): Promise<any> {
|
|
return this.send("DELETE", "/emergency-access/" + id, null, true, false);
|
|
}
|
|
|
|
postEmergencyAccessInvite(request: EmergencyAccessInviteRequest): Promise<any> {
|
|
return this.send("POST", "/emergency-access/invite", request, true, false);
|
|
}
|
|
|
|
postEmergencyAccessReinvite(id: string): Promise<any> {
|
|
return this.send("POST", "/emergency-access/" + id + "/reinvite", null, true, false);
|
|
}
|
|
|
|
postEmergencyAccessAccept(id: string, request: EmergencyAccessAcceptRequest): Promise<any> {
|
|
return this.send("POST", "/emergency-access/" + id + "/accept", request, true, false);
|
|
}
|
|
|
|
postEmergencyAccessConfirm(id: string, request: EmergencyAccessConfirmRequest): Promise<any> {
|
|
return this.send("POST", "/emergency-access/" + id + "/confirm", request, true, false);
|
|
}
|
|
|
|
postEmergencyAccessInitiate(id: string): Promise<any> {
|
|
return this.send("POST", "/emergency-access/" + id + "/initiate", null, true, false);
|
|
}
|
|
|
|
postEmergencyAccessApprove(id: string): Promise<any> {
|
|
return this.send("POST", "/emergency-access/" + id + "/approve", null, true, false);
|
|
}
|
|
|
|
postEmergencyAccessReject(id: string): Promise<any> {
|
|
return this.send("POST", "/emergency-access/" + id + "/reject", null, true, false);
|
|
}
|
|
|
|
async postEmergencyAccessTakeover(id: string): Promise<EmergencyAccessTakeoverResponse> {
|
|
const r = await this.send("POST", "/emergency-access/" + id + "/takeover", null, true, true);
|
|
return new EmergencyAccessTakeoverResponse(r);
|
|
}
|
|
|
|
async postEmergencyAccessPassword(
|
|
id: string,
|
|
request: EmergencyAccessPasswordRequest
|
|
): Promise<any> {
|
|
await this.send("POST", "/emergency-access/" + id + "/password", request, true, true);
|
|
}
|
|
|
|
async postEmergencyAccessView(id: string): Promise<EmergencyAccessViewResponse> {
|
|
const r = await this.send("POST", "/emergency-access/" + id + "/view", null, true, true);
|
|
return new EmergencyAccessViewResponse(r);
|
|
}
|
|
|
|
// Organization APIs
|
|
|
|
async getCloudCommunicationsEnabled(): Promise<boolean> {
|
|
const r = await this.send("GET", "/organizations/connections/enabled", null, true, true);
|
|
return r as boolean;
|
|
}
|
|
|
|
async getOrganizationConnection<TConfig extends OrganizationConnectionConfigApis>(
|
|
id: string,
|
|
type: OrganizationConnectionType,
|
|
configType: { new (response: any): TConfig }
|
|
): Promise<OrganizationConnectionResponse<TConfig>> {
|
|
const r = await this.send("GET", `/organizations/connections/${id}/${type}`, null, true, true);
|
|
return new OrganizationConnectionResponse(r, configType);
|
|
}
|
|
|
|
async createOrganizationConnection<TConfig extends OrganizationConnectionConfigApis>(
|
|
request: OrganizationConnectionRequest,
|
|
configType: { new (response: any): TConfig }
|
|
): Promise<OrganizationConnectionResponse<TConfig>> {
|
|
const r = await this.send("POST", "/organizations/connections/", request, true, true);
|
|
return new OrganizationConnectionResponse(r, configType);
|
|
}
|
|
|
|
async updateOrganizationConnection<TConfig extends OrganizationConnectionConfigApis>(
|
|
request: OrganizationConnectionRequest,
|
|
configType: { new (response: any): TConfig },
|
|
organizationConnectionId?: string
|
|
): Promise<OrganizationConnectionResponse<TConfig>> {
|
|
const r = await this.send(
|
|
"PUT",
|
|
"/organizations/connections/" + organizationConnectionId,
|
|
request,
|
|
true,
|
|
true
|
|
);
|
|
return new OrganizationConnectionResponse(r, configType);
|
|
}
|
|
|
|
async deleteOrganizationConnection(id: string): Promise<void> {
|
|
return this.send("DELETE", "/organizations/connections/" + id, null, true, false);
|
|
}
|
|
|
|
// Provider APIs
|
|
|
|
async postProviderSetup(id: string, request: ProviderSetupRequest) {
|
|
const r = await this.send("POST", "/providers/" + id + "/setup", request, true, true);
|
|
return new ProviderResponse(r);
|
|
}
|
|
|
|
async getProvider(id: string) {
|
|
const r = await this.send("GET", "/providers/" + id, null, true, true);
|
|
return new ProviderResponse(r);
|
|
}
|
|
|
|
async putProvider(id: string, request: ProviderUpdateRequest) {
|
|
const r = await this.send("PUT", "/providers/" + id, request, true, true);
|
|
return new ProviderResponse(r);
|
|
}
|
|
|
|
// Provider User APIs
|
|
|
|
async getProviderUsers(
|
|
providerId: string
|
|
): Promise<ListResponse<ProviderUserUserDetailsResponse>> {
|
|
const r = await this.send("GET", "/providers/" + providerId + "/users", null, true, true);
|
|
return new ListResponse(r, ProviderUserUserDetailsResponse);
|
|
}
|
|
|
|
async getProviderUser(providerId: string, id: string): Promise<ProviderUserResponse> {
|
|
const r = await this.send("GET", "/providers/" + providerId + "/users/" + id, null, true, true);
|
|
return new ProviderUserResponse(r);
|
|
}
|
|
|
|
postProviderUserInvite(providerId: string, request: ProviderUserInviteRequest): Promise<any> {
|
|
return this.send("POST", "/providers/" + providerId + "/users/invite", request, true, false);
|
|
}
|
|
|
|
postProviderUserReinvite(providerId: string, id: string): Promise<any> {
|
|
return this.send(
|
|
"POST",
|
|
"/providers/" + providerId + "/users/" + id + "/reinvite",
|
|
null,
|
|
true,
|
|
false
|
|
);
|
|
}
|
|
|
|
async postManyProviderUserReinvite(
|
|
providerId: string,
|
|
request: ProviderUserBulkRequest
|
|
): Promise<ListResponse<ProviderUserBulkResponse>> {
|
|
const r = await this.send(
|
|
"POST",
|
|
"/providers/" + providerId + "/users/reinvite",
|
|
request,
|
|
true,
|
|
true
|
|
);
|
|
return new ListResponse(r, ProviderUserBulkResponse);
|
|
}
|
|
|
|
async postProviderUserBulkConfirm(
|
|
providerId: string,
|
|
request: ProviderUserBulkConfirmRequest
|
|
): Promise<ListResponse<ProviderUserBulkResponse>> {
|
|
const r = await this.send(
|
|
"POST",
|
|
"/providers/" + providerId + "/users/confirm",
|
|
request,
|
|
true,
|
|
true
|
|
);
|
|
return new ListResponse(r, ProviderUserBulkResponse);
|
|
}
|
|
|
|
async deleteManyProviderUsers(
|
|
providerId: string,
|
|
request: ProviderUserBulkRequest
|
|
): Promise<ListResponse<ProviderUserBulkResponse>> {
|
|
const r = await this.send("DELETE", "/providers/" + providerId + "/users", request, true, true);
|
|
return new ListResponse(r, ProviderUserBulkResponse);
|
|
}
|
|
|
|
postProviderUserAccept(
|
|
providerId: string,
|
|
id: string,
|
|
request: ProviderUserAcceptRequest
|
|
): Promise<any> {
|
|
return this.send(
|
|
"POST",
|
|
"/providers/" + providerId + "/users/" + id + "/accept",
|
|
request,
|
|
true,
|
|
false
|
|
);
|
|
}
|
|
|
|
postProviderUserConfirm(
|
|
providerId: string,
|
|
id: string,
|
|
request: ProviderUserConfirmRequest
|
|
): Promise<any> {
|
|
return this.send(
|
|
"POST",
|
|
"/providers/" + providerId + "/users/" + id + "/confirm",
|
|
request,
|
|
true,
|
|
false
|
|
);
|
|
}
|
|
|
|
async postProviderUsersPublicKey(
|
|
providerId: string,
|
|
request: ProviderUserBulkRequest
|
|
): Promise<ListResponse<ProviderUserBulkPublicKeyResponse>> {
|
|
const r = await this.send(
|
|
"POST",
|
|
"/providers/" + providerId + "/users/public-keys",
|
|
request,
|
|
true,
|
|
true
|
|
);
|
|
return new ListResponse(r, ProviderUserBulkPublicKeyResponse);
|
|
}
|
|
|
|
putProviderUser(
|
|
providerId: string,
|
|
id: string,
|
|
request: ProviderUserUpdateRequest
|
|
): Promise<any> {
|
|
return this.send("PUT", "/providers/" + providerId + "/users/" + id, request, true, false);
|
|
}
|
|
|
|
deleteProviderUser(providerId: string, id: string): Promise<any> {
|
|
return this.send("DELETE", "/providers/" + providerId + "/users/" + id, null, true, false);
|
|
}
|
|
|
|
// Provider Organization APIs
|
|
|
|
async getProviderClients(
|
|
providerId: string
|
|
): Promise<ListResponse<ProviderOrganizationOrganizationDetailsResponse>> {
|
|
const r = await this.send(
|
|
"GET",
|
|
"/providers/" + providerId + "/organizations",
|
|
null,
|
|
true,
|
|
true
|
|
);
|
|
return new ListResponse(r, ProviderOrganizationOrganizationDetailsResponse);
|
|
}
|
|
|
|
postProviderAddOrganization(
|
|
providerId: string,
|
|
request: ProviderAddOrganizationRequest
|
|
): Promise<any> {
|
|
return this.send(
|
|
"POST",
|
|
"/providers/" + providerId + "/organizations/add",
|
|
request,
|
|
true,
|
|
false
|
|
);
|
|
}
|
|
|
|
async postProviderCreateOrganization(
|
|
providerId: string,
|
|
request: ProviderOrganizationCreateRequest
|
|
): Promise<ProviderOrganizationResponse> {
|
|
const r = await this.send(
|
|
"POST",
|
|
"/providers/" + providerId + "/organizations",
|
|
request,
|
|
true,
|
|
true
|
|
);
|
|
return new ProviderOrganizationResponse(r);
|
|
}
|
|
|
|
deleteProviderOrganization(providerId: string, id: string): Promise<any> {
|
|
return this.send(
|
|
"DELETE",
|
|
"/providers/" + providerId + "/organizations/" + id,
|
|
null,
|
|
true,
|
|
false
|
|
);
|
|
}
|
|
|
|
// Event APIs
|
|
|
|
async getEvents(start: string, end: string, token: string): Promise<ListResponse<EventResponse>> {
|
|
const r = await this.send(
|
|
"GET",
|
|
this.addEventParameters("/events", start, end, token),
|
|
null,
|
|
true,
|
|
true
|
|
);
|
|
return new ListResponse(r, EventResponse);
|
|
}
|
|
|
|
async getEventsCipher(
|
|
id: string,
|
|
start: string,
|
|
end: string,
|
|
token: string
|
|
): Promise<ListResponse<EventResponse>> {
|
|
const r = await this.send(
|
|
"GET",
|
|
this.addEventParameters("/ciphers/" + id + "/events", start, end, token),
|
|
null,
|
|
true,
|
|
true
|
|
);
|
|
return new ListResponse(r, EventResponse);
|
|
}
|
|
|
|
async getEventsOrganization(
|
|
id: string,
|
|
start: string,
|
|
end: string,
|
|
token: string
|
|
): Promise<ListResponse<EventResponse>> {
|
|
const r = await this.send(
|
|
"GET",
|
|
this.addEventParameters("/organizations/" + id + "/events", start, end, token),
|
|
null,
|
|
true,
|
|
true
|
|
);
|
|
return new ListResponse(r, EventResponse);
|
|
}
|
|
|
|
async getEventsOrganizationUser(
|
|
organizationId: string,
|
|
id: string,
|
|
start: string,
|
|
end: string,
|
|
token: string
|
|
): Promise<ListResponse<EventResponse>> {
|
|
const r = await this.send(
|
|
"GET",
|
|
this.addEventParameters(
|
|
"/organizations/" + organizationId + "/users/" + id + "/events",
|
|
start,
|
|
end,
|
|
token
|
|
),
|
|
null,
|
|
true,
|
|
true
|
|
);
|
|
return new ListResponse(r, EventResponse);
|
|
}
|
|
|
|
async getEventsProvider(
|
|
id: string,
|
|
start: string,
|
|
end: string,
|
|
token: string
|
|
): Promise<ListResponse<EventResponse>> {
|
|
const r = await this.send(
|
|
"GET",
|
|
this.addEventParameters("/providers/" + id + "/events", start, end, token),
|
|
null,
|
|
true,
|
|
true
|
|
);
|
|
return new ListResponse(r, EventResponse);
|
|
}
|
|
|
|
async getEventsProviderUser(
|
|
providerId: string,
|
|
id: string,
|
|
start: string,
|
|
end: string,
|
|
token: string
|
|
): Promise<ListResponse<EventResponse>> {
|
|
const r = await this.send(
|
|
"GET",
|
|
this.addEventParameters(
|
|
"/providers/" + providerId + "/users/" + id + "/events",
|
|
start,
|
|
end,
|
|
token
|
|
),
|
|
null,
|
|
true,
|
|
true
|
|
);
|
|
return new ListResponse(r, EventResponse);
|
|
}
|
|
|
|
async postEventsCollect(request: EventRequest[]): Promise<any> {
|
|
const authHeader = await this.getActiveBearerToken();
|
|
const headers = new Headers({
|
|
"Device-Type": this.deviceType,
|
|
Authorization: "Bearer " + authHeader,
|
|
"Content-Type": "application/json; charset=utf-8",
|
|
});
|
|
if (this.customUserAgent != null) {
|
|
headers.set("User-Agent", this.customUserAgent);
|
|
}
|
|
const response = await this.fetch(
|
|
new Request(this.environmentService.getEventsUrl() + "/collect", {
|
|
cache: "no-store",
|
|
credentials: this.getCredentials(),
|
|
method: "POST",
|
|
body: JSON.stringify(request),
|
|
headers: headers,
|
|
})
|
|
);
|
|
if (response.status !== 200) {
|
|
return Promise.reject("Event post failed.");
|
|
}
|
|
}
|
|
|
|
// User APIs
|
|
|
|
async getUserPublicKey(id: string): Promise<UserKeyResponse> {
|
|
const r = await this.send("GET", "/users/" + id + "/public-key", null, true, true);
|
|
return new UserKeyResponse(r);
|
|
}
|
|
|
|
// HIBP APIs
|
|
|
|
async getHibpBreach(username: string): Promise<BreachAccountResponse[]> {
|
|
const r = await this.send("GET", "/hibp/breach?username=" + username, null, true, true);
|
|
return r.map((a: any) => new BreachAccountResponse(a));
|
|
}
|
|
|
|
// Misc
|
|
|
|
async postBitPayInvoice(request: BitPayInvoiceRequest): Promise<string> {
|
|
const r = await this.send("POST", "/bitpay-invoice", request, true, true);
|
|
return r as string;
|
|
}
|
|
|
|
async postSetupPayment(): Promise<string> {
|
|
const r = await this.send("POST", "/setup-payment", null, true, true);
|
|
return r as string;
|
|
}
|
|
|
|
// Key Connector
|
|
|
|
async getUserKeyFromKeyConnector(keyConnectorUrl: string): Promise<KeyConnectorUserKeyResponse> {
|
|
const authHeader = await this.getActiveBearerToken();
|
|
|
|
const response = await this.fetch(
|
|
new Request(keyConnectorUrl + "/user-keys", {
|
|
cache: "no-store",
|
|
method: "GET",
|
|
headers: new Headers({
|
|
Accept: "application/json",
|
|
Authorization: "Bearer " + authHeader,
|
|
}),
|
|
})
|
|
);
|
|
|
|
if (response.status !== 200) {
|
|
const error = await this.handleError(response, false, true);
|
|
return Promise.reject(error);
|
|
}
|
|
|
|
return new KeyConnectorUserKeyResponse(await response.json());
|
|
}
|
|
|
|
async postUserKeyToKeyConnector(
|
|
keyConnectorUrl: string,
|
|
request: KeyConnectorUserKeyRequest
|
|
): Promise<void> {
|
|
const authHeader = await this.getActiveBearerToken();
|
|
|
|
const response = await this.fetch(
|
|
new Request(keyConnectorUrl + "/user-keys", {
|
|
cache: "no-store",
|
|
method: "POST",
|
|
headers: new Headers({
|
|
Accept: "application/json",
|
|
Authorization: "Bearer " + authHeader,
|
|
"Content-Type": "application/json; charset=utf-8",
|
|
}),
|
|
body: JSON.stringify(request),
|
|
})
|
|
);
|
|
|
|
if (response.status !== 200) {
|
|
const error = await this.handleError(response, false, true);
|
|
return Promise.reject(error);
|
|
}
|
|
}
|
|
|
|
async getKeyConnectorAlive(keyConnectorUrl: string) {
|
|
const response = await this.fetch(
|
|
new Request(keyConnectorUrl + "/alive", {
|
|
cache: "no-store",
|
|
method: "GET",
|
|
headers: new Headers({
|
|
Accept: "application/json",
|
|
"Content-Type": "application/json; charset=utf-8",
|
|
}),
|
|
})
|
|
);
|
|
|
|
if (response.status !== 200) {
|
|
const error = await this.handleError(response, false, true);
|
|
return Promise.reject(error);
|
|
}
|
|
}
|
|
|
|
async getOrganizationExport(organizationId: string): Promise<OrganizationExportResponse> {
|
|
const r = await this.send(
|
|
"GET",
|
|
"/organizations/" + organizationId + "/export",
|
|
null,
|
|
true,
|
|
true
|
|
);
|
|
return new OrganizationExportResponse(r);
|
|
}
|
|
|
|
// Helpers
|
|
|
|
async getActiveBearerToken(): Promise<string> {
|
|
let accessToken = await this.tokenService.getToken();
|
|
if (await this.tokenService.tokenNeedsRefresh()) {
|
|
await this.doAuthRefresh();
|
|
accessToken = await this.tokenService.getToken();
|
|
}
|
|
return accessToken;
|
|
}
|
|
|
|
async fetch(request: Request): Promise<Response> {
|
|
if (request.method === "GET") {
|
|
request.headers.set("Cache-Control", "no-store");
|
|
request.headers.set("Pragma", "no-cache");
|
|
}
|
|
request.headers.set("Bitwarden-Client-Name", this.platformUtilsService.getClientType());
|
|
request.headers.set(
|
|
"Bitwarden-Client-Version",
|
|
await this.platformUtilsService.getApplicationVersion()
|
|
);
|
|
return this.nativeFetch(request);
|
|
}
|
|
|
|
nativeFetch(request: Request): Promise<Response> {
|
|
return fetch(request);
|
|
}
|
|
|
|
async preValidateSso(identifier: string): Promise<SsoPreValidateResponse> {
|
|
if (identifier == null || identifier === "") {
|
|
throw new Error("Organization Identifier was not provided.");
|
|
}
|
|
const headers = new Headers({
|
|
Accept: "application/json",
|
|
"Device-Type": this.deviceType,
|
|
});
|
|
if (this.customUserAgent != null) {
|
|
headers.set("User-Agent", this.customUserAgent);
|
|
}
|
|
|
|
const path = `/account/prevalidate?domainHint=${encodeURIComponent(identifier)}`;
|
|
const response = await this.fetch(
|
|
new Request(this.environmentService.getIdentityUrl() + path, {
|
|
cache: "no-store",
|
|
credentials: this.getCredentials(),
|
|
headers: headers,
|
|
method: "GET",
|
|
})
|
|
);
|
|
|
|
if (response.status === 200) {
|
|
const body = await response.json();
|
|
return new SsoPreValidateResponse(body);
|
|
} else {
|
|
const error = await this.handleError(response, false, true);
|
|
return Promise.reject(error);
|
|
}
|
|
}
|
|
|
|
async postCreateSponsorship(
|
|
sponsoredOrgId: string,
|
|
request: OrganizationSponsorshipCreateRequest
|
|
): Promise<void> {
|
|
return await this.send(
|
|
"POST",
|
|
"/organization/sponsorship/" +
|
|
(this.platformUtilsService.isSelfHost() ? "self-hosted/" : "") +
|
|
sponsoredOrgId +
|
|
"/families-for-enterprise",
|
|
request,
|
|
true,
|
|
false
|
|
);
|
|
}
|
|
|
|
async getSponsorshipSyncStatus(
|
|
sponsoredOrgId: string
|
|
): Promise<OrganizationSponsorshipSyncStatusResponse> {
|
|
const response = await this.send(
|
|
"GET",
|
|
"/organization/sponsorship/" + sponsoredOrgId + "/sync-status",
|
|
null,
|
|
true,
|
|
true
|
|
);
|
|
return new OrganizationSponsorshipSyncStatusResponse(response);
|
|
}
|
|
|
|
async deleteRevokeSponsorship(sponsoringOrganizationId: string): Promise<void> {
|
|
return await this.send(
|
|
"DELETE",
|
|
"/organization/sponsorship/" +
|
|
(this.platformUtilsService.isSelfHost() ? "self-hosted/" : "") +
|
|
sponsoringOrganizationId,
|
|
null,
|
|
true,
|
|
false
|
|
);
|
|
}
|
|
|
|
async deleteRemoveSponsorship(sponsoringOrgId: string): Promise<void> {
|
|
return await this.send(
|
|
"DELETE",
|
|
"/organization/sponsorship/sponsored/" + sponsoringOrgId,
|
|
null,
|
|
true,
|
|
false
|
|
);
|
|
}
|
|
|
|
async postPreValidateSponsorshipToken(sponsorshipToken: string): Promise<boolean> {
|
|
const r = await this.send(
|
|
"POST",
|
|
"/organization/sponsorship/validate-token?sponsorshipToken=" +
|
|
encodeURIComponent(sponsorshipToken),
|
|
null,
|
|
true,
|
|
true
|
|
);
|
|
return r as boolean;
|
|
}
|
|
|
|
async postRedeemSponsorship(
|
|
sponsorshipToken: string,
|
|
request: OrganizationSponsorshipRedeemRequest
|
|
): Promise<void> {
|
|
return await this.send(
|
|
"POST",
|
|
"/organization/sponsorship/redeem?sponsorshipToken=" + encodeURIComponent(sponsorshipToken),
|
|
request,
|
|
true,
|
|
false
|
|
);
|
|
}
|
|
|
|
async postResendSponsorshipOffer(sponsoringOrgId: string): Promise<void> {
|
|
return await this.send(
|
|
"POST",
|
|
"/organization/sponsorship/" + sponsoringOrgId + "/families-for-enterprise/resend",
|
|
null,
|
|
true,
|
|
false
|
|
);
|
|
}
|
|
|
|
protected async doAuthRefresh(): Promise<void> {
|
|
const refreshToken = await this.tokenService.getRefreshToken();
|
|
if (refreshToken != null && refreshToken !== "") {
|
|
return this.doRefreshToken();
|
|
}
|
|
|
|
const clientId = await this.tokenService.getClientId();
|
|
const clientSecret = await this.tokenService.getClientSecret();
|
|
if (!Utils.isNullOrWhitespace(clientId) && !Utils.isNullOrWhitespace(clientSecret)) {
|
|
return this.doApiTokenRefresh();
|
|
}
|
|
|
|
throw new Error("Cannot refresh token, no refresh token or api keys are stored");
|
|
}
|
|
|
|
protected async doRefreshToken(): Promise<void> {
|
|
const refreshToken = await this.tokenService.getRefreshToken();
|
|
if (refreshToken == null || refreshToken === "") {
|
|
throw new Error();
|
|
}
|
|
const headers = new Headers({
|
|
"Content-Type": "application/x-www-form-urlencoded; charset=utf-8",
|
|
Accept: "application/json",
|
|
"Device-Type": this.deviceType,
|
|
});
|
|
if (this.customUserAgent != null) {
|
|
headers.set("User-Agent", this.customUserAgent);
|
|
}
|
|
|
|
const decodedToken = await this.tokenService.decodeToken();
|
|
const response = await this.fetch(
|
|
new Request(this.environmentService.getIdentityUrl() + "/connect/token", {
|
|
body: this.qsStringify({
|
|
grant_type: "refresh_token",
|
|
client_id: decodedToken.client_id,
|
|
refresh_token: refreshToken,
|
|
}),
|
|
cache: "no-store",
|
|
credentials: this.getCredentials(),
|
|
headers: headers,
|
|
method: "POST",
|
|
})
|
|
);
|
|
|
|
if (response.status === 200) {
|
|
const responseJson = await response.json();
|
|
const tokenResponse = new IdentityTokenResponse(responseJson);
|
|
await this.tokenService.setTokens(
|
|
tokenResponse.accessToken,
|
|
tokenResponse.refreshToken,
|
|
null
|
|
);
|
|
} else {
|
|
const error = await this.handleError(response, true, true);
|
|
return Promise.reject(error);
|
|
}
|
|
}
|
|
|
|
protected async doApiTokenRefresh(): Promise<void> {
|
|
const clientId = await this.tokenService.getClientId();
|
|
const clientSecret = await this.tokenService.getClientSecret();
|
|
|
|
const appId = await this.appIdService.getAppId();
|
|
const deviceRequest = new DeviceRequest(appId, this.platformUtilsService);
|
|
|
|
const tokenRequest = new ApiTokenRequest(
|
|
clientId,
|
|
clientSecret,
|
|
new TokenTwoFactorRequest(),
|
|
deviceRequest
|
|
);
|
|
|
|
const response = await this.postIdentityToken(tokenRequest);
|
|
if (!(response instanceof IdentityTokenResponse)) {
|
|
throw new Error("Invalid response received when refreshing api token");
|
|
}
|
|
|
|
await this.tokenService.setToken(response.accessToken);
|
|
}
|
|
|
|
async send(
|
|
method: "GET" | "POST" | "PUT" | "DELETE",
|
|
path: string,
|
|
body: any,
|
|
authed: boolean,
|
|
hasResponse: boolean,
|
|
apiUrl?: string,
|
|
alterHeaders?: (headers: Headers) => void
|
|
): Promise<any> {
|
|
apiUrl = Utils.isNullOrWhitespace(apiUrl) ? this.environmentService.getApiUrl() : apiUrl;
|
|
|
|
const requestUrl = apiUrl + path;
|
|
// Prevent directory traversal from malicious paths
|
|
if (new URL(requestUrl).href !== requestUrl) {
|
|
return Promise.reject("Invalid request url path.");
|
|
}
|
|
|
|
const headers = new Headers({
|
|
"Device-Type": this.deviceType,
|
|
});
|
|
if (this.customUserAgent != null) {
|
|
headers.set("User-Agent", this.customUserAgent);
|
|
}
|
|
|
|
const requestInit: RequestInit = {
|
|
cache: "no-store",
|
|
credentials: this.getCredentials(),
|
|
method: method,
|
|
};
|
|
|
|
if (authed) {
|
|
const authHeader = await this.getActiveBearerToken();
|
|
headers.set("Authorization", "Bearer " + authHeader);
|
|
}
|
|
if (body != null) {
|
|
if (typeof body === "string") {
|
|
requestInit.body = body;
|
|
headers.set("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
|
|
} else if (typeof body === "object") {
|
|
if (body instanceof FormData) {
|
|
requestInit.body = body;
|
|
} else {
|
|
headers.set("Content-Type", "application/json; charset=utf-8");
|
|
requestInit.body = JSON.stringify(body);
|
|
}
|
|
}
|
|
}
|
|
if (hasResponse) {
|
|
headers.set("Accept", "application/json");
|
|
}
|
|
if (alterHeaders != null) {
|
|
alterHeaders(headers);
|
|
}
|
|
|
|
requestInit.headers = headers;
|
|
const response = await this.fetch(new Request(requestUrl, requestInit));
|
|
|
|
const responseType = response.headers.get("content-type");
|
|
const responseIsJson = responseType != null && responseType.indexOf("application/json") !== -1;
|
|
if (hasResponse && response.status === 200 && responseIsJson) {
|
|
const responseJson = await response.json();
|
|
return responseJson;
|
|
} else if (response.status !== 200) {
|
|
const error = await this.handleError(response, false, authed);
|
|
return Promise.reject(error);
|
|
}
|
|
}
|
|
|
|
private async handleError(
|
|
response: Response,
|
|
tokenError: boolean,
|
|
authed: boolean
|
|
): Promise<ErrorResponse> {
|
|
let responseJson: any = null;
|
|
if (this.isJsonResponse(response)) {
|
|
responseJson = await response.json();
|
|
} else if (this.isTextResponse(response)) {
|
|
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);
|
|
}
|
|
|
|
private qsStringify(params: any): string {
|
|
return Object.keys(params)
|
|
.map((key) => {
|
|
return encodeURIComponent(key) + "=" + encodeURIComponent(params[key]);
|
|
})
|
|
.join("&");
|
|
}
|
|
|
|
private getCredentials(): RequestCredentials {
|
|
if (!this.isWebClient || this.environmentService.hasBaseUrl()) {
|
|
return "include";
|
|
}
|
|
return undefined;
|
|
}
|
|
|
|
private addEventParameters(base: string, start: string, end: string, token: string) {
|
|
if (start != null) {
|
|
base += "?start=" + start;
|
|
}
|
|
if (end != null) {
|
|
base += base.indexOf("?") > -1 ? "&" : "?";
|
|
base += "end=" + end;
|
|
}
|
|
if (token != null) {
|
|
base += base.indexOf("?") > -1 ? "&" : "?";
|
|
base += "continuationToken=" + token;
|
|
}
|
|
return base;
|
|
}
|
|
|
|
private isJsonResponse(response: Response): boolean {
|
|
const typeHeader = response.headers.get("content-type");
|
|
return typeHeader != null && typeHeader.indexOf("application/json") > -1;
|
|
}
|
|
|
|
private isTextResponse(response: Response): boolean {
|
|
const typeHeader = response.headers.get("content-type");
|
|
return typeHeader != null && typeHeader.indexOf("text") > -1;
|
|
}
|
|
}
|