@antscorp/antsomi-ui 1.3.7-beta.7 → 1.3.7-beta.71
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +70 -0
- package/es/components/atoms/Input/Input.js +3 -1
- package/es/components/atoms/InputDynamic/InputDynamic.js +3 -3
- package/es/components/atoms/Tag/Tag.js +1 -1
- package/es/components/icons/LazyIcon/LazyIcon.d.ts +2 -0
- package/es/components/icons/LazyIcon/LazyIcon.js +2 -0
- package/es/components/icons/QRCodeManagementIcon.d.ts +3 -0
- package/es/components/icons/QRCodeManagementIcon.js +7 -0
- package/es/components/icons/QRSetDashboardIcon.d.ts +3 -0
- package/es/components/icons/QRSetDashboardIcon.js +7 -0
- package/es/components/icons/index.d.ts +2 -0
- package/es/components/icons/index.js +2 -0
- package/es/components/molecules/AddDynamicContent/AddDynamicContent.js +28 -2
- package/es/components/molecules/AddDynamicContent/components/DisplayFormat/DisplayFormat.d.ts +1 -0
- package/es/components/molecules/AddDynamicContent/constants.d.ts +2 -0
- package/es/components/molecules/AddDynamicContent/constants.js +2 -0
- package/es/components/molecules/ColorPicker/index.d.ts +2 -0
- package/es/components/molecules/ColorPicker/index.js +8 -3
- package/es/components/molecules/EmojiPopover/EmojiPopover.d.ts +1 -0
- package/es/components/molecules/EmojiPopover/EmojiPopover.js +2 -2
- package/es/components/molecules/EmojiPopover/styled.d.ts +2 -2
- package/es/components/molecules/EmojiPopover/styled.js +1 -1
- package/es/components/molecules/EmptyData/EmptyData.d.ts +1 -1
- package/es/components/molecules/EmptyData/EmptyData.js +4 -2
- package/es/components/molecules/HeaderV2/HeaderV2.d.ts +1 -1
- package/es/components/molecules/InputSearch/index.d.ts +1 -1
- package/es/components/molecules/InputSearch/index.js +2 -1
- package/es/components/molecules/Modal/Modal.js +7 -1
- package/es/components/molecules/ModalV2/ModalV2.js +2 -1
- package/es/components/molecules/SearchPopover/SearchPopover.js +2 -2
- package/es/components/molecules/SearchPopover/styled.d.ts +12 -1
- package/es/components/molecules/SearchPopover/styled.js +1 -2
- package/es/components/molecules/SearchPopover/types.d.ts +4 -3
- package/es/components/molecules/Select/Select.js +3 -3
- package/es/components/molecules/Select/styled.d.ts +3 -1
- package/es/components/molecules/Select/styled.js +50 -6
- package/es/components/molecules/ShareAccess/ShareAccess.d.ts +2 -1
- package/es/components/molecules/ShareAccess/ShareAccess.js +12 -9
- package/es/components/molecules/ShareAccess/components/LayoutContent/LayoutContent.js +5 -5
- package/es/components/molecules/ShareAccess/components/PeopleAccess/PeopleAccess.js +2 -2
- package/es/components/molecules/ShareAccess/hooks/useShareAccess.d.ts +2 -1
- package/es/components/molecules/ShareAccess/index.d.ts +1 -0
- package/es/components/molecules/ShareAccess/reducer.d.ts +1 -1
- package/es/components/molecules/ShareAccess/reducer.js +7 -4
- package/es/components/molecules/ShareAccess/types.d.ts +22 -0
- package/es/components/molecules/ShareAccess/utils.d.ts +3 -1
- package/es/components/molecules/ShareAccess/utils.js +35 -2
- package/es/components/molecules/TagifyInput/TagifyInput.js +48 -27
- package/es/components/molecules/TagifyInput/types.d.ts +14 -8
- package/es/components/molecules/TagifyInput/utils.d.ts +6 -1
- package/es/components/molecules/TagifyInput/utils.js +19 -0
- package/es/components/molecules/VirtualizedMenu/VirtualizedMenu.d.ts +1 -0
- package/es/components/molecules/VirtualizedMenu/components/Item/Item.js +3 -7
- package/es/components/molecules/VirtualizedMenu/components/MenuInline/MenuInline.d.ts +10 -10
- package/es/components/molecules/VirtualizedMenu/components/MenuInline/MenuInline.js +46 -327
- package/es/components/molecules/VirtualizedMenu/components/MenuInline/hooks/index.d.ts +9 -0
- package/es/components/molecules/VirtualizedMenu/components/MenuInline/hooks/index.js +5 -0
- package/es/components/molecules/VirtualizedMenu/components/MenuInline/hooks/useFocusManagement.d.ts +23 -0
- package/es/components/molecules/VirtualizedMenu/components/MenuInline/hooks/useFocusManagement.js +81 -0
- package/es/components/molecules/VirtualizedMenu/components/MenuInline/hooks/useItemInteraction.d.ts +24 -0
- package/es/components/molecules/VirtualizedMenu/components/MenuInline/hooks/useItemInteraction.js +32 -0
- package/es/components/molecules/VirtualizedMenu/components/MenuInline/hooks/useKeyboardNavigation.d.ts +26 -0
- package/es/components/molecules/VirtualizedMenu/components/MenuInline/hooks/useKeyboardNavigation.js +93 -0
- package/es/components/molecules/VirtualizedMenu/components/MenuInline/hooks/useTreeState.d.ts +24 -0
- package/es/components/molecules/VirtualizedMenu/components/MenuInline/hooks/useTreeState.js +94 -0
- package/es/components/molecules/VirtualizedMenu/components/MenuInline/hooks/useVisibleItems.d.ts +7 -0
- package/es/components/molecules/VirtualizedMenu/components/MenuInline/hooks/useVisibleItems.js +132 -0
- package/es/components/molecules/VirtualizedMenu/styled.js +14 -3
- package/es/components/molecules/VirtualizedMenu/types.d.ts +1 -0
- package/es/components/molecules/VirtualizedMenu/utils.d.ts +1 -0
- package/es/components/molecules/VirtualizedMenu/utils.js +1 -0
- package/es/components/molecules/index.d.ts +1 -0
- package/es/components/organism/AccountSharing/AccountSharing.d.ts +1 -0
- package/es/components/organism/AccountSharing/AccountSharing.js +17 -33
- package/es/components/organism/AccountSharing/styled.js +1 -1
- package/es/components/organism/ActivityTimeline/ActivityTimeline.js +3 -3
- package/es/components/organism/ActivityTimeline/constants.d.ts +9 -9
- package/es/components/organism/ActivityTimeline/constants.js +3 -3
- package/es/components/organism/ActivityTimeline/index.d.ts +530 -1
- package/es/components/organism/ActivityTimeline/index.js +9 -1
- package/es/components/organism/ActivityTimeline/utils.js +186 -15
- package/es/components/organism/LeftMenu/LeftMenu.js +6 -6
- package/es/components/organism/LeftMenu/hooks/usePermission.js +1 -1
- package/es/components/organism/LeftMenu/styled.js +2 -0
- package/es/components/organism/LeftMenu/types/index.d.ts +7 -0
- package/es/components/organism/LeftMenu/utils/index.js +1 -1
- package/es/components/organism/Login/Login.js +19 -36
- package/es/components/organism/Login/components/IconInfo/IconInfo.js +1 -1
- package/es/components/organism/Login/components/LoginSelectPortal/LoginSelectPortal.js +1 -1
- package/es/components/organism/Login/components/SignIn/SignIn.js +2 -2
- package/es/components/organism/Login/types/index.d.ts +2 -0
- package/es/components/organism/LoginV2/LoginV2.d.ts +3 -0
- package/es/components/organism/LoginV2/LoginV2.js +957 -0
- package/es/components/organism/LoginV2/components/Avatar/Avatar.d.ts +8 -0
- package/es/components/organism/LoginV2/components/Avatar/Avatar.js +11 -0
- package/es/components/organism/LoginV2/components/Avatar/index.d.ts +1 -0
- package/es/components/organism/LoginV2/components/Avatar/index.js +1 -0
- package/es/components/organism/LoginV2/components/ChooseMethod/ChooseMethod.d.ts +9 -0
- package/es/components/organism/LoginV2/components/ChooseMethod/ChooseMethod.js +54 -0
- package/es/components/organism/LoginV2/components/ChooseMethod/Method.d.ts +10 -0
- package/es/components/organism/LoginV2/components/ChooseMethod/Method.js +13 -0
- package/es/components/organism/LoginV2/components/ChooseMethod/index.d.ts +1 -0
- package/es/components/organism/LoginV2/components/ChooseMethod/index.js +1 -0
- package/es/components/organism/LoginV2/components/ChooseMethod/styled.d.ts +10 -0
- package/es/components/organism/LoginV2/components/ChooseMethod/styled.js +24 -0
- package/es/components/organism/LoginV2/components/ChooseMethod/utils.d.ts +1 -0
- package/es/components/organism/LoginV2/components/ChooseMethod/utils.js +1 -0
- package/es/components/organism/LoginV2/components/ForgotPassword/ForgotPassword.d.ts +14 -0
- package/es/components/organism/LoginV2/components/ForgotPassword/ForgotPassword.js +195 -0
- package/es/components/organism/LoginV2/components/ForgotPassword/index.d.ts +2 -0
- package/es/components/organism/LoginV2/components/ForgotPassword/index.js +2 -0
- package/es/components/organism/LoginV2/components/ForgotPassword/styled.d.ts +1 -0
- package/es/components/organism/LoginV2/components/ForgotPassword/styled.js +10 -0
- package/es/components/organism/LoginV2/components/IconInfo/IconInfo.d.ts +7 -0
- package/es/components/organism/LoginV2/components/IconInfo/IconInfo.js +18 -0
- package/es/components/organism/LoginV2/components/IconInfo/index.d.ts +1 -0
- package/es/components/organism/LoginV2/components/IconInfo/index.js +1 -0
- package/es/components/organism/LoginV2/components/LoginSelectPortal/Item/Item.d.ts +10 -0
- package/es/components/organism/LoginV2/components/LoginSelectPortal/Item/Item.js +12 -0
- package/es/components/organism/LoginV2/components/LoginSelectPortal/Item/index.d.ts +1 -0
- package/es/components/organism/LoginV2/components/LoginSelectPortal/Item/index.js +1 -0
- package/es/components/organism/LoginV2/components/LoginSelectPortal/Item/styled.d.ts +2 -0
- package/es/components/organism/LoginV2/components/LoginSelectPortal/Item/styled.js +34 -0
- package/es/components/organism/LoginV2/components/LoginSelectPortal/LoginSelectPortal.d.ts +19 -0
- package/es/components/organism/LoginV2/components/LoginSelectPortal/LoginSelectPortal.js +194 -0
- package/es/components/organism/LoginV2/components/LoginSelectPortal/index.d.ts +1 -0
- package/es/components/organism/LoginV2/components/LoginSelectPortal/index.js +1 -0
- package/es/components/organism/LoginV2/components/LoginSelectPortal/styled.d.ts +1 -0
- package/es/components/organism/LoginV2/components/LoginSelectPortal/styled.js +5 -0
- package/es/components/organism/LoginV2/components/LoginWithEmail/LoginWithEmail.d.ts +15 -0
- package/es/components/organism/LoginV2/components/LoginWithEmail/LoginWithEmail.js +211 -0
- package/es/components/organism/LoginV2/components/LoginWithEmail/index.d.ts +1 -0
- package/es/components/organism/LoginV2/components/LoginWithEmail/index.js +1 -0
- package/es/components/organism/LoginV2/components/LoginWithEmail/styled.d.ts +3 -0
- package/es/components/organism/LoginV2/components/LoginWithEmail/styled.js +5 -0
- package/es/components/organism/LoginV2/components/LoginWithGG/LoginWithGG.d.ts +14 -0
- package/es/components/organism/LoginV2/components/LoginWithGG/LoginWithGG.js +116 -0
- package/es/components/organism/LoginV2/components/LoginWithGG/index.d.ts +1 -0
- package/es/components/organism/LoginV2/components/LoginWithGG/index.js +1 -0
- package/es/components/organism/LoginV2/components/LoginWithGG/styled.d.ts +3 -0
- package/es/components/organism/LoginV2/components/LoginWithGG/styled.js +5 -0
- package/es/components/organism/LoginV2/components/Logo/Logo.d.ts +6 -0
- package/es/components/organism/LoginV2/components/Logo/Logo.js +9 -0
- package/es/components/organism/LoginV2/components/Logo/index.d.ts +1 -0
- package/es/components/organism/LoginV2/components/Logo/index.js +1 -0
- package/es/components/organism/LoginV2/components/OryConsent/OryAuthLayout.d.ts +9 -0
- package/es/components/organism/LoginV2/components/OryConsent/OryAuthLayout.js +4 -0
- package/es/components/organism/LoginV2/components/OryConsent/OryConsent.d.ts +17 -0
- package/es/components/organism/LoginV2/components/OryConsent/OryConsent.js +204 -0
- package/es/components/organism/LoginV2/components/OryConsent/OryThemeProvider.d.ts +8 -0
- package/es/components/organism/LoginV2/components/OryConsent/OryThemeProvider.js +10 -0
- package/es/components/organism/LoginV2/components/OryConsent/PortalSelect.d.ts +15 -0
- package/es/components/organism/LoginV2/components/OryConsent/PortalSelect.js +30 -0
- package/es/components/organism/LoginV2/components/OryConsent/ScopeConsent.d.ts +20 -0
- package/es/components/organism/LoginV2/components/OryConsent/ScopeConsent.js +29 -0
- package/es/components/organism/LoginV2/components/OryConsent/index.d.ts +2 -0
- package/es/components/organism/LoginV2/components/OryConsent/index.js +2 -0
- package/es/components/organism/LoginV2/components/OryConsent/styled.d.ts +31 -0
- package/es/components/organism/LoginV2/components/OryConsent/styled.js +292 -0
- package/es/components/organism/LoginV2/components/OrySignIn/OryFormShell.d.ts +9 -0
- package/es/components/organism/LoginV2/components/OrySignIn/OryFormShell.js +36 -0
- package/es/components/organism/LoginV2/components/OrySignIn/OryMfa.d.ts +11 -0
- package/es/components/organism/LoginV2/components/OrySignIn/OryMfa.js +144 -0
- package/es/components/organism/LoginV2/components/OrySignIn/OryRecovery.d.ts +9 -0
- package/es/components/organism/LoginV2/components/OrySignIn/OryRecovery.js +128 -0
- package/es/components/organism/LoginV2/components/OrySignIn/OryStatus.d.ts +17 -0
- package/es/components/organism/LoginV2/components/OrySignIn/OryStatus.js +33 -0
- package/es/components/organism/LoginV2/components/OrySignIn/index.d.ts +3 -0
- package/es/components/organism/LoginV2/components/OrySignIn/index.js +3 -0
- package/es/components/organism/LoginV2/components/SetupGGAuthenticator/SetupGGAuthenticator.d.ts +14 -0
- package/es/components/organism/LoginV2/components/SetupGGAuthenticator/SetupGGAuthenticator.js +100 -0
- package/es/components/organism/LoginV2/components/SetupGGAuthenticator/index.d.ts +2 -0
- package/es/components/organism/LoginV2/components/SetupGGAuthenticator/index.js +2 -0
- package/es/components/organism/LoginV2/components/SetupGGAuthenticator/styled.d.ts +4 -0
- package/es/components/organism/LoginV2/components/SetupGGAuthenticator/styled.js +10 -0
- package/es/components/organism/LoginV2/components/SignIn/SignIn.d.ts +22 -0
- package/es/components/organism/LoginV2/components/SignIn/SignIn.js +107 -0
- package/es/components/organism/LoginV2/components/SignIn/index.d.ts +1 -0
- package/es/components/organism/LoginV2/components/SignIn/index.js +1 -0
- package/es/components/organism/LoginV2/components/SignIn/styled.d.ts +3 -0
- package/es/components/organism/LoginV2/components/SignIn/styled.js +10 -0
- package/es/components/organism/LoginV2/components/VerifyAccount/VerifyAccount.d.ts +25 -0
- package/es/components/organism/LoginV2/components/VerifyAccount/VerifyAccount.js +42 -0
- package/es/components/organism/LoginV2/components/VerifyAccount/index.d.ts +1 -0
- package/es/components/organism/LoginV2/components/VerifyAccount/index.js +1 -0
- package/es/components/organism/LoginV2/components/VerifyAccount/styled.d.ts +22 -0
- package/es/components/organism/LoginV2/components/VerifyAccount/styled.js +17 -0
- package/es/components/organism/LoginV2/components/WidgetLayout/WidgetLayout.d.ts +13 -0
- package/es/components/organism/LoginV2/components/WidgetLayout/WidgetLayout.js +18 -0
- package/es/components/organism/LoginV2/components/WidgetLayout/index.d.ts +1 -0
- package/es/components/organism/LoginV2/components/WidgetLayout/index.js +1 -0
- package/es/components/organism/LoginV2/components/WidgetLayout/styled.d.ts +5 -0
- package/es/components/organism/LoginV2/components/WidgetLayout/styled.js +22 -0
- package/es/components/organism/LoginV2/components/index.d.ts +11 -0
- package/es/components/organism/LoginV2/components/index.js +11 -0
- package/es/components/organism/LoginV2/constants/index.d.ts +48 -0
- package/es/components/organism/LoginV2/constants/index.js +48 -0
- package/es/components/organism/LoginV2/hooks/index.d.ts +1 -0
- package/es/components/organism/LoginV2/hooks/index.js +1 -0
- package/es/components/organism/LoginV2/hooks/useResize.d.ts +7 -0
- package/es/components/organism/LoginV2/hooks/useResize.js +21 -0
- package/es/components/organism/LoginV2/index.d.ts +6 -0
- package/es/components/organism/LoginV2/index.js +4 -0
- package/es/components/organism/LoginV2/styled.d.ts +51 -0
- package/es/components/organism/LoginV2/styled.js +129 -0
- package/es/components/organism/LoginV2/types/index.d.ts +79 -0
- package/es/components/organism/LoginV2/types/index.js +1 -0
- package/es/components/organism/LoginV2/types/ory.d.ts +52 -0
- package/es/components/organism/LoginV2/types/ory.js +1 -0
- package/es/components/organism/LoginV2/utils/index.d.ts +14 -0
- package/es/components/organism/LoginV2/utils/index.js +49 -0
- package/es/components/organism/LoginV2/utils/ory.d.ts +138 -0
- package/es/components/organism/LoginV2/utils/ory.js +408 -0
- package/es/components/organism/LoginV2/utils/oryConsent.d.ts +52 -0
- package/es/components/organism/LoginV2/utils/oryConsent.js +174 -0
- package/es/components/organism/LoginV2/utils/oryFlows.d.ts +100 -0
- package/es/components/organism/LoginV2/utils/oryFlows.js +319 -0
- package/es/components/organism/TextEditor/TextEditor.d.ts +9 -2
- package/es/components/organism/TextEditor/TextEditor.js +203 -42
- package/es/components/organism/TextEditor/constants.d.ts +9 -0
- package/es/components/organism/TextEditor/constants.js +66 -0
- package/es/components/organism/TextEditor/extensions/BubbleMenu/bubble-menu-plugin.d.ts +6 -128
- package/es/components/organism/TextEditor/extensions/BubbleMenu/bubble-menu-plugin.js +7 -292
- package/es/components/organism/TextEditor/extensions/BubbleMenu/bubble-menu.d.ts +1 -1
- package/es/components/organism/TextEditor/extensions/BubbleMenu/bubble-menu.js +4 -0
- package/es/components/organism/TextEditor/extensions/Link.js +33 -14
- package/es/components/organism/TextEditor/extensions/ListItem.d.ts +10 -0
- package/es/components/organism/TextEditor/extensions/ListItem.js +93 -0
- package/es/components/organism/TextEditor/extensions/SmartTag.d.ts +5 -6
- package/es/components/organism/TextEditor/extensions/SmartTag.js +96 -4
- package/es/components/organism/TextEditor/hooks/useColorSet.js +7 -0
- package/es/components/organism/TextEditor/hooks/useMarkTracking.js +2 -1
- package/es/components/organism/TextEditor/index.d.ts +7 -5
- package/es/components/organism/TextEditor/index.scss +4 -7
- package/es/components/organism/TextEditor/provider.d.ts +1 -0
- package/es/components/organism/TextEditor/provider.js +6 -3
- package/es/components/organism/TextEditor/store.d.ts +11 -4
- package/es/components/organism/TextEditor/store.js +22 -2
- package/es/components/organism/TextEditor/stories/WithOldDynAndLink/froala-legacy-format.settings.json +95 -0
- package/es/components/organism/TextEditor/stories/WithOldDynAndLink/shared.d.ts +111 -0
- package/es/components/organism/TextEditor/stories/WithOldDynAndLink/shared.js +82 -0
- package/es/components/organism/TextEditor/stories/shared.d.ts +64 -0
- package/es/components/organism/TextEditor/stories/shared.js +57 -0
- package/es/components/organism/TextEditor/styled.d.ts +1 -1
- package/es/components/organism/TextEditor/styled.js +1 -0
- package/es/components/organism/TextEditor/types.d.ts +161 -11
- package/es/components/organism/TextEditor/types.js +1 -0
- package/es/components/organism/TextEditor/ui/BubbleMenu/BubbleMenu.d.ts +2 -1
- package/es/components/organism/TextEditor/ui/BubbleMenu/BubbleMenu.js +80 -51
- package/es/components/organism/TextEditor/ui/Emoji/EmojiList.js +1 -1
- package/es/components/organism/TextEditor/ui/Emoji/suggestion.d.ts +1 -1
- package/es/components/organism/TextEditor/ui/Emoji/suggestion.js +2 -2
- package/es/components/organism/TextEditor/ui/FontPopover/FontPopover.js +12 -2
- package/es/components/organism/TextEditor/ui/LinkInsertForm/LinkInsertForm.d.ts +16 -0
- package/es/components/organism/TextEditor/ui/LinkInsertForm/LinkInsertForm.js +61 -0
- package/es/components/organism/TextEditor/ui/LinkInsertForm/index.d.ts +2 -0
- package/es/components/organism/TextEditor/ui/LinkInsertForm/index.js +1 -0
- package/es/components/organism/TextEditor/ui/LinkPopover/LinkPopover.d.ts +9 -0
- package/es/components/organism/TextEditor/ui/LinkPopover/LinkPopover.js +126 -0
- package/es/components/organism/TextEditor/ui/LinkPopover/index.d.ts +2 -0
- package/es/components/organism/TextEditor/ui/LinkPopover/index.js +1 -0
- package/es/components/organism/TextEditor/ui/Popover/Popover.js +1 -1
- package/es/components/organism/TextEditor/ui/TextAlignSelect/TextAlignSelect.js +1 -3
- package/es/components/organism/TextEditor/ui/Toolbar/{Toolbar.d.ts → FormattingToolbar.d.ts} +3 -4
- package/es/components/organism/TextEditor/ui/Toolbar/FormattingToolbar.js +90 -0
- package/es/components/organism/TextEditor/ui/Toolbar/LinkPreviewToolbar.d.ts +10 -0
- package/es/components/organism/TextEditor/ui/Toolbar/LinkPreviewToolbar.js +39 -0
- package/es/components/organism/TextEditor/ui/Toolbar/actions/EmojiAction.js +4 -3
- package/es/components/organism/TextEditor/ui/Toolbar/actions/FontFamilyAction.d.ts +1 -0
- package/es/components/organism/TextEditor/ui/Toolbar/actions/FontFamilyAction.js +2 -2
- package/es/components/organism/TextEditor/ui/Toolbar/actions/FontSizeAction.js +6 -1
- package/es/components/organism/TextEditor/ui/Toolbar/index.d.ts +2 -1
- package/es/components/organism/TextEditor/ui/Toolbar/index.js +2 -1
- package/es/components/organism/TextEditor/utils/documentState.d.ts +14 -0
- package/es/components/organism/TextEditor/utils/documentState.js +25 -0
- package/es/components/organism/TextEditor/utils/htmlProcessing.js +60 -0
- package/es/components/organism/TextEditor/utils/link.d.ts +10 -1
- package/es/components/organism/TextEditor/utils/link.js +161 -7
- package/es/components/organism/TextEditor/utils/menu.js +2 -1
- package/es/components/organism/TextEditor/utils/selection.js +3 -2
- package/es/components/organism/TextEditor/utils/smartTag.js +2 -1
- package/es/components/organism/index.d.ts +3 -1
- package/es/components/organism/index.js +1 -0
- package/es/components/template/TemplateListing/Loadable.d.ts +1 -0
- package/es/hooks/index.d.ts +1 -1
- package/es/hooks/index.js +1 -1
- package/es/providers/ConfigProvider/ConfigProvider.d.ts +4 -0
- package/es/providers/ConfigProvider/ConfigProvider.js +2 -3
- package/es/providers/ConfigProvider/GlobalStyle.d.ts +2 -2
- package/es/providers/ConfigProvider/GlobalStyle.js +67 -64
- package/es/services/MediaTemplateDesign/UploadFile/index.js +4 -4
- package/es/utils/common.d.ts +1 -1
- package/es/utils/common.js +3 -3
- package/es/utils/cookie.js +2 -1
- package/es/utils/crossSubdomainCookieOptions.d.ts +14 -0
- package/es/utils/crossSubdomainCookieOptions.js +12 -0
- package/package.json +26 -30
- package/es/components/organism/TextEditor/ui/BubbleToolbar/BubbleToolbar.d.ts +0 -1
- package/es/components/organism/TextEditor/ui/BubbleToolbar/BubbleToolbar.js +0 -1
- package/es/components/organism/TextEditor/ui/BubbleToolbar/index.d.ts +0 -0
- package/es/components/organism/TextEditor/ui/BubbleToolbar/index.js +0 -1
- package/es/components/organism/TextEditor/ui/Toolbar/Toolbar.js +0 -39
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
export const DEFAULT_OAUTH_LOGIN_URL = '/oauth2/login';
|
|
2
|
+
export const DEFAULT_OAUTH_TOKEN_URL = '/oauth2/token';
|
|
3
|
+
export const DEFAULT_KRATOS_LOGIN_URL = '/self-service/login/browser';
|
|
4
|
+
export const DEFAULT_KRATOS_LOGOUT_URL = '/self-service/logout/browser';
|
|
5
|
+
export const DEFAULT_SESSION_URL = '/api/session';
|
|
6
|
+
export const DEFAULT_OAUTH_STORAGE_KEY = 'antsomi.ory.oauth';
|
|
7
|
+
const makeError = (code, message, status) => {
|
|
8
|
+
const error = new Error(message);
|
|
9
|
+
error.code = code;
|
|
10
|
+
if (status !== undefined) {
|
|
11
|
+
error.status = status;
|
|
12
|
+
}
|
|
13
|
+
return error;
|
|
14
|
+
};
|
|
15
|
+
export const makeUserError = (code, message, userMessage, status) => {
|
|
16
|
+
const error = makeError(code, message, status);
|
|
17
|
+
error.userMessage = userMessage;
|
|
18
|
+
return error;
|
|
19
|
+
};
|
|
20
|
+
export const getOrigin = (location) => location?.origin || 'http://localhost';
|
|
21
|
+
export const toURL = (value, origin) => {
|
|
22
|
+
try {
|
|
23
|
+
return new URL(value, origin);
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
throw makeError('ORY_INVALID_REDIRECT', 'Invalid OAuth redirect URL');
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
export const isOryLoginRequest = ({ location }) => {
|
|
30
|
+
const params = new URLSearchParams(location.search || '');
|
|
31
|
+
if (params.get('login_challenge')) {
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
const returnTo = params.get('return_to');
|
|
35
|
+
if (!returnTo) {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
try {
|
|
39
|
+
return Boolean(toURL(returnTo, getOrigin(location)).searchParams.get('login_challenge'));
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
export const isOryCallbackRequest = ({ location }) => {
|
|
46
|
+
const params = new URLSearchParams(location.search || '');
|
|
47
|
+
return Boolean(params.get('code') || params.get('error'));
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Build the only redirect accepted by the Ory login bridge. A return_to URL
|
|
51
|
+
* is trusted only when it has the configured bridge origin and path.
|
|
52
|
+
*/
|
|
53
|
+
export const getOAuthBridgeURL = ({ location, oauthLoginUrl = DEFAULT_OAUTH_LOGIN_URL, }) => {
|
|
54
|
+
const origin = getOrigin(location);
|
|
55
|
+
const expectedBridge = toURL(oauthLoginUrl, origin);
|
|
56
|
+
const params = new URLSearchParams(location.search || '');
|
|
57
|
+
const loginChallenge = params.get('login_challenge');
|
|
58
|
+
const returnTo = params.get('return_to');
|
|
59
|
+
const bridge = returnTo ? toURL(returnTo, origin) : expectedBridge;
|
|
60
|
+
if (bridge.origin !== expectedBridge.origin || bridge.pathname !== expectedBridge.pathname) {
|
|
61
|
+
throw makeError('ORY_UNTRUSTED_REDIRECT', 'OAuth return URL is not trusted');
|
|
62
|
+
}
|
|
63
|
+
if (loginChallenge) {
|
|
64
|
+
const bridgeChallenge = bridge.searchParams.get('login_challenge');
|
|
65
|
+
if (bridgeChallenge && bridgeChallenge !== loginChallenge) {
|
|
66
|
+
throw makeError('ORY_CHALLENGE_MISMATCH', 'OAuth login challenge mismatch');
|
|
67
|
+
}
|
|
68
|
+
if (!bridgeChallenge) {
|
|
69
|
+
bridge.searchParams.set('login_challenge', loginChallenge);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
if (!bridge.searchParams.get('login_challenge')) {
|
|
73
|
+
throw makeError('ORY_MISSING_CHALLENGE', 'OAuth login challenge is required');
|
|
74
|
+
}
|
|
75
|
+
return bridge.toString();
|
|
76
|
+
};
|
|
77
|
+
export const getKratosLoginURL = ({ kratosLoginUrl = DEFAULT_KRATOS_LOGIN_URL, returnTo, location, }) => {
|
|
78
|
+
const loginURL = toURL(kratosLoginUrl, getOrigin(location));
|
|
79
|
+
loginURL.searchParams.set('return_to', returnTo);
|
|
80
|
+
return loginURL.toString();
|
|
81
|
+
};
|
|
82
|
+
const hasSessionSubject = (payload) => {
|
|
83
|
+
const data = payload?.data;
|
|
84
|
+
return Boolean(data?.subjectId || data?.identityId);
|
|
85
|
+
};
|
|
86
|
+
export const resolveOryLogin = async ({ location, oauthLoginUrl = DEFAULT_OAUTH_LOGIN_URL, kratosLoginUrl = DEFAULT_KRATOS_LOGIN_URL, sessionUrl = DEFAULT_SESSION_URL, fetchImpl, assign, }) => {
|
|
87
|
+
const bridgeURL = getOAuthBridgeURL({ location, oauthLoginUrl });
|
|
88
|
+
const request = fetchImpl || (typeof fetch === 'function' ? fetch : undefined);
|
|
89
|
+
if (!request) {
|
|
90
|
+
throw makeError('ORY_SESSION_CHECK_UNAVAILABLE', 'Browser session check is unavailable');
|
|
91
|
+
}
|
|
92
|
+
const response = await request(sessionUrl, {
|
|
93
|
+
credentials: 'include',
|
|
94
|
+
headers: { Accept: 'application/json' },
|
|
95
|
+
});
|
|
96
|
+
let payload = null;
|
|
97
|
+
try {
|
|
98
|
+
payload = await response.json();
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
// An authenticated session endpoint must return its JSON session envelope.
|
|
102
|
+
}
|
|
103
|
+
if (response.ok && hasSessionSubject(payload)) {
|
|
104
|
+
assign?.(bridgeURL);
|
|
105
|
+
return { status: 'redirect', destination: bridgeURL };
|
|
106
|
+
}
|
|
107
|
+
if (response.status === 401) {
|
|
108
|
+
const destination = getKratosLoginURL({ kratosLoginUrl, returnTo: bridgeURL, location });
|
|
109
|
+
assign?.(destination);
|
|
110
|
+
return { status: 'redirect', destination };
|
|
111
|
+
}
|
|
112
|
+
throw makeError(response.ok ? 'ORY_INVALID_SESSION_RESPONSE' : 'ORY_SESSION_CHECK_FAILED', response.ok ? 'Authenticated session response is invalid' : 'Browser session check failed', response.status);
|
|
113
|
+
};
|
|
114
|
+
export const readJSON = async (response) => {
|
|
115
|
+
try {
|
|
116
|
+
return await response.json();
|
|
117
|
+
}
|
|
118
|
+
catch (error) {
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
export const checkOrySession = async ({ sessionUrl = DEFAULT_SESSION_URL, fetchImpl, }) => {
|
|
123
|
+
const request = fetchImpl || (typeof fetch === 'function' ? fetch : undefined);
|
|
124
|
+
if (!request)
|
|
125
|
+
throw makeError('ORY_SESSION_CHECK_UNAVAILABLE', 'Browser session check is unavailable');
|
|
126
|
+
const response = await request(sessionUrl, {
|
|
127
|
+
credentials: 'include',
|
|
128
|
+
headers: { Accept: 'application/json' },
|
|
129
|
+
});
|
|
130
|
+
const payload = await readJSON(response);
|
|
131
|
+
if (response.ok && hasSessionSubject(payload))
|
|
132
|
+
return payload;
|
|
133
|
+
if (response.status === 401 && payload?.error?.code === "MFA_REQUIRED")
|
|
134
|
+
throw makeError("ORY_MFA_REQUIRED", "Additional verification is required", 401);
|
|
135
|
+
if (response.status === 401)
|
|
136
|
+
throw makeError('ORY_SESSION_REQUIRED', 'A browser session is required', 401);
|
|
137
|
+
throw makeError('ORY_SESSION_CHECK_FAILED', 'Browser session check failed', response.status);
|
|
138
|
+
};
|
|
139
|
+
/** Continue with Kratos's existing MFA UI; retain the validated Hydra bridge. */
|
|
140
|
+
export const redirectOryMFA = ({ location, kratosLoginUrl = DEFAULT_KRATOS_LOGIN_URL, oauthLoginUrl = DEFAULT_OAUTH_LOGIN_URL, assign }) => {
|
|
141
|
+
const url = toURL(kratosLoginUrl, getOrigin(location));
|
|
142
|
+
url.searchParams.set('aal', 'aal2');
|
|
143
|
+
url.searchParams.set('return_to', getOAuthBridgeURL({ location, oauthLoginUrl }));
|
|
144
|
+
assign(url.toString());
|
|
145
|
+
};
|
|
146
|
+
const hasStepUpNode = (payload) => {
|
|
147
|
+
const nodes = payload?.ui?.nodes;
|
|
148
|
+
return (Array.isArray(nodes) &&
|
|
149
|
+
nodes.some(node => {
|
|
150
|
+
const name = node?.attributes?.name;
|
|
151
|
+
return name === 'totp' || name === 'lookup_secret' || name === 'webauthn' || name === 'code';
|
|
152
|
+
}));
|
|
153
|
+
};
|
|
154
|
+
const getSameOriginKratosAction = ({ location, kratosLoginUrl, flowId, action, }) => {
|
|
155
|
+
const origin = getOrigin(location);
|
|
156
|
+
const configured = toURL(kratosLoginUrl, origin);
|
|
157
|
+
const candidate = action ? toURL(action, origin) : configured;
|
|
158
|
+
const configuredPath = configured.pathname.replace(/\/browser\/?$/, '');
|
|
159
|
+
// Kratos may return an absolute action for its upstream port. Only retain
|
|
160
|
+
// the validated login path and flow id when posting through the app proxy.
|
|
161
|
+
if (candidate.pathname.replace(/\/$/, '') !== configuredPath.replace(/\/$/, '') &&
|
|
162
|
+
candidate.pathname !== configured.pathname) {
|
|
163
|
+
throw makeError('ORY_LOGIN_ACTION_INVALID', 'Kratos login action is invalid');
|
|
164
|
+
}
|
|
165
|
+
const postURL = new URL(configuredPath || '/self-service/login', origin);
|
|
166
|
+
postURL.searchParams.set('flow', flowId);
|
|
167
|
+
return postURL.toString();
|
|
168
|
+
};
|
|
169
|
+
/**
|
|
170
|
+
* Submit the existing package SignIn form to a same-origin Kratos browser
|
|
171
|
+
* flow, then return the verified browser session to Hydra's login bridge.
|
|
172
|
+
* Passwords are sent only in the form request and are never persisted.
|
|
173
|
+
*/
|
|
174
|
+
export const submitOryPasswordLogin = async ({ location, email, password, kratosLoginUrl = DEFAULT_KRATOS_LOGIN_URL, sessionUrl = DEFAULT_SESSION_URL, oauthLoginUrl = DEFAULT_OAUTH_LOGIN_URL, returnToBridge = true, inlineMfa = false, fetchImpl, assign, }) => {
|
|
175
|
+
const request = fetchImpl || (typeof fetch === 'function' ? fetch : undefined);
|
|
176
|
+
if (!request) {
|
|
177
|
+
throw makeError('ORY_LOGIN_UNAVAILABLE', 'Kratos login is unavailable');
|
|
178
|
+
}
|
|
179
|
+
const bridgeURL = returnToBridge ? getOAuthBridgeURL({ location, oauthLoginUrl }) : '';
|
|
180
|
+
const loginURL = toURL(kratosLoginUrl, getOrigin(location));
|
|
181
|
+
loginURL.searchParams.set('refresh', 'true');
|
|
182
|
+
if (bridgeURL) {
|
|
183
|
+
loginURL.searchParams.set('return_to', bridgeURL);
|
|
184
|
+
}
|
|
185
|
+
const flowResponse = await request(loginURL.toString(), {
|
|
186
|
+
credentials: 'include',
|
|
187
|
+
headers: { Accept: 'application/json' },
|
|
188
|
+
});
|
|
189
|
+
const flowPayload = (await readJSON(flowResponse));
|
|
190
|
+
if (!flowResponse.ok || !flowPayload?.id) {
|
|
191
|
+
throw makeUserError('ORY_LOGIN_FLOW_FAILED', 'Kratos login flow could not be initialized', 'Unable to start secure sign-in. Please try again.', flowResponse.status);
|
|
192
|
+
}
|
|
193
|
+
const csrfNode = flowPayload.ui?.nodes?.find(node => node?.attributes?.name === 'csrf_token');
|
|
194
|
+
const csrfToken = csrfNode?.attributes?.value;
|
|
195
|
+
if (!csrfToken) {
|
|
196
|
+
throw makeUserError('ORY_CSRF_MISSING', 'Kratos login flow did not provide a CSRF token', 'Secure sign-in could not be verified. Please try again.');
|
|
197
|
+
}
|
|
198
|
+
const body = new URLSearchParams({
|
|
199
|
+
method: 'password',
|
|
200
|
+
identifier: email,
|
|
201
|
+
password,
|
|
202
|
+
csrf_token: csrfToken,
|
|
203
|
+
});
|
|
204
|
+
const submitURL = getSameOriginKratosAction({
|
|
205
|
+
location,
|
|
206
|
+
kratosLoginUrl,
|
|
207
|
+
flowId: flowPayload.id,
|
|
208
|
+
action: flowPayload.ui?.action,
|
|
209
|
+
});
|
|
210
|
+
const submitResponse = await request(submitURL, {
|
|
211
|
+
method: 'POST',
|
|
212
|
+
credentials: 'include',
|
|
213
|
+
headers: { Accept: 'application/json', 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
214
|
+
body: body.toString(),
|
|
215
|
+
});
|
|
216
|
+
const submitPayload = await readJSON(submitResponse);
|
|
217
|
+
if (!submitResponse.ok && submitPayload?.error?.id !== 'browser_location_change_required') {
|
|
218
|
+
if (hasStepUpNode(submitPayload) || submitPayload?.error?.id === 'session_aal2_required') {
|
|
219
|
+
if (!returnToBridge || inlineMfa)
|
|
220
|
+
return { status: 'mfa-required' };
|
|
221
|
+
if (assign) {
|
|
222
|
+
redirectOryMFA({ location, kratosLoginUrl, oauthLoginUrl, assign });
|
|
223
|
+
return { status: 'mfa-required' };
|
|
224
|
+
}
|
|
225
|
+
throw makeUserError('ORY_MFA_REQUIRED', 'Additional Kratos verification is required', 'Additional verification is required to finish signing in.', submitResponse.status);
|
|
226
|
+
}
|
|
227
|
+
throw makeUserError('ORY_INVALID_CREDENTIALS', 'Kratos rejected the submitted credentials', 'Email or password is invalid', submitResponse.status);
|
|
228
|
+
}
|
|
229
|
+
const sessionResponse = await request(sessionUrl, {
|
|
230
|
+
credentials: 'include',
|
|
231
|
+
headers: { Accept: 'application/json' },
|
|
232
|
+
});
|
|
233
|
+
const sessionPayload = await readJSON(sessionResponse);
|
|
234
|
+
if (sessionResponse.status === 401 && sessionPayload?.error?.code === 'MFA_REQUIRED') {
|
|
235
|
+
if (returnToBridge && assign && !inlineMfa) {
|
|
236
|
+
redirectOryMFA({ location, kratosLoginUrl, oauthLoginUrl, assign });
|
|
237
|
+
}
|
|
238
|
+
return { status: 'mfa-required' };
|
|
239
|
+
}
|
|
240
|
+
if (!sessionResponse.ok || !hasSessionSubject(sessionPayload)) {
|
|
241
|
+
throw makeUserError('ORY_SESSION_CHECK_FAILED', 'Kratos did not establish a browser session', 'Secure sign-in could not be completed. Please try again.', sessionResponse.status);
|
|
242
|
+
}
|
|
243
|
+
if (!bridgeURL) {
|
|
244
|
+
return { status: 'authenticated', session: sessionPayload };
|
|
245
|
+
}
|
|
246
|
+
assign?.(bridgeURL);
|
|
247
|
+
return { status: 'redirect', destination: bridgeURL };
|
|
248
|
+
};
|
|
249
|
+
const encodeBase64URL = (value) => {
|
|
250
|
+
if (typeof btoa !== 'function') {
|
|
251
|
+
throw makeError('ORY_PKCE_UNAVAILABLE', 'Browser PKCE support is unavailable');
|
|
252
|
+
}
|
|
253
|
+
let binary = '';
|
|
254
|
+
value.forEach(byte => {
|
|
255
|
+
binary += String.fromCharCode(byte);
|
|
256
|
+
});
|
|
257
|
+
return btoa(binary).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
|
|
258
|
+
};
|
|
259
|
+
const randomURLSafeValue = (cryptoImpl) => {
|
|
260
|
+
const bytes = new Uint8Array(32);
|
|
261
|
+
cryptoImpl.getRandomValues(bytes);
|
|
262
|
+
return encodeBase64URL(bytes);
|
|
263
|
+
};
|
|
264
|
+
const getStorage = (storage) => {
|
|
265
|
+
if (storage) {
|
|
266
|
+
return storage;
|
|
267
|
+
}
|
|
268
|
+
if (typeof sessionStorage === 'undefined') {
|
|
269
|
+
throw makeError('ORY_STORAGE_UNAVAILABLE', 'Browser OAuth session storage is unavailable');
|
|
270
|
+
}
|
|
271
|
+
return sessionStorage;
|
|
272
|
+
};
|
|
273
|
+
const getCrypto = (cryptoImpl) => {
|
|
274
|
+
if (cryptoImpl) {
|
|
275
|
+
return cryptoImpl;
|
|
276
|
+
}
|
|
277
|
+
if (typeof crypto === 'undefined' || !crypto.subtle) {
|
|
278
|
+
throw makeError('ORY_PKCE_UNAVAILABLE', 'Browser PKCE support is unavailable');
|
|
279
|
+
}
|
|
280
|
+
return crypto;
|
|
281
|
+
};
|
|
282
|
+
const getRequiredConfig = (value, code, message) => {
|
|
283
|
+
if (!value || !value.trim()) {
|
|
284
|
+
throw makeError(code, message);
|
|
285
|
+
}
|
|
286
|
+
return value.trim();
|
|
287
|
+
};
|
|
288
|
+
export const startOryAuthorization = async ({ location, authorizeUrl, clientId, redirectUri, scope, audience, storage, storageKey = DEFAULT_OAUTH_STORAGE_KEY, cryptoImpl, assign, }) => {
|
|
289
|
+
const resolvedClientId = getRequiredConfig(clientId, 'ORY_CLIENT_ID_REQUIRED', 'OAuth client ID is required');
|
|
290
|
+
const resolvedRedirectUri = getRequiredConfig(redirectUri, 'ORY_REDIRECT_URI_REQUIRED', 'OAuth redirect URI is required');
|
|
291
|
+
const resolvedScope = getRequiredConfig(scope, 'ORY_SCOPE_REQUIRED', 'OAuth scope is required');
|
|
292
|
+
const cryptoValue = getCrypto(cryptoImpl);
|
|
293
|
+
const state = randomURLSafeValue(cryptoValue);
|
|
294
|
+
const verifier = randomURLSafeValue(cryptoValue);
|
|
295
|
+
const digest = await cryptoValue.subtle.digest('SHA-256', new TextEncoder().encode(verifier));
|
|
296
|
+
const challenge = encodeBase64URL(new Uint8Array(digest));
|
|
297
|
+
const authURL = toURL(authorizeUrl, getOrigin(location));
|
|
298
|
+
authURL.searchParams.set('client_id', resolvedClientId);
|
|
299
|
+
authURL.searchParams.set('redirect_uri', resolvedRedirectUri);
|
|
300
|
+
authURL.searchParams.set('response_type', 'code');
|
|
301
|
+
authURL.searchParams.set('scope', resolvedScope);
|
|
302
|
+
authURL.searchParams.set('state', state);
|
|
303
|
+
authURL.searchParams.set('code_challenge', challenge);
|
|
304
|
+
authURL.searchParams.set('code_challenge_method', 'S256');
|
|
305
|
+
if (audience && audience.trim()) {
|
|
306
|
+
authURL.searchParams.set('audience', audience.trim());
|
|
307
|
+
}
|
|
308
|
+
getStorage(storage).setItem(storageKey, JSON.stringify({
|
|
309
|
+
state,
|
|
310
|
+
verifier,
|
|
311
|
+
clientId: resolvedClientId,
|
|
312
|
+
redirectUri: resolvedRedirectUri,
|
|
313
|
+
}));
|
|
314
|
+
const destination = authURL.toString();
|
|
315
|
+
assign?.(destination);
|
|
316
|
+
return { status: 'redirect', destination };
|
|
317
|
+
};
|
|
318
|
+
export const completeOryAuthorization = async ({ location, tokenUrl, clientId, redirectUri, storage, storageKey = DEFAULT_OAUTH_STORAGE_KEY, fetchImpl, }) => {
|
|
319
|
+
const params = new URLSearchParams(location.search || '');
|
|
320
|
+
const oauthError = params.get('error');
|
|
321
|
+
if (oauthError) {
|
|
322
|
+
throw makeError('ORY_AUTHORIZATION_DENIED', 'OAuth authorization was denied');
|
|
323
|
+
}
|
|
324
|
+
const code = getRequiredConfig(params.get('code') || undefined, 'ORY_CODE_REQUIRED', 'OAuth authorization code is required');
|
|
325
|
+
const returnedState = getRequiredConfig(params.get('state') || undefined, 'ORY_STATE_REQUIRED', 'OAuth state is required');
|
|
326
|
+
const resolvedClientId = getRequiredConfig(clientId, 'ORY_CLIENT_ID_REQUIRED', 'OAuth client ID is required');
|
|
327
|
+
const resolvedRedirectUri = getRequiredConfig(redirectUri, 'ORY_REDIRECT_URI_REQUIRED', 'OAuth redirect URI is required');
|
|
328
|
+
const stored = getStorage(storage);
|
|
329
|
+
const rawTransaction = stored.getItem(storageKey);
|
|
330
|
+
stored.removeItem(storageKey);
|
|
331
|
+
if (!rawTransaction) {
|
|
332
|
+
throw makeError('ORY_STATE_MISSING', 'OAuth login transaction is missing');
|
|
333
|
+
}
|
|
334
|
+
let transaction;
|
|
335
|
+
try {
|
|
336
|
+
transaction = JSON.parse(rawTransaction);
|
|
337
|
+
}
|
|
338
|
+
catch (error) {
|
|
339
|
+
throw makeError('ORY_STATE_INVALID', 'OAuth login transaction is invalid');
|
|
340
|
+
}
|
|
341
|
+
if (transaction.state !== returnedState ||
|
|
342
|
+
transaction.clientId !== resolvedClientId ||
|
|
343
|
+
transaction.redirectUri !== resolvedRedirectUri ||
|
|
344
|
+
!transaction.verifier) {
|
|
345
|
+
throw makeError('ORY_STATE_MISMATCH', 'OAuth state verification failed');
|
|
346
|
+
}
|
|
347
|
+
const request = fetchImpl || (typeof fetch === 'function' ? fetch : undefined);
|
|
348
|
+
const resolvedTokenUrl = getRequiredConfig(tokenUrl, 'ORY_TOKEN_URL_REQUIRED', 'OAuth token URL is required');
|
|
349
|
+
if (!request) {
|
|
350
|
+
throw makeError('ORY_TOKEN_EXCHANGE_UNAVAILABLE', 'OAuth token exchange is unavailable');
|
|
351
|
+
}
|
|
352
|
+
const response = await request(resolvedTokenUrl, {
|
|
353
|
+
method: 'POST',
|
|
354
|
+
credentials: 'omit',
|
|
355
|
+
headers: { Accept: 'application/json', 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
356
|
+
body: new URLSearchParams({
|
|
357
|
+
grant_type: 'authorization_code',
|
|
358
|
+
client_id: resolvedClientId,
|
|
359
|
+
redirect_uri: resolvedRedirectUri,
|
|
360
|
+
code,
|
|
361
|
+
code_verifier: transaction.verifier,
|
|
362
|
+
}).toString(),
|
|
363
|
+
});
|
|
364
|
+
let payload = null;
|
|
365
|
+
try {
|
|
366
|
+
payload = await response.json();
|
|
367
|
+
}
|
|
368
|
+
catch (error) {
|
|
369
|
+
// An OAuth token endpoint must return JSON on both success and failure.
|
|
370
|
+
}
|
|
371
|
+
if (!response.ok ||
|
|
372
|
+
!payload ||
|
|
373
|
+
typeof payload !== 'object' ||
|
|
374
|
+
typeof payload.access_token !== 'string') {
|
|
375
|
+
throw makeError('ORY_TOKEN_EXCHANGE_FAILED', 'OAuth token exchange failed', response.status);
|
|
376
|
+
}
|
|
377
|
+
return payload;
|
|
378
|
+
};
|
|
379
|
+
/**
|
|
380
|
+
* End the Kratos browser session ("sign in with a different account"). Kratos
|
|
381
|
+
* hands back a one-time logout URL for the same-origin session cookie; the
|
|
382
|
+
* return URL must stay on this origin.
|
|
383
|
+
*/
|
|
384
|
+
export const startOryLogout = async ({ location, returnTo, kratosLogoutUrl = DEFAULT_KRATOS_LOGOUT_URL, fetchImpl, assign, }) => {
|
|
385
|
+
const request = fetchImpl || (typeof fetch === 'function' ? fetch : undefined);
|
|
386
|
+
if (!request) {
|
|
387
|
+
throw makeError('ORY_LOGOUT_UNAVAILABLE', 'Kratos logout is unavailable');
|
|
388
|
+
}
|
|
389
|
+
const origin = getOrigin(location);
|
|
390
|
+
const target = toURL(returnTo, origin);
|
|
391
|
+
if (target.origin !== origin) {
|
|
392
|
+
throw makeError('ORY_UNTRUSTED_REDIRECT', 'Logout return URL is not trusted');
|
|
393
|
+
}
|
|
394
|
+
const logoutInit = toURL(kratosLogoutUrl, origin);
|
|
395
|
+
logoutInit.searchParams.set('return_to', target.toString());
|
|
396
|
+
const response = await request(logoutInit.toString(), {
|
|
397
|
+
credentials: 'include',
|
|
398
|
+
headers: { Accept: 'application/json' },
|
|
399
|
+
});
|
|
400
|
+
const payload = await readJSON(response);
|
|
401
|
+
const logoutUrl = payload?.logout_url || payload?.data?.logout_url;
|
|
402
|
+
if (!response.ok || !logoutUrl) {
|
|
403
|
+
throw makeUserError('ORY_LOGOUT_FAILED', 'Kratos logout could not be initialized', 'Unable to sign out. Please try again.', response.status);
|
|
404
|
+
}
|
|
405
|
+
const destination = toURL(logoutUrl, origin).toString();
|
|
406
|
+
assign?.(destination);
|
|
407
|
+
return { status: 'redirect', destination };
|
|
408
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { OryAccount, OryConsentGrant, OryConsentRequest, OryPortal, OryScopeCatalog, OryScopeInfo } from '../types/ory';
|
|
2
|
+
import { FetchLike, LocationLike } from './ory';
|
|
3
|
+
/** Scopes that describe the user's identity rather than a portal resource. */
|
|
4
|
+
export declare const OIDC_SCOPES: string[];
|
|
5
|
+
export declare const DEFAULT_SCOPE_CATALOG: OryScopeCatalog;
|
|
6
|
+
export declare const getOryScopeInfo: (scope: string, catalog?: OryScopeCatalog) => OryScopeInfo;
|
|
7
|
+
/** A portal must be chosen when the token carries business (non-OIDC) access. */
|
|
8
|
+
export declare const requiresOryPortal: (request?: OryConsentRequest | null) => boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Portals come from the verified session memberships. Only the identifier is
|
|
11
|
+
* guaranteed; name, environment and tags are shown when the backend sends them.
|
|
12
|
+
*/
|
|
13
|
+
export declare const getOryPortals: (payload: unknown) => OryPortal[];
|
|
14
|
+
export declare const getOryAccount: (payload: unknown, subject?: string) => OryAccount;
|
|
15
|
+
export declare const getOryAccountLabel: (account: OryAccount) => string;
|
|
16
|
+
export declare const getInitials: (value: string) => string;
|
|
17
|
+
/** Preferred portal (e.g. `portal_id` in the URL) wins, then the default, then a sole portal. */
|
|
18
|
+
export declare const getInitialOryPortalId: (portals: OryPortal[], preferred?: string | null) => string;
|
|
19
|
+
/** Multiple memberships always require an explicit portal choice for the token. */
|
|
20
|
+
export declare const shouldPromptForOryPortal: (portals: OryPortal[], preferred?: string | null) => boolean;
|
|
21
|
+
/** Distinct environment/tag labels, used as filter chips. */
|
|
22
|
+
export declare const getOryPortalTags: (portals: OryPortal[]) => string[];
|
|
23
|
+
export declare const filterOryPortals: (portals: OryPortal[], { query, tag }: {
|
|
24
|
+
query?: string;
|
|
25
|
+
tag?: string;
|
|
26
|
+
}) => OryPortal[];
|
|
27
|
+
export declare const getInitialSelectedScopes: (request: OryConsentRequest) => string[];
|
|
28
|
+
/**
|
|
29
|
+
* Build the acceptance body. Only scopes Hydra requested can be granted, in the
|
|
30
|
+
* requested order, and required scopes (openid) are always kept.
|
|
31
|
+
*/
|
|
32
|
+
export declare const buildOryConsentGrant: ({ request, selected, portalId, remember, catalog, }: {
|
|
33
|
+
request: OryConsentRequest;
|
|
34
|
+
selected: string[];
|
|
35
|
+
portalId: string;
|
|
36
|
+
remember: boolean;
|
|
37
|
+
catalog?: OryScopeCatalog;
|
|
38
|
+
}) => OryConsentGrant;
|
|
39
|
+
/**
|
|
40
|
+
* Decline the authorization request. Hydra answers with the redirect back to
|
|
41
|
+
* the requesting application carrying `error=access_denied`, so the client is
|
|
42
|
+
* told the outcome instead of the challenge silently expiring.
|
|
43
|
+
*/
|
|
44
|
+
export declare const declineOryConsent: ({ location, rejectUrl, csrfUrl, challenge, fetchImpl, }: {
|
|
45
|
+
location: LocationLike;
|
|
46
|
+
rejectUrl: string;
|
|
47
|
+
csrfUrl: string;
|
|
48
|
+
challenge: string;
|
|
49
|
+
fetchImpl?: FetchLike;
|
|
50
|
+
}) => Promise<{
|
|
51
|
+
redirectTo: string;
|
|
52
|
+
}>;
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { getOrigin, makeUserError, readJSON, toURL } from './ory';
|
|
2
|
+
/** Scopes that describe the user's identity rather than a portal resource. */
|
|
3
|
+
export const OIDC_SCOPES = ['openid', 'profile', 'email', 'offline_access'];
|
|
4
|
+
export const DEFAULT_SCOPE_CATALOG = {
|
|
5
|
+
openid: {
|
|
6
|
+
title: 'Verify your identity',
|
|
7
|
+
description: 'Confirm who you are with your Antsomi account.',
|
|
8
|
+
required: true,
|
|
9
|
+
},
|
|
10
|
+
profile: {
|
|
11
|
+
title: 'Basic profile',
|
|
12
|
+
description: 'Read your name and profile details.',
|
|
13
|
+
},
|
|
14
|
+
email: {
|
|
15
|
+
title: 'Email address',
|
|
16
|
+
description: 'Read the email address of your account.',
|
|
17
|
+
},
|
|
18
|
+
offline_access: {
|
|
19
|
+
title: 'Offline access',
|
|
20
|
+
description: 'Stay connected without asking you to sign in again.',
|
|
21
|
+
},
|
|
22
|
+
'reports.read': {
|
|
23
|
+
title: 'View reports',
|
|
24
|
+
description: 'Read reports in the selected portal.',
|
|
25
|
+
},
|
|
26
|
+
'reports.write': {
|
|
27
|
+
title: 'Manage reports',
|
|
28
|
+
description: 'Create and edit reports in the selected portal.',
|
|
29
|
+
sensitive: true,
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
export const getOryScopeInfo = (scope, catalog = {}) => catalog[scope] ||
|
|
33
|
+
DEFAULT_SCOPE_CATALOG[scope] || {
|
|
34
|
+
title: scope,
|
|
35
|
+
description: 'Access requested by this application.',
|
|
36
|
+
};
|
|
37
|
+
const isRequiredScope = (scope, catalog) => Boolean(getOryScopeInfo(scope, catalog).required);
|
|
38
|
+
/** A portal must be chosen when the token carries business (non-OIDC) access. */
|
|
39
|
+
export const requiresOryPortal = (request) => {
|
|
40
|
+
if (!request)
|
|
41
|
+
return false;
|
|
42
|
+
const hasBusinessScope = (request.requested_scope || []).some(scope => !OIDC_SCOPES.includes(scope));
|
|
43
|
+
return hasBusinessScope || Boolean(request.requested_access_token_audience?.length);
|
|
44
|
+
};
|
|
45
|
+
const asText = (value) => typeof value === 'string' && value.trim() ? value.trim() : undefined;
|
|
46
|
+
/**
|
|
47
|
+
* Portals come from the verified session memberships. Only the identifier is
|
|
48
|
+
* guaranteed; name, environment and tags are shown when the backend sends them.
|
|
49
|
+
*/
|
|
50
|
+
export const getOryPortals = (payload) => {
|
|
51
|
+
const memberships = payload?.data?.memberships;
|
|
52
|
+
if (!Array.isArray(memberships))
|
|
53
|
+
return [];
|
|
54
|
+
const seen = new Set();
|
|
55
|
+
const portals = [];
|
|
56
|
+
memberships.forEach((item) => {
|
|
57
|
+
const id = item?.portalId === undefined ? '' : String(item.portalId);
|
|
58
|
+
if (!id || seen.has(id))
|
|
59
|
+
return;
|
|
60
|
+
seen.add(id);
|
|
61
|
+
const label = item.legacyPortalId ?? id;
|
|
62
|
+
portals.push({
|
|
63
|
+
id,
|
|
64
|
+
name: asText(item.portalName) || `Portal ${label}`,
|
|
65
|
+
slug: asText(item.portalSlug),
|
|
66
|
+
environment: asText(item.environment),
|
|
67
|
+
tags: Array.isArray(item.tags)
|
|
68
|
+
? item.tags.map(asText).filter(Boolean)
|
|
69
|
+
: undefined,
|
|
70
|
+
logo: asText(item.logo),
|
|
71
|
+
isDefault: item.isDefault === true,
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
return portals;
|
|
75
|
+
};
|
|
76
|
+
export const getOryAccount = (payload, subject) => {
|
|
77
|
+
const data = (payload?.data || {});
|
|
78
|
+
return {
|
|
79
|
+
name: asText(data.displayName) || asText(data.name) || asText(data.fullName),
|
|
80
|
+
email: asText(data.email),
|
|
81
|
+
avatar: asText(data.avatar),
|
|
82
|
+
subject: asText(data.subjectId) || subject,
|
|
83
|
+
};
|
|
84
|
+
};
|
|
85
|
+
export const getOryAccountLabel = (account) => account.email || account.name || account.subject || 'your account';
|
|
86
|
+
export const getInitials = (value) => {
|
|
87
|
+
const words = value
|
|
88
|
+
.trim()
|
|
89
|
+
.split(/[\s@._-]+/)
|
|
90
|
+
.filter(Boolean);
|
|
91
|
+
const letters = words.length > 1 ? words[0][0] + words[1][0] : (words[0] || '?').slice(0, 2);
|
|
92
|
+
return letters.toUpperCase();
|
|
93
|
+
};
|
|
94
|
+
/** Preferred portal (e.g. `portal_id` in the URL) wins, then the default, then a sole portal. */
|
|
95
|
+
export const getInitialOryPortalId = (portals, preferred) => {
|
|
96
|
+
if (preferred && portals.some(portal => portal.id === preferred))
|
|
97
|
+
return preferred;
|
|
98
|
+
const fallback = portals.find(portal => portal.isDefault);
|
|
99
|
+
if (fallback)
|
|
100
|
+
return fallback.id;
|
|
101
|
+
return portals.length === 1 ? portals[0].id : '';
|
|
102
|
+
};
|
|
103
|
+
/** Multiple memberships always require an explicit portal choice for the token. */
|
|
104
|
+
export const shouldPromptForOryPortal = (portals, preferred) => portals.length > 1 && !(preferred && portals.some(portal => portal.id === preferred));
|
|
105
|
+
const portalLabels = (portal) => [portal.environment, ...(portal.tags || [])].filter(Boolean);
|
|
106
|
+
/** Distinct environment/tag labels, used as filter chips. */
|
|
107
|
+
export const getOryPortalTags = (portals) => {
|
|
108
|
+
const labels = [];
|
|
109
|
+
portals.forEach(portal => {
|
|
110
|
+
portalLabels(portal).forEach(label => {
|
|
111
|
+
if (!labels.some(existing => existing.toLowerCase() === label.toLowerCase())) {
|
|
112
|
+
labels.push(label);
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
return labels;
|
|
117
|
+
};
|
|
118
|
+
export const filterOryPortals = (portals, { query = '', tag = '' }) => {
|
|
119
|
+
const needle = query.trim().toLowerCase();
|
|
120
|
+
const wantedTag = tag.trim().toLowerCase();
|
|
121
|
+
return portals.filter(portal => {
|
|
122
|
+
const labels = portalLabels(portal).map(label => label.toLowerCase());
|
|
123
|
+
if (wantedTag && !labels.includes(wantedTag))
|
|
124
|
+
return false;
|
|
125
|
+
if (!needle)
|
|
126
|
+
return true;
|
|
127
|
+
return [portal.name, portal.slug, portal.id, ...labels].some(value => value && value.toLowerCase().includes(needle));
|
|
128
|
+
});
|
|
129
|
+
};
|
|
130
|
+
export const getInitialSelectedScopes = (request) => [
|
|
131
|
+
...(request.requested_scope || []),
|
|
132
|
+
];
|
|
133
|
+
/**
|
|
134
|
+
* Build the acceptance body. Only scopes Hydra requested can be granted, in the
|
|
135
|
+
* requested order, and required scopes (openid) are always kept.
|
|
136
|
+
*/
|
|
137
|
+
export const buildOryConsentGrant = ({ request, selected, portalId, remember, catalog = {}, }) => ({
|
|
138
|
+
portalId,
|
|
139
|
+
grantScope: (request.requested_scope || []).filter(scope => selected.includes(scope) || isRequiredScope(scope, catalog)),
|
|
140
|
+
grantAccessTokenAudience: request.requested_access_token_audience || [],
|
|
141
|
+
remember,
|
|
142
|
+
});
|
|
143
|
+
/**
|
|
144
|
+
* Decline the authorization request. Hydra answers with the redirect back to
|
|
145
|
+
* the requesting application carrying `error=access_denied`, so the client is
|
|
146
|
+
* told the outcome instead of the challenge silently expiring.
|
|
147
|
+
*/
|
|
148
|
+
export const declineOryConsent = async ({ location, rejectUrl, csrfUrl, challenge, fetchImpl, }) => {
|
|
149
|
+
const request = fetchImpl || (typeof fetch === 'function' ? fetch : undefined);
|
|
150
|
+
const failure = (status) => makeUserError('ORY_CONSENT_DECLINE_FAILED', 'The authorization request could not be declined', 'Unable to decline the request. Please try again.', status);
|
|
151
|
+
if (!request || !challenge)
|
|
152
|
+
throw failure();
|
|
153
|
+
const origin = getOrigin(location);
|
|
154
|
+
const csrfResponse = await request(toURL(csrfUrl, origin).toString(), {
|
|
155
|
+
credentials: 'include',
|
|
156
|
+
headers: { Accept: 'application/json' },
|
|
157
|
+
});
|
|
158
|
+
const csrfPayload = await readJSON(csrfResponse);
|
|
159
|
+
const csrfToken = csrfPayload?.token || csrfPayload?.data?.token;
|
|
160
|
+
if (!csrfResponse.ok || !csrfToken)
|
|
161
|
+
throw failure(csrfResponse.status);
|
|
162
|
+
const url = toURL(rejectUrl, origin);
|
|
163
|
+
url.searchParams.set('consent_challenge', challenge);
|
|
164
|
+
const response = await request(url.toString(), {
|
|
165
|
+
method: 'POST',
|
|
166
|
+
credentials: 'include',
|
|
167
|
+
headers: { Accept: 'application/json', 'X-CSRF-Token': csrfToken },
|
|
168
|
+
});
|
|
169
|
+
const payload = await readJSON(response);
|
|
170
|
+
const redirectTo = payload?.data?.redirectTo || payload?.redirectTo;
|
|
171
|
+
if (!response.ok || !redirectTo)
|
|
172
|
+
throw failure(response.status);
|
|
173
|
+
return { redirectTo: toURL(redirectTo, origin).toString() };
|
|
174
|
+
};
|