@abtnode/blocklet-services 1.16.34-beta-20241204-140321-4d75ca21 → 1.16.34-beta-20241205-145120-3a7aa096
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/api/libs/connect/session.js +4 -4
- package/api/middlewares/check-federated.js +157 -0
- package/api/routes/federated.js +529 -573
- package/api/routes/oauth.js +32 -54
- package/api/routes/user-session.js +239 -214
- package/api/routes/user.js +52 -45
- package/api/services/auth/connect/invite.js +1 -1
- package/api/services/auth/connect/issue-passport.js +1 -1
- package/api/services/auth/session.js +31 -9
- package/api/util/attach-shared-utils.js +6 -6
- package/api/util/federated.js +28 -72
- package/dist/assets/Add-CEkiASJk.js +1 -0
- package/dist/assets/{Alert-XwCbbCdw.js → Alert-D7cZ7kYh.js} +1 -1
- package/dist/assets/ArrowDropDown-CNA2YBpw.js +1 -0
- package/dist/assets/{Autocomplete-CtKfl8OV.js → Autocomplete-DqOPJmfP.js} +1 -1
- package/dist/assets/{Avatar-BuTYVz6S.js → Avatar-CC2uCgJO.js} +1 -1
- package/dist/assets/{ButtonGroup-9mTO_MUt.js → ButtonGroup-DVkbPyCf.js} +1 -1
- package/dist/assets/{CSSTransition-VPmtoKE7.js → CSSTransition-CAyoWadY.js} +1 -1
- package/dist/assets/CheckCircle-ne5PaInr.js +1 -0
- package/dist/assets/ChevronLeft-CzFyG6B9.js +1 -0
- package/dist/assets/ChevronRight-D28wkT_7.js +1 -0
- package/dist/assets/Delete-W0XHLr5E.js +1 -0
- package/dist/assets/DeleteOutline-CBAPet9Y.js +1 -0
- package/dist/assets/DialogContentText-DF6wXq4v.js +1 -0
- package/dist/assets/Done-BMgw3G29.js +1 -0
- package/dist/assets/Download-CWu1DNgF.js +1 -0
- package/dist/assets/{EditIcon-D5uy6dXe.js → EditIcon-L7k3tqrQ.js} +1 -1
- package/dist/assets/Error-DewSa72i.js +1 -0
- package/dist/assets/ExpandMore-dR0m3faK.js +1 -0
- package/dist/assets/FormControl-C3U9aSdK.js +1 -0
- package/dist/assets/{FormControlLabel-Ka9Y3VW4.js → FormControlLabel-uhzkWhIR.js} +1 -1
- package/dist/assets/FormGroup-zmk2zBRp.js +1 -0
- package/dist/assets/{Google-fmIzZ4SE.js → Google-BJOVX6-i.js} +1 -1
- package/dist/assets/{Grid-CLg9BKgo.js → Grid-CRcYquo8.js} +1 -1
- package/dist/assets/HelpOutline-1C4eFcXT.js +1 -0
- package/dist/assets/Hidden-C6Nsczh0.js +1 -0
- package/dist/assets/InfoOutlined-0F0dMk0M.js +1 -0
- package/dist/assets/{InputAdornment-7bcT-OxU.js → InputAdornment-HjZlszj5.js} +1 -1
- package/dist/assets/{LastPage-BNIPjfIv.js → LastPage-C8Ibu_ZS.js} +1 -1
- package/dist/assets/Launch-_9WY6qT8.js +1 -0
- package/dist/assets/LaunchOutlined-DpBWMSDU.js +1 -0
- package/dist/assets/{Link-Dgz_hg-A.js → Link-BHzX6Bty.js} +1 -1
- package/dist/assets/{ListItemButton-COVroopz.js → ListItemButton-Bg2hcpe4.js} +1 -1
- package/dist/assets/{ListSubheader-DoFPqSxT.js → ListSubheader-BnOsaMFL.js} +1 -1
- package/dist/assets/{LoadingButton-Cpsng3ic.js → LoadingButton-DHvQ4mj0.js} +1 -1
- package/dist/assets/{LockIcon-xMd6TgDT.js → LockIcon-BF2LVzIr.js} +1 -1
- package/dist/assets/Loop-DwW0YmEY.js +1 -0
- package/dist/assets/MarkEmailRead-BUgtVfuj.js +1 -0
- package/dist/assets/Menu-C0_eNw-R.js +1 -0
- package/dist/assets/MoreHoriz-B3eBOSmM.js +1 -0
- package/dist/assets/MoreVert-9FUIKqvo.js +1 -0
- package/dist/assets/OpenInNew-IfJ9_ovA.js +1 -0
- package/dist/assets/{Pagination-BdODbVsE.js → Pagination-KTMAbLPe.js} +1 -1
- package/dist/assets/PlayArrow-BzCvLnOA.js +1 -0
- package/dist/assets/{QuestionMarkCircle-CeLvEIhA.js → QuestionMarkCircle-Bp1qdiMj.js} +1 -1
- package/dist/assets/{RadioGroup-CkuUb_-r.js → RadioGroup-D6iB2v9N.js} +1 -1
- package/dist/assets/Search-CeQJr6Zd.js +1 -0
- package/dist/assets/{Select-BM5xijW7.js → Select-63T17LTs.js} +2 -2
- package/dist/assets/{ServerLogo-CocwN-L6.js → ServerLogo-BjD55kNo.js} +1 -1
- package/dist/assets/{Skeleton-BQ4gLbdR.js → Skeleton-Cguhg4Uf.js} +5 -5
- package/dist/assets/{Stack-690-8aHU.js → Stack-B2wvO5ch.js} +1 -1
- package/dist/assets/{Stepper-DPFFvB9h.js → Stepper-Cf6EXzKT.js} +1 -1
- package/dist/assets/{TextField-CFRK87D0.js → TextField-DaxOve82.js} +1 -1
- package/dist/assets/{Toolbar-Ba22YRhW.js → Toolbar-CbY6pPMn.js} +1 -1
- package/dist/assets/ViewColumn-BSkUFzQn.js +1 -0
- package/dist/assets/ViewList-BJW4-xJh.js +1 -0
- package/dist/assets/{_createAggregator-Ct5VkIH5.js → _createAggregator-gmWpxOiT.js} +1 -1
- package/dist/assets/access-control-hkwSmrDz.js +13 -0
- package/dist/assets/{actions-R7d7-bh3.js → actions-mviDIL98.js} +1 -1
- package/dist/assets/{add-component-core-qARkFBQB.js → add-component-core-D8ycTCOD.js} +10 -10
- package/dist/assets/add-resource-Dvlc6tV9.js +1 -0
- package/dist/assets/{addon-BJli1WRW.js → addon-CBWbLYEt.js} +1 -1
- package/dist/assets/{analytics-B3iUwhYK.js → analytics-DEYYvSpr.js} +7 -7
- package/dist/assets/api-09lpjN_y.js +1 -0
- package/dist/assets/{ar-7AvHBDLJ.js → ar-BENken66.js} +1 -1
- package/dist/assets/audit-logs-CKasQ1r7.js +58 -0
- package/dist/assets/{base32-Mo2B3fHT.js → base32-BodeVrwr.js} +1 -1
- package/dist/assets/{branding-BThKyvoW.js → branding-C6L3eHHi.js} +2 -2
- package/dist/assets/bundle-avatar-DGCY6XtV.js +1 -0
- package/dist/assets/{button-eTEsJSJ0.js → button-_kh3esRx.js} +1 -1
- package/dist/assets/{click-to-copy-CkFI8a1W.js → click-to-copy-Dhz68Zb7.js} +1 -1
- package/dist/assets/{complete-Bb-6z_26.js → complete-CbF_9acR.js} +4 -4
- package/dist/assets/{component-kGv-hUvT.js → component-TW3Q8q-H.js} +2 -2
- package/dist/assets/{config-BVYueZpV.js → config-DOKBlczF.js} +2 -2
- package/dist/assets/config-NLq72VC7.js +1 -0
- package/dist/assets/{config-navigation-NUbYVs4N.js → config-navigation-BrZYJfdX.js} +5 -5
- package/dist/assets/config-space-CgNK0LkG.js +1 -0
- package/dist/assets/{confirm-CIF7Vu-X.js → confirm-CgBlPewa.js} +1 -1
- package/dist/assets/{connect-Dj-BrpmM.js → connect-BLWlkmzZ.js} +2 -2
- package/dist/assets/connect-BoJDz_r9.js +1 -0
- package/dist/assets/{connect-to-ZJr8_Nq9.js → connect-to-Bjjro7dm.js} +1 -1
- package/dist/assets/{content-layout-DSpN7kL2.js → content-layout-De6X9MfH.js} +1 -1
- package/dist/assets/{dashboard-BUsMb2Wm.js → dashboard-DNfo36ET.js} +7 -7
- package/dist/assets/{de-S6ufmRx0.js → de-C8d8saMJ.js} +1 -1
- package/dist/assets/{deprecate-W6wP2f1U.js → deprecate-C8CVzteH.js} +1 -1
- package/dist/assets/{did-address-DpP51eII.js → did-address-CQAHayeq.js} +1 -1
- package/dist/assets/domain-4tz_iUAg.js +9 -0
- package/dist/assets/domain-list-CSCowbSF.js +15 -0
- package/dist/assets/{email-DETfN-BC.js → email-B7GCHFcD.js} +3 -3
- package/dist/assets/emotion-cache.browser.esm-7imm0F3K.js +1 -0
- package/dist/assets/{es-Sth9cv6C.js → es-8ZzWXB3U.js} +1 -1
- package/dist/assets/exchange-passport-BMGoDnTe.js +1 -0
- package/dist/assets/{fallback-CTOpqcoo.js → fallback-xgYg9R2J.js} +1 -1
- package/dist/assets/form-text-input-D8gtQI8g.js +11 -0
- package/dist/assets/{format-error-jTY-wvGv.js → format-error-kGGriKiA.js} +2 -2
- package/dist/assets/{fr-BX6bo8e1.js → fr-CDmTLuDM.js} +1 -1
- package/dist/assets/{fuel-Dx06V-YR.js → fuel-NUdjiJCN.js} +1 -1
- package/dist/assets/{fullpage-Dz8PPWdq.js → fullpage-BVHpRAYk.js} +1 -1
- package/dist/assets/{hi-pYobKga6.js → hi-DfYUKMCb.js} +1 -1
- package/dist/assets/{home-BCoo1Guo.js → home-rJKruo1j.js} +1 -1
- package/dist/assets/{id-Xei40tOm.js → id-BeY7iur-.js} +1 -1
- package/dist/assets/{iframe-GN8AUKA4.js → iframe-Cv3PJcvz.js} +1 -1
- package/dist/assets/index-6GwWrwWj.js +16 -0
- package/dist/assets/{index-cIe0Ged1.js → index-B2zxMB5n.js} +1 -1
- package/dist/assets/{index-B019qXp1.js → index-BHrceiDz.js} +1 -1
- package/dist/assets/{index-BDxuBkP1.js → index-BIDxxb9t.js} +1 -1
- package/dist/assets/{index-COdSzYad.js → index-BILgagmI.js} +2 -2
- package/dist/assets/{index-Bs9TLgSC.js → index-BM0eHOUA.js} +2 -2
- package/dist/assets/index-BaLRQJTh.js +102 -0
- package/dist/assets/{index-B3pPqycI.js → index-BlTIDXDG.js} +1 -1
- package/dist/assets/{index-BidszMO2.js → index-BnljNGH7.js} +38 -38
- package/dist/assets/{index-W2CQmt_X.js → index-BxZgdCUX.js} +2 -2
- package/dist/assets/{index-delqLXRr.js → index-C-s0lU62.js} +8 -8
- package/dist/assets/index-CBp5iNXP.js +1 -0
- package/dist/assets/{index-4RJk4AiM.js → index-CETPQNRT.js} +1 -1
- package/dist/assets/{index-yi-655mj.js → index-CKLF9fLH.js} +1 -1
- package/dist/assets/{index-BjfhU-QW.js → index-CMY8zSjT.js} +1 -1
- package/dist/assets/{index-ZPFypmuO.js → index-CTGtgEeG.js} +1 -1
- package/dist/assets/{index-BXHMtAUn.js → index-C_vk9fqw.js} +2 -2
- package/dist/assets/{index-q1m8Euwz.js → index-CuHWguJg.js} +1 -1
- package/dist/assets/{index-BxKrUgd9.js → index-Cu_bNPbk.js} +70 -70
- package/dist/assets/index-D1YHjvRT.js +4 -0
- package/dist/assets/{index-CG1XIXZC.js → index-D1YU1vFk.js} +1 -1
- package/dist/assets/{index-BzVm0XuZ.js → index-D2d4qfN2.js} +1 -1
- package/dist/assets/{index-UEoZJA9L.js → index-DAKGZhdR.js} +1 -1
- package/dist/assets/index-DQrMXKph.js +1 -0
- package/dist/assets/{index-CYQV6023.js → index-DToO2H3Q.js} +12 -12
- package/dist/assets/{index-DgonWrzm.js → index-DeYzXL4z.js} +4 -4
- package/dist/assets/{index-BP0LEaeg.js → index-DpZHKufu.js} +8 -8
- package/dist/assets/index-DqjLLD7P.js +5 -0
- package/dist/assets/{index-CjkNshyI.js → index-Dt4OruAC.js} +1 -1
- package/dist/assets/{index-B_EeAcSB.js → index-HYjTpFy9.js} +1 -1
- package/dist/assets/index-J3ZVv3j-.js +316 -0
- package/dist/assets/{index-rA_BKM5G.js → index-MtDT2QJN.js} +3 -3
- package/dist/assets/{index-8OiEpVkg.js → index-ag_Qlo60.js} +1 -1
- package/dist/assets/{index-B3Z8DzsY.js → index-mFPL7bdj.js} +3 -3
- package/dist/assets/{index-Db_Y81_-.js → index-nKobfUQ1.js} +1 -1
- package/dist/assets/{invitation-BPrK4inJ.js → invitation-DLNLgy6r.js} +5 -5
- package/dist/assets/invite-DPYR6t3s.js +5 -0
- package/dist/assets/{isEmail-BnC4loew.js → isEmail-i2tngnJi.js} +1 -1
- package/dist/assets/{issue-passport-573OuQnm.js → issue-passport-CBrIp3jc.js} +1 -1
- package/dist/assets/item-Brjh4PLo.js +1 -0
- package/dist/assets/{ja-DG0a06x8.js → ja-DvJTZg_Q.js} +1 -1
- package/dist/assets/{jss-plugin-props-sort.esm-Bp0MqRVc.js → jss-plugin-props-sort.esm-BX_bur4g.js} +4 -4
- package/dist/assets/{ko-BBC-RcU5.js → ko-C1lnK-Gx.js} +1 -1
- package/dist/assets/{launch-result-message-4m30f0Ag.js → launch-result-message-DF58OHNC.js} +1 -1
- package/dist/assets/{layout-Btp-_hcD.js → layout-BZwnld0E.js} +2 -2
- package/dist/assets/{list-header-DQEePd_T.js → list-header-DKFtTh4o.js} +1 -1
- package/dist/assets/localization-DIaD7pty.js +1 -0
- package/dist/assets/{log-DGIf8qzM.js → log-DcFRCLCX.js} +1 -1
- package/dist/assets/login-Bf5SQlPn.js +1 -0
- package/dist/assets/login-oauth-callback-BU7Pl33l.js +1 -0
- package/dist/assets/{logo-uploader-CC8WqbW-.js → logo-uploader-BbCcpszA.js} +4 -4
- package/dist/assets/{lost-passport-D_HnDqKr.js → lost-passport-D3RvUegp.js} +4 -4
- package/dist/assets/{lottie-react.esm-CtltdV0t.js → lottie-react.esm-ZH4Wk5XO.js} +1 -1
- package/dist/assets/notifications-BkSUBEzY.js +65 -0
- package/dist/assets/{open-window-CmBy5HkH.js → open-window-CSdTLwaf.js} +1 -1
- package/dist/assets/overview-DXC_j46y.js +12 -0
- package/dist/assets/{page-header-B5a7RE0E.js → page-header-Cri_UHX5.js} +1 -1
- package/dist/assets/{permission-CBfa-qlX.js → permission-DSn8EOQ9.js} +1 -1
- package/dist/assets/{preferences-CuRLxM0K.js → preferences-JFVWkPL4.js} +1 -1
- package/dist/assets/{pt-CNmFfxJU.js → pt-C86mXB8Z.js} +1 -1
- package/dist/assets/publish-resource-gk91W1J0.js +1 -0
- package/dist/assets/{raf-schd.esm-KaxPdV64.js → raf-schd.esm-CpouI05w.js} +1 -1
- package/dist/assets/{react-beautiful-dnd.esm-BlBywA4z.js → react-beautiful-dnd.esm-ChA2xoay.js} +1 -1
- package/dist/assets/refType-BXcUP-YS.js +1 -0
- package/dist/assets/{resource-dialog-DpLtB_Fw.js → resource-dialog-DZPqi5pw.js} +1 -1
- package/dist/assets/{ru-BVNv9w91.js → ru-Dxm-iAqn.js} +1 -1
- package/dist/assets/sdk-neE1aE7y.js +1 -0
- package/dist/assets/{selector-Drr6pXp9.js → selector--uPvisem.js} +4 -4
- package/dist/assets/session-D7-00CVs.js +1 -0
- package/dist/assets/{setup-cPNeqLVK.js → setup-CMaryrU8.js} +3 -3
- package/dist/assets/{shorten-label-DK0L2sJV.js → shorten-label-uAzGTCBy.js} +1 -1
- package/dist/assets/{simple-select-CHsQAOYZ.js → simple-select-M9sKVVQT.js} +1 -1
- package/dist/assets/{slicedToArray-n9LJBwV4.js → slicedToArray-CHm_9UsL.js} +2 -2
- package/dist/assets/{start-CcvndivR.js → start-D5P3Y_Mp.js} +1 -1
- package/dist/assets/{step-actions-D_1mpc4C.js → step-actions-DRDtE9i9.js} +2 -2
- package/dist/assets/studio-DDRR9uTH.js +6 -0
- package/dist/assets/{switch-control-2C3bwebR.js → switch-control-C8d_eiWi.js} +1 -1
- package/dist/assets/{th-CObnQ6OH.js → th-BamIf1b8.js} +1 -1
- package/dist/assets/{toUpper-DtTJYJCz.js → toUpper-Bq-NIfax.js} +1 -1
- package/dist/assets/{transfer-BNPHc5-e.js → transfer-COMtxr-_.js} +2 -2
- package/dist/assets/{trim-Boaje3e9.js → trim-Bn0r8NiZ.js} +1 -1
- package/dist/assets/{uniqBy-B2B_OSuq.js → uniqBy-Baa3ApX9.js} +1 -1
- package/dist/assets/unsubscribe-BUf0fqE6.js +1 -0
- package/dist/assets/{url-join-aL0dlRwK.js → url-join-BUPuIN5Z.js} +1 -1
- package/dist/assets/use-mobile-BexDu-6x.js +1 -0
- package/dist/assets/use-mobile-CUJBViwc.js +1 -0
- package/dist/assets/{useAsync-B5aCa8BU.js → useAsync-DlT-wYlz.js} +1 -1
- package/dist/assets/{useFormControl-De83T2k8.js → useFormControl-CW2PoJes.js} +1 -1
- package/dist/assets/{useLocalStorage-Cg4UWbtJ.js → useLocalStorage-BfN8jDuG.js} +1 -1
- package/dist/assets/{useSetState-C5EefhmT.js → useSetState-CKmZy4S9.js} +1 -1
- package/dist/assets/useSlot-BDokg4R-.js +1 -0
- package/dist/assets/{useSlotProps-9EZsnKiK.js → useSlotProps-BvV0G0yb.js} +1 -1
- package/dist/assets/{useThemeProps-DFbMvLjq.js → useThemeProps-28x2bH1r.js} +1 -1
- package/dist/assets/user-center-D6WQO8xG.js +1 -0
- package/dist/assets/user-sessions-DRnCKb0z.js +1 -0
- package/dist/assets/util-ZRcOJEuz.js +1 -0
- package/dist/assets/{vi-DPE1cpvE.js → vi-CTEgHnG8.js} +1 -1
- package/dist/assets/wrap-locale-Bsx6I5ww.js +1 -0
- package/dist/assets/{zh-ZJh718gR.js → zh-C9pcKSvk.js} +1 -1
- package/dist/assets/{zh-tw-q3KEUdcz.js → zh-tw-CuhSzmQN.js} +1 -1
- package/dist/index.html +1 -1
- package/dist/service-worker.js +1 -1
- package/package.json +26 -25
- package/api/middlewares/verify-federated-call.js +0 -36
- package/dist/assets/Add-DtejxYv7.js +0 -1
- package/dist/assets/ArrowDropDown-DLu5ghJ6.js +0 -1
- package/dist/assets/CheckCircle-BvTAg_Vb.js +0 -1
- package/dist/assets/ChevronLeft-CogeEPev.js +0 -1
- package/dist/assets/ChevronRight-BATWClLP.js +0 -1
- package/dist/assets/Delete-BvK_hDyw.js +0 -1
- package/dist/assets/DeleteOutline-CFkN2u6G.js +0 -1
- package/dist/assets/DialogContentText-BSTFqlB8.js +0 -1
- package/dist/assets/Done-BCayGyaP.js +0 -1
- package/dist/assets/Download-3v1IPpRg.js +0 -1
- package/dist/assets/Error-KMHXOqQS.js +0 -1
- package/dist/assets/ExpandMore-XeiYcXA0.js +0 -1
- package/dist/assets/FormControl-D9UzJGr3.js +0 -1
- package/dist/assets/FormGroup-BqZ71koG.js +0 -1
- package/dist/assets/HelpOutline-D-mVzldg.js +0 -1
- package/dist/assets/Hidden-B_FCIv2F.js +0 -1
- package/dist/assets/InfoOutlined-fhivWooJ.js +0 -1
- package/dist/assets/Launch-B6-uAhbQ.js +0 -1
- package/dist/assets/LaunchOutlined-BEenLVbN.js +0 -1
- package/dist/assets/Loop-tJ6uJkRI.js +0 -1
- package/dist/assets/MarkEmailRead-BNHtpgz2.js +0 -1
- package/dist/assets/Menu-CkD81HZ5.js +0 -1
- package/dist/assets/MoreHoriz-qqmi4YRC.js +0 -1
- package/dist/assets/MoreVert-BZZ4IBOf.js +0 -1
- package/dist/assets/OpenInNew-C5XvRsRC.js +0 -1
- package/dist/assets/PlayArrow-Cn0cfGNW.js +0 -1
- package/dist/assets/Search-DXRr3XZy.js +0 -1
- package/dist/assets/ViewColumn-GTnSFOFd.js +0 -1
- package/dist/assets/ViewList-BtVWmZJ0.js +0 -1
- package/dist/assets/access-control-BmMbklSe.js +0 -13
- package/dist/assets/add-resource-lnxpvPO7.js +0 -1
- package/dist/assets/api-lbSHYKYc.js +0 -1
- package/dist/assets/audit-logs-0TJ_0Mvw.js +0 -58
- package/dist/assets/bundle-avatar-CcIs5XOV.js +0 -1
- package/dist/assets/config-kysZ8p5u.js +0 -1
- package/dist/assets/config-space-BPpdFWKx.js +0 -1
- package/dist/assets/connect-DPIWGg69.js +0 -1
- package/dist/assets/domain-CcBPnmmR.js +0 -9
- package/dist/assets/domain-list-CVn1TPCl.js +0 -15
- package/dist/assets/emotion-cache.browser.esm-DkJEKl9I.js +0 -1
- package/dist/assets/exchange-passport-BetHiKY_.js +0 -1
- package/dist/assets/form-text-input-BUB_rL9o.js +0 -11
- package/dist/assets/index-B2fUK0Jg.js +0 -16
- package/dist/assets/index-BArNVkrG.js +0 -1
- package/dist/assets/index-CQSz6hXt.js +0 -316
- package/dist/assets/index-CRK13xk6.js +0 -102
- package/dist/assets/index-D_g2YpF8.js +0 -1
- package/dist/assets/index-De1VedzO.js +0 -5
- package/dist/assets/index-PD8enw5a.js +0 -4
- package/dist/assets/invite-VzUmhGJg.js +0 -5
- package/dist/assets/item-BoFU04RW.js +0 -1
- package/dist/assets/localization-BJhiRnk-.js +0 -1
- package/dist/assets/login-Cu5oiCaE.js +0 -1
- package/dist/assets/login-oauth-callback-Dim9h4c3.js +0 -1
- package/dist/assets/notifications-tGIsoEd6.js +0 -65
- package/dist/assets/overview-CmwcUtDq.js +0 -12
- package/dist/assets/publish-resource-aoq2ZIeT.js +0 -1
- package/dist/assets/refType-CNi4gHMp.js +0 -1
- package/dist/assets/sdk-CrAhZvgC.js +0 -1
- package/dist/assets/session-BGDxwrDP.js +0 -1
- package/dist/assets/studio-BdIpZDRv.js +0 -6
- package/dist/assets/unsubscribe-eud8OqTh.js +0 -1
- package/dist/assets/use-mobile-D7IK9xm6.js +0 -1
- package/dist/assets/use-mobile-TJQ6s1hH.js +0 -1
- package/dist/assets/useSlot-DebDFCUQ.js +0 -1
- package/dist/assets/user-center-BWtnQHWR.js +0 -1
- package/dist/assets/user-sessions-DTvyZm5S.js +0 -1
- package/dist/assets/util-BBKZBp8H.js +0 -1
- package/dist/assets/wrap-locale-Ci8gmRb6.js +0 -1
package/api/routes/federated.js
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
const { WELLKNOWN_SERVICE_PATH_PREFIX, FEDERATED } = require('@abtnode/constant');
|
|
2
2
|
const { signV2 } = require('@arcblock/jwt');
|
|
3
|
-
const normalizePathPrefix = require('@abtnode/util/lib/normalize-path-prefix');
|
|
4
|
-
const cloneDeep = require('lodash/cloneDeep');
|
|
5
3
|
const isNil = require('lodash/isNil');
|
|
4
|
+
const pick = require('lodash/pick');
|
|
5
|
+
const remove = require('lodash/remove');
|
|
6
6
|
const pLimit = require('p-limit');
|
|
7
|
-
const
|
|
8
|
-
const { joinURL } = require('ufo');
|
|
7
|
+
const pMap = require('p-map');
|
|
9
8
|
|
|
10
|
-
const { LOGIN_PROVIDER } = require('@blocklet/constant');
|
|
9
|
+
const { LOGIN_PROVIDER, SIG_VERSION } = require('@blocklet/constant');
|
|
11
10
|
const { getAvatarByUrl, extractUserAvatar } = require('@abtnode/util/lib/user');
|
|
12
11
|
const { getApplicationInfo, messages } = require('@abtnode/auth/lib/auth');
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
const {
|
|
13
|
+
callFederated,
|
|
14
|
+
generateSiteInfo,
|
|
15
|
+
getFederatedSiteEnv,
|
|
16
|
+
safeGetFederated,
|
|
17
|
+
} = require('@abtnode/auth/lib/util/federated');
|
|
16
18
|
const { fromAppDid } = require('@arcblock/did-ext');
|
|
17
19
|
|
|
18
20
|
const logger = require('../libs/logger')('blocklet-services:federated');
|
|
19
|
-
const { api } = require('../libs/api');
|
|
20
21
|
const initJwt = require('../libs/jwt');
|
|
21
22
|
const { createTokenFn, getDidConnectVersion } = require('../util');
|
|
22
23
|
const ensureBlocklet = require('../middlewares/ensure-blocklet');
|
|
23
|
-
const verifyFederatedCall = require('../middlewares/verify-federated-call');
|
|
24
24
|
const {
|
|
25
25
|
getUserAvatarUrl,
|
|
26
26
|
getFederatedMaster,
|
|
@@ -28,10 +28,10 @@ const {
|
|
|
28
28
|
getTrustedDomains,
|
|
29
29
|
} = require('../util/federated');
|
|
30
30
|
const { declareAccount, migrateAccount } = require('../services/oauth');
|
|
31
|
+
const { checkFederatedCall } = require('../middlewares/check-federated');
|
|
31
32
|
|
|
32
33
|
const PREFIX = WELLKNOWN_SERVICE_PATH_PREFIX;
|
|
33
|
-
|
|
34
|
-
const prefix = `${PREFIX}/api/federated`;
|
|
34
|
+
const prefixApi = `${PREFIX}/api/federated`;
|
|
35
35
|
|
|
36
36
|
function getAuditLogActorByFederatedSite(blocklet) {
|
|
37
37
|
return {
|
|
@@ -145,96 +145,76 @@ async function syncDisconnectAccount(user, { node, teamDid, blocklet }) {
|
|
|
145
145
|
/**
|
|
146
146
|
* member 站点向 master 站点请求拉取一个用户信息
|
|
147
147
|
*/
|
|
148
|
-
async function pullUserAccount(user, { node, teamDid, blocklet }) {
|
|
149
|
-
const { did } = user;
|
|
150
|
-
const currentUser = await node.getUser({
|
|
151
|
-
teamDid,
|
|
152
|
-
user: {
|
|
153
|
-
did,
|
|
154
|
-
},
|
|
155
|
-
options: {
|
|
156
|
-
enableConnectedAccount: true,
|
|
157
|
-
},
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
if (!currentUser) return null;
|
|
161
148
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
'pk',
|
|
165
|
-
'fullName',
|
|
166
|
-
'email',
|
|
167
|
-
'phone',
|
|
168
|
-
'url',
|
|
169
|
-
'remark',
|
|
170
|
-
'sourceProvider',
|
|
171
|
-
'locale',
|
|
172
|
-
'approved',
|
|
173
|
-
'extra',
|
|
174
|
-
'sourceAppPid',
|
|
175
|
-
'inviter',
|
|
176
|
-
'emailVerified',
|
|
177
|
-
'phoneVerified',
|
|
178
|
-
]);
|
|
179
|
-
syncUser.avatar = getUserAvatarUrl(currentUser.avatar, blocklet);
|
|
180
|
-
syncUser.email = syncUser.email || '';
|
|
181
|
-
syncUser.connectedAccounts = currentUser.connectedAccounts.map((x) => {
|
|
182
|
-
const connectAccount = pick(x, ['did', 'pk', 'provider', 'id', 'userInfo']);
|
|
183
|
-
if (!connectAccount.id) {
|
|
184
|
-
delete connectAccount.id;
|
|
185
|
-
}
|
|
186
|
-
return connectAccount;
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
return syncUser;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
const syncFnMaps = {
|
|
149
|
+
const syncUserFnMaps = {
|
|
150
|
+
// 用户更换 profile 通知
|
|
193
151
|
switchProfile: syncSwitchProfile,
|
|
152
|
+
// 用户绑定第三方登录
|
|
194
153
|
connectAccount: syncConnectAccount,
|
|
154
|
+
// 用户解绑第三方登录
|
|
195
155
|
disconnectAccount: syncDisconnectAccount,
|
|
196
|
-
pullAccount: pullUserAccount,
|
|
197
156
|
};
|
|
198
157
|
|
|
199
158
|
module.exports = {
|
|
200
159
|
init(server, node, options) {
|
|
160
|
+
// =============================== 以下为公开的接口 ===============================
|
|
161
|
+
|
|
162
|
+
// 获取当前站点所有可信的域名
|
|
163
|
+
server.get(`${prefixApi}/getTrustedDomains`, ensureBlocklet(), async (req, res) => {
|
|
164
|
+
const { blocklet } = req;
|
|
165
|
+
const result = await getTrustedDomains({ node, req, blocklet });
|
|
166
|
+
res.json(result);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
server.get(`${prefixApi}/env`, ensureBlocklet(), (req, res) => {
|
|
170
|
+
const { blocklet } = req;
|
|
171
|
+
const masterSite = getFederatedMaster(blocklet);
|
|
172
|
+
const result = {
|
|
173
|
+
sigVersion: SIG_VERSION.DEFAULT,
|
|
174
|
+
masterAppUrl: masterSite?.appUrl,
|
|
175
|
+
};
|
|
176
|
+
res.json(result);
|
|
177
|
+
});
|
|
178
|
+
|
|
201
179
|
// step 1 申请加入(member 向 master 申请)
|
|
202
|
-
|
|
203
|
-
|
|
180
|
+
// member 发起(master 不能发起),master 处理该路由
|
|
181
|
+
server.post(`${prefixApi}/join`, ensureBlocklet(), async (req, res) => {
|
|
204
182
|
const { blocklet } = req;
|
|
205
183
|
const { site } = req.body;
|
|
206
184
|
const teamDid = blocklet.appPid;
|
|
207
185
|
|
|
208
|
-
const federated =
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
186
|
+
const federated = safeGetFederated(blocklet, { isMaster: true });
|
|
187
|
+
const exists = federated.sites.find((x) => x.appPid === site.appPid);
|
|
188
|
+
// 1. 检查当前站点群的数据中是否有目标站点
|
|
189
|
+
if (exists) {
|
|
190
|
+
logger.error("already in a federated site group, don't need join again", {
|
|
191
|
+
teamDid,
|
|
192
|
+
site,
|
|
193
|
+
});
|
|
194
|
+
res.status(401).send("already in a federated site group, don't need join again");
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// 1. 检查目标站点自身是否已加入其他的站点群
|
|
199
|
+
const siteEnv = await getFederatedSiteEnv({
|
|
200
|
+
site: {
|
|
201
|
+
appUrl: site.appUrl,
|
|
212
202
|
},
|
|
213
|
-
sites: [],
|
|
214
203
|
});
|
|
204
|
+
if (siteEnv.masterAppUrl) {
|
|
205
|
+
logger.error('already in a federated site group, please quit federated site group first', {
|
|
206
|
+
siteEnv,
|
|
207
|
+
site,
|
|
208
|
+
});
|
|
209
|
+
res.status(401).send('already in a federated site group, please quit federated site group first');
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// 当前站点未形成站点群,需要先生成 master 的相关信息
|
|
215
214
|
if (federated.sites.length === 0) {
|
|
216
215
|
const nodeInfo = await req.getNodeInfo();
|
|
217
|
-
const blockletInfo = await req.getBlockletInfo();
|
|
218
216
|
const domainAliases = await node.getBlockletDomainAliases({ blocklet, nodeInfo });
|
|
219
|
-
const masterSite = {
|
|
220
|
-
appId: blocklet.appDid,
|
|
221
|
-
appPid: teamDid,
|
|
222
|
-
aliasDid: (blocklet.migratedFrom || []).map((item) => item.appDid),
|
|
223
|
-
appName: blockletInfo.name,
|
|
224
|
-
appDescription: blockletInfo.description,
|
|
225
|
-
appUrl: blockletInfo.appUrl,
|
|
226
|
-
aliasDomain: domainAliases.map((item) => item.value),
|
|
227
|
-
appLogo:
|
|
228
|
-
blocklet.environmentObj.BLOCKLET_APP_LOGO ||
|
|
229
|
-
normalizePathPrefix(`${WELLKNOWN_SERVICE_PATH_PREFIX}/blocklet/logo`) ||
|
|
230
|
-
'/',
|
|
231
|
-
appLogoRect: blocklet.environmentObj.BLOCKLET_APP_LOGO_RECT,
|
|
232
|
-
did: blockletInfo.permanentWallet.address,
|
|
233
|
-
pk: blockletInfo.permanentWallet.publicKey,
|
|
234
|
-
serverId: nodeInfo.did,
|
|
235
|
-
serverVersion: nodeInfo.version,
|
|
236
|
-
version: blocklet.meta.version,
|
|
237
|
-
};
|
|
217
|
+
const masterSite = await generateSiteInfo({ blocklet, domainAliases, nodeInfo });
|
|
238
218
|
federated.sites = [masterSite];
|
|
239
219
|
}
|
|
240
220
|
|
|
@@ -247,8 +227,8 @@ module.exports = {
|
|
|
247
227
|
});
|
|
248
228
|
}
|
|
249
229
|
// member 申请后,将 member 展示在列表中
|
|
250
|
-
//
|
|
251
|
-
const
|
|
230
|
+
// 更新的是自己,此时还不用通知其他的子成员站点
|
|
231
|
+
const newBlockletState = await node.setFederated({
|
|
252
232
|
did: teamDid,
|
|
253
233
|
config: federated,
|
|
254
234
|
});
|
|
@@ -260,195 +240,469 @@ module.exports = {
|
|
|
260
240
|
context: {
|
|
261
241
|
user: getAuditLogActorByFederatedSite(site),
|
|
262
242
|
},
|
|
263
|
-
result:
|
|
243
|
+
result: newBlockletState,
|
|
264
244
|
},
|
|
265
245
|
node
|
|
266
246
|
);
|
|
267
247
|
|
|
268
|
-
// 将新增的数据返回给 member
|
|
248
|
+
// 将新增的数据返回给 member,只返回 master 和申请成员,待审核通过后,才能获取所有的成员站点信息
|
|
249
|
+
const result = federated.sites.filter((x) => [teamDid, site.appPid].includes(x.appPid));
|
|
269
250
|
res.json({
|
|
270
|
-
sites:
|
|
251
|
+
sites: result,
|
|
271
252
|
});
|
|
272
253
|
});
|
|
273
254
|
|
|
274
|
-
//
|
|
275
|
-
server.post(`${prefix}/quit`, ensureBlocklet(), verifyFederatedCall(), async (req, res) => {
|
|
276
|
-
const { blocklet } = req;
|
|
277
|
-
const { memberPid } = req.body.verifyData;
|
|
278
|
-
const teamDid = blocklet.appPid;
|
|
255
|
+
// =============================== 以下为需要鉴权的接口 ===============================
|
|
279
256
|
|
|
280
|
-
|
|
281
|
-
config: {
|
|
282
|
-
appId: blocklet.appDid,
|
|
283
|
-
appPid: teamDid,
|
|
284
|
-
},
|
|
285
|
-
sites: [],
|
|
286
|
-
});
|
|
257
|
+
// ------------------------------- 以下为仅 member 可以发起的请求 -------------------------------
|
|
287
258
|
|
|
288
|
-
|
|
259
|
+
// member 向 master 请求退出统一登录,然后 master 把情况同步给所有成员站点
|
|
260
|
+
// member 发起(master 不能发起),master 处理该路由 (member -> master)
|
|
261
|
+
server.post(
|
|
262
|
+
`${prefixApi}/quit`,
|
|
263
|
+
ensureBlocklet(),
|
|
264
|
+
checkFederatedCall({ mode: 'memberToMaster', allowStatus: ['approved', 'rejected', 'pending'] }),
|
|
265
|
+
async (req, res) => {
|
|
266
|
+
const { blocklet, verifySite } = req;
|
|
267
|
+
const teamDid = blocklet.appPid;
|
|
289
268
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
269
|
+
const federated = safeGetFederated(blocklet, { isMaster: true });
|
|
270
|
+
const [removedSite] = remove(federated.sites, (item) => item.appPid === verifySite.appPid);
|
|
271
|
+
|
|
272
|
+
const { permanentWallet } = await req.getBlockletInfo();
|
|
273
|
+
const limitSync = pLimit(FEDERATED.SYNC_LIMIT);
|
|
274
|
+
|
|
275
|
+
const waitingList = federated.sites
|
|
276
|
+
// 排除 master 和请求退出的 member
|
|
277
|
+
.filter((item) => ![teamDid, verifySite.appPid].includes(item.appPid))
|
|
278
|
+
.map((item) => {
|
|
279
|
+
return limitSync(async () => {
|
|
280
|
+
// NOTICE: 即使通知其他 member 失败了,也不影响来源 member 退出统一登录
|
|
281
|
+
try {
|
|
282
|
+
await callFederated({
|
|
283
|
+
action: 'sync',
|
|
284
|
+
site: item,
|
|
285
|
+
data: { sites: [{ action: 'delete', appPid: verifySite.appPid }] },
|
|
286
|
+
permanentWallet,
|
|
287
|
+
});
|
|
288
|
+
} catch (error) {
|
|
289
|
+
logger.error('Failed to sync federated member', {
|
|
290
|
+
error,
|
|
291
|
+
did: blocklet.appDid,
|
|
292
|
+
action: 'quit',
|
|
293
|
+
siteItem: item,
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
});
|
|
315
297
|
});
|
|
298
|
+
await Promise.all(waitingList);
|
|
299
|
+
|
|
300
|
+
const newState = await node.setFederated({
|
|
301
|
+
did: teamDid,
|
|
302
|
+
config: federated,
|
|
316
303
|
});
|
|
317
|
-
await Promise.all(waitingList);
|
|
318
304
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
305
|
+
await node.createAuditLog(
|
|
306
|
+
{
|
|
307
|
+
action: 'quitFederated',
|
|
308
|
+
args: { memberSite: removedSite, teamDid },
|
|
309
|
+
context: {
|
|
310
|
+
user: getAuditLogActorByFederatedSite(removedSite),
|
|
311
|
+
},
|
|
312
|
+
result: newState,
|
|
313
|
+
},
|
|
314
|
+
node
|
|
315
|
+
);
|
|
323
316
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
317
|
+
res.status(204).send();
|
|
318
|
+
}
|
|
319
|
+
);
|
|
320
|
+
|
|
321
|
+
// member 向 master 申请第三方账号的 migrate
|
|
322
|
+
// member 发起(master 不能发起),master 处理该路由 (member -> master)
|
|
323
|
+
server.post(
|
|
324
|
+
`${prefixApi}/migrateAccount`,
|
|
325
|
+
ensureBlocklet(),
|
|
326
|
+
checkFederatedCall({ mode: 'memberToMaster' }),
|
|
327
|
+
async (req, res) => {
|
|
328
|
+
const { blocklet, verifySite, verifyData } = req;
|
|
329
|
+
const { did: teamDid, wallet: blockletWallet } = await req.getBlockletInfo();
|
|
330
|
+
const { fromUserDid, toUserDid, toUserPk } = verifyData;
|
|
331
|
+
const oauthUser = await node.getUser({ teamDid, user: { did: fromUserDid } });
|
|
332
|
+
const connectedAccounts = oauthUser?.connectedAccounts || [];
|
|
333
|
+
const sourceProvider = oauthUser?.sourceProvider;
|
|
334
|
+
const oauthAccount = connectedAccounts.find((item) => item.provider === sourceProvider);
|
|
335
|
+
const userWallet = fromAppDid(oauthAccount.id, blockletWallet.secretKey);
|
|
336
|
+
|
|
337
|
+
const bindUser = {
|
|
338
|
+
did: toUserDid,
|
|
339
|
+
pk: toUserPk,
|
|
340
|
+
};
|
|
341
|
+
await declareAccount({ wallet: userWallet, blocklet });
|
|
342
|
+
await migrateAccount({ wallet: userWallet, blocklet, user: bindUser });
|
|
343
|
+
await node.createAuditLog(
|
|
344
|
+
{
|
|
345
|
+
action: 'migrateFederatedAccount',
|
|
346
|
+
args: { fromUserDid, toUserDid, callerSite: verifySite, teamDid },
|
|
347
|
+
context: {
|
|
348
|
+
user: getAuditLogActorByFederatedSite(verifySite),
|
|
349
|
+
},
|
|
330
350
|
},
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
351
|
+
node
|
|
352
|
+
);
|
|
353
|
+
res.status(204).send();
|
|
354
|
+
}
|
|
355
|
+
);
|
|
335
356
|
|
|
336
|
-
|
|
337
|
-
|
|
357
|
+
// member 向 master 索取 delegation 和 roles 列表
|
|
358
|
+
// member 发起(master 不能发起),master 处理该路由 (member -> master)
|
|
359
|
+
server.post(
|
|
360
|
+
`${prefixApi}/getMasterAuthorization`,
|
|
361
|
+
ensureBlocklet(),
|
|
362
|
+
checkFederatedCall({ mode: 'memberToMaster' }),
|
|
363
|
+
async (req, res) => {
|
|
364
|
+
const { blocklet, verifySite } = req;
|
|
365
|
+
const teamDid = blocklet.appPid;
|
|
366
|
+
const { permanentWallet } = await req.getBlockletInfo();
|
|
367
|
+
const delegation = signV2(permanentWallet.address, permanentWallet.secretKey, {
|
|
368
|
+
// HACK: 钱包签名使用的始终是最新的,这里的 dalegation 也保持 agentDid 就是当前应用最新的 did(appId)
|
|
369
|
+
agentDid: `did:abt:${verifySite.appId}`,
|
|
370
|
+
permissions: [
|
|
371
|
+
{
|
|
372
|
+
role: 'DIDConnectAgent',
|
|
373
|
+
claims: [
|
|
374
|
+
'authPrincipal',
|
|
375
|
+
'profile',
|
|
376
|
+
'signature',
|
|
377
|
+
'prepareTx',
|
|
378
|
+
'agreement',
|
|
379
|
+
'verifiableCredential',
|
|
380
|
+
'asset',
|
|
381
|
+
'assetOrVC',
|
|
382
|
+
'keyPair',
|
|
383
|
+
// 'encryptionKey', // 备份还原应用时使用
|
|
384
|
+
],
|
|
385
|
+
},
|
|
386
|
+
],
|
|
387
|
+
exp: Math.floor(new Date().getTime() / 1000) + 86400 * 365 * 100, // valid for 100 year
|
|
388
|
+
});
|
|
389
|
+
const roleList = await node.getRoles({ teamDid });
|
|
390
|
+
const roles = roleList.map((item) => pick(item, ['name', 'title', 'description']));
|
|
391
|
+
res.json({ delegation, roles });
|
|
392
|
+
}
|
|
393
|
+
);
|
|
338
394
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
395
|
+
server.post(
|
|
396
|
+
`${prefixApi}/pullFederatedSites`,
|
|
397
|
+
ensureBlocklet(),
|
|
398
|
+
checkFederatedCall({ mode: 'memberToMaster' }),
|
|
399
|
+
(req, res) => {
|
|
400
|
+
const { blocklet } = req;
|
|
401
|
+
const federated = safeGetFederated(blocklet, { isMaster: true });
|
|
402
|
+
const result = federated.sites.filter((x) => !['pending'].includes(x.status));
|
|
403
|
+
res.json(result);
|
|
404
|
+
}
|
|
405
|
+
);
|
|
344
406
|
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
})
|
|
349
|
-
|
|
350
|
-
{
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
407
|
+
server.post(
|
|
408
|
+
`${prefixApi}/pullAccount`,
|
|
409
|
+
ensureBlocklet(),
|
|
410
|
+
checkFederatedCall({ mode: 'memberToMaster' }),
|
|
411
|
+
async (req, res) => {
|
|
412
|
+
const { blocklet, verifyData } = req;
|
|
413
|
+
const { users } = verifyData;
|
|
414
|
+
const result = await pMap(
|
|
415
|
+
users,
|
|
416
|
+
async (user) => {
|
|
417
|
+
const teamDid = blocklet.appPid;
|
|
418
|
+
const currentUser = await node.getUser({
|
|
419
|
+
teamDid,
|
|
420
|
+
user: {
|
|
421
|
+
did: user.did,
|
|
422
|
+
},
|
|
423
|
+
options: {
|
|
424
|
+
enableConnectedAccount: true,
|
|
425
|
+
},
|
|
426
|
+
});
|
|
427
|
+
|
|
428
|
+
if (!currentUser) return null;
|
|
429
|
+
|
|
430
|
+
const syncUser = pick(currentUser, [
|
|
431
|
+
'did',
|
|
432
|
+
'pk',
|
|
433
|
+
'fullName',
|
|
434
|
+
'email',
|
|
435
|
+
'phone',
|
|
436
|
+
'url',
|
|
437
|
+
'remark',
|
|
438
|
+
'sourceProvider',
|
|
439
|
+
'locale',
|
|
440
|
+
'approved',
|
|
441
|
+
'extra',
|
|
442
|
+
'sourceAppPid',
|
|
443
|
+
'inviter',
|
|
444
|
+
'emailVerified',
|
|
445
|
+
'phoneVerified',
|
|
446
|
+
]);
|
|
447
|
+
syncUser.avatar = getUserAvatarUrl(currentUser.avatar, blocklet);
|
|
448
|
+
syncUser.email = syncUser.email || '';
|
|
449
|
+
syncUser.connectedAccounts = currentUser.connectedAccounts.map((x) => {
|
|
450
|
+
const connectAccount = pick(x, ['did', 'pk', 'provider', 'id', 'userInfo']);
|
|
451
|
+
if (!connectAccount.id) {
|
|
452
|
+
delete connectAccount.id;
|
|
453
|
+
}
|
|
454
|
+
return connectAccount;
|
|
455
|
+
});
|
|
456
|
+
return syncUser;
|
|
355
457
|
},
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
458
|
+
{ concurrency: FEDERATED.SYNC_LIMIT }
|
|
459
|
+
);
|
|
460
|
+
|
|
461
|
+
res.json(result);
|
|
462
|
+
}
|
|
463
|
+
);
|
|
464
|
+
|
|
465
|
+
// ------------------------------- 以下为仅 master 可以发起的请求 -------------------------------
|
|
466
|
+
|
|
467
|
+
// master 通知 member 当前统一登录要解散
|
|
468
|
+
// master 发起(member 不能发起),member 处理该路由 (master -> member)
|
|
469
|
+
server.post(
|
|
470
|
+
`${prefixApi}/disband`,
|
|
471
|
+
ensureBlocklet(),
|
|
472
|
+
checkFederatedCall({ mode: 'masterToMember' }),
|
|
473
|
+
async (req, res) => {
|
|
474
|
+
const { blocklet, verifySite } = req;
|
|
475
|
+
const teamDid = blocklet.appPid;
|
|
476
|
+
|
|
477
|
+
const newState = await node.setFederated({
|
|
478
|
+
did: teamDid,
|
|
479
|
+
config: null,
|
|
480
|
+
});
|
|
481
|
+
await node.createAuditLog(
|
|
482
|
+
{
|
|
483
|
+
action: 'disbandFederated',
|
|
484
|
+
args: { blocklet, masterSite: verifySite, teamDid },
|
|
485
|
+
context: {
|
|
486
|
+
user: getAuditLogActorByFederatedSite(verifySite),
|
|
487
|
+
},
|
|
488
|
+
result: newState,
|
|
489
|
+
},
|
|
490
|
+
node
|
|
491
|
+
);
|
|
492
|
+
res.status(204).send();
|
|
493
|
+
}
|
|
494
|
+
);
|
|
362
495
|
|
|
363
496
|
// step 2 审批(master 申批 member)
|
|
364
497
|
// core/state/lib/blocklet/manager/disk.js -> auditFederatedLogin
|
|
365
|
-
// audit-res 接受 master
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
remark: 'Generated on join federated login',
|
|
391
|
-
mappings: roles.map((item) => {
|
|
392
|
-
return {
|
|
393
|
-
from: { passport: item.name },
|
|
394
|
-
to: { role: 'guest' },
|
|
395
|
-
};
|
|
396
|
-
}),
|
|
397
|
-
},
|
|
398
|
-
],
|
|
399
|
-
});
|
|
498
|
+
// audit-res 接受 master 的处理结果同步
|
|
499
|
+
// master 发起(member 不能发起),member 处理该路由 (master -> member)
|
|
500
|
+
server.post(
|
|
501
|
+
`${prefixApi}/audit-res`,
|
|
502
|
+
ensureBlocklet(),
|
|
503
|
+
checkFederatedCall({
|
|
504
|
+
mode: 'masterToMember',
|
|
505
|
+
}),
|
|
506
|
+
async (req, res) => {
|
|
507
|
+
const { blocklet, verifySite, verifyData } = req;
|
|
508
|
+
const { status } = verifyData;
|
|
509
|
+
const teamDid = blocklet.appPid;
|
|
510
|
+
if (status === 'approved') {
|
|
511
|
+
await node.syncMasterAuthorization({ did: teamDid });
|
|
512
|
+
await node.syncFederatedConfig({ did: teamDid });
|
|
513
|
+
} else if (status === 'rejected') {
|
|
514
|
+
const federated = safeGetFederated(blocklet);
|
|
515
|
+
const selfSite = federated.sites?.find((x) => x.appPid === teamDid);
|
|
516
|
+
if (selfSite) {
|
|
517
|
+
selfSite.status = 'rejected';
|
|
518
|
+
await node.setFederated({
|
|
519
|
+
did: teamDid,
|
|
520
|
+
config: federated,
|
|
521
|
+
});
|
|
522
|
+
}
|
|
400
523
|
}
|
|
524
|
+
|
|
525
|
+
await node.createAuditLog(
|
|
526
|
+
{
|
|
527
|
+
action: 'auditFederated',
|
|
528
|
+
args: { masterSite: verifySite, status, teamDid },
|
|
529
|
+
context: {
|
|
530
|
+
user: getAuditLogActorByFederatedSite(verifySite),
|
|
531
|
+
},
|
|
532
|
+
result: blocklet,
|
|
533
|
+
},
|
|
534
|
+
node
|
|
535
|
+
);
|
|
536
|
+
res.status(204).send();
|
|
401
537
|
}
|
|
538
|
+
);
|
|
402
539
|
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
540
|
+
// 用于在 master 站点登录页面获取 member 登录的 token
|
|
541
|
+
// master 发起(member 不能发起),member 处理该路由 (master -> member)
|
|
542
|
+
server.post(
|
|
543
|
+
`${prefixApi}/loginByMaster`,
|
|
544
|
+
ensureBlocklet(),
|
|
545
|
+
checkFederatedCall({ mode: 'masterToMember' }),
|
|
546
|
+
async (req, res) => {
|
|
547
|
+
const { blocklet, verifySite, verifyData } = req;
|
|
548
|
+
const { passport, user, walletOS, provider } = verifyData;
|
|
549
|
+
const { createSessionToken } = initJwt(node, options);
|
|
550
|
+
const createToken = createTokenFn(createSessionToken);
|
|
551
|
+
const { secret } = await req.getBlockletInfo();
|
|
552
|
+
const teamDid = blocklet.appPid;
|
|
553
|
+
|
|
554
|
+
const sessionConfig = blocklet.settings?.session || {};
|
|
555
|
+
const prevUser = await getUserWithinFederated(
|
|
556
|
+
{
|
|
557
|
+
teamDid,
|
|
558
|
+
sourceAppPid: verifySite.appPid,
|
|
559
|
+
userDid: user.did,
|
|
560
|
+
userPk: user.pk,
|
|
413
561
|
},
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
562
|
+
{
|
|
563
|
+
node,
|
|
564
|
+
blocklet,
|
|
565
|
+
}
|
|
566
|
+
);
|
|
567
|
+
if (prevUser?.approved === false) {
|
|
568
|
+
res.status(401).json({ error: messages.notAllowedAppUser.en });
|
|
569
|
+
return;
|
|
570
|
+
}
|
|
571
|
+
// HACK: member 调用 master 时,将 passport 的 role 还原为 master 中原有的 role
|
|
572
|
+
const targetPassport = passport?.id
|
|
573
|
+
? (prevUser?.passports || []).find((item) => item.id === passport.id)
|
|
574
|
+
: null;
|
|
575
|
+
|
|
576
|
+
// HACK: 用户在 master 中存在时,不更新任何用户信息;不存在时,将新增一个用户
|
|
577
|
+
const filterUserInfo = prevUser ? {} : user;
|
|
578
|
+
if (filterUserInfo.avatar) {
|
|
579
|
+
let avatar = await getAvatarByUrl(filterUserInfo.avatar);
|
|
580
|
+
const nodeInfo = await req.getNodeInfo();
|
|
581
|
+
|
|
582
|
+
const { dataDir } = await getApplicationInfo({ node, nodeInfo, teamDid });
|
|
583
|
+
avatar = await extractUserAvatar(avatar, { dataDir });
|
|
584
|
+
filterUserInfo.avatar = avatar;
|
|
585
|
+
}
|
|
586
|
+
const realDid = prevUser?.did || user.did;
|
|
587
|
+
const realPk = prevUser?.pk || user.pk;
|
|
588
|
+
const newUser = await node.loginUser({
|
|
589
|
+
teamDid,
|
|
590
|
+
user: {
|
|
591
|
+
...filterUserInfo,
|
|
592
|
+
did: realDid,
|
|
593
|
+
pk: realPk,
|
|
594
|
+
passport: targetPassport,
|
|
595
|
+
sourceAppPid: verifySite.appPid,
|
|
596
|
+
connectedAccount: {
|
|
597
|
+
provider: provider || LOGIN_PROVIDER.WALLET,
|
|
598
|
+
did: user.did,
|
|
599
|
+
pk: user.pk,
|
|
600
|
+
},
|
|
601
|
+
},
|
|
602
|
+
});
|
|
603
|
+
|
|
604
|
+
const { sessionToken, refreshToken } = createToken(
|
|
605
|
+
user.did,
|
|
606
|
+
{
|
|
607
|
+
secret,
|
|
608
|
+
passport: targetPassport,
|
|
609
|
+
role: targetPassport?.role || 'guest',
|
|
610
|
+
fullName: newUser.fullName,
|
|
611
|
+
provider: provider || LOGIN_PROVIDER.WALLET,
|
|
612
|
+
walletOS,
|
|
613
|
+
sourceAppPid: verifySite.appPid,
|
|
614
|
+
emailVerified: newUser.emailVerified,
|
|
615
|
+
phoneVerified: newUser.phoneVerified,
|
|
616
|
+
},
|
|
617
|
+
{
|
|
618
|
+
...sessionConfig,
|
|
619
|
+
didConnectVersion: getDidConnectVersion(req),
|
|
620
|
+
}
|
|
621
|
+
);
|
|
622
|
+
|
|
623
|
+
await node.createAuditLog(
|
|
624
|
+
{
|
|
625
|
+
action: 'loginByMaster',
|
|
626
|
+
args: { masterSite: verifySite, teamDid },
|
|
627
|
+
context: {
|
|
628
|
+
user: newUser,
|
|
629
|
+
},
|
|
630
|
+
result: blocklet,
|
|
631
|
+
},
|
|
632
|
+
node
|
|
633
|
+
);
|
|
634
|
+
|
|
635
|
+
res.json({ sessionToken, refreshToken });
|
|
636
|
+
}
|
|
637
|
+
);
|
|
638
|
+
|
|
639
|
+
// ------------------------------- 以下为站点群内可以互相发起的请求 -------------------------------
|
|
420
640
|
|
|
421
641
|
// step 3 同步站点群信息(master 向 member 广播站点群信息,广播请求在 manager/disk.js 文件中 class FederatedBlockletManager 发起 )
|
|
422
|
-
//
|
|
423
|
-
server.post(`${
|
|
424
|
-
const { blocklet } = req;
|
|
425
|
-
const { verifySite } = req.body;
|
|
642
|
+
// 站点群互相可以任意获取
|
|
643
|
+
server.post(`${prefixApi}/sync`, ensureBlocklet(), checkFederatedCall(), async (req, res) => {
|
|
644
|
+
const { blocklet, verifySite, verifyData } = req;
|
|
426
645
|
const teamDid = blocklet.appPid;
|
|
427
|
-
const { users = null, sites = null, userSessions = null } =
|
|
646
|
+
const { users = null, sites = null, userSessions = null } = verifyData;
|
|
428
647
|
const resultData = {
|
|
429
648
|
users: [],
|
|
430
649
|
sites: [],
|
|
431
650
|
userSessions: [],
|
|
432
651
|
};
|
|
433
652
|
|
|
434
|
-
//
|
|
653
|
+
// sites 支持增量更新
|
|
435
654
|
if (!isNil(sites)) {
|
|
436
655
|
const limitSync = pLimit(FEDERATED.SYNC_LIMIT);
|
|
437
656
|
const pendingSiteList = [];
|
|
438
|
-
const federated =
|
|
439
|
-
|
|
657
|
+
const federated = safeGetFederated(blocklet);
|
|
658
|
+
for (const site of sites) {
|
|
659
|
+
const { action, ...siteItem } = site;
|
|
660
|
+
const findIndex = federated.sites.findIndex((x) => x.appPid === siteItem.appPid);
|
|
661
|
+
const isMyself = siteItem.appPid === teamDid;
|
|
662
|
+
if (action === 'update') {
|
|
663
|
+
if (findIndex > -1) {
|
|
664
|
+
Object.assign(federated.sites[findIndex], siteItem);
|
|
665
|
+
}
|
|
666
|
+
} else if (action === 'upsert') {
|
|
667
|
+
if (findIndex > -1) {
|
|
668
|
+
Object.assign(federated.sites[findIndex], siteItem);
|
|
669
|
+
} else {
|
|
670
|
+
federated.sites.push(siteItem);
|
|
671
|
+
}
|
|
672
|
+
// 不允许增加自己,也不允许删除自己
|
|
673
|
+
} else if (!isMyself) {
|
|
674
|
+
if (action === 'add') {
|
|
675
|
+
if (findIndex === -1) {
|
|
676
|
+
federated.sites.push(siteItem);
|
|
677
|
+
}
|
|
678
|
+
} else if (action === 'delete') {
|
|
679
|
+
if (findIndex > -1) {
|
|
680
|
+
federated.sites.splice(findIndex, 1);
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
}
|
|
440
685
|
pendingSiteList.push(
|
|
441
686
|
limitSync(async () => {
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
687
|
+
try {
|
|
688
|
+
await node.setFederated({
|
|
689
|
+
did: teamDid,
|
|
690
|
+
config: federated,
|
|
691
|
+
});
|
|
692
|
+
} catch (error) {
|
|
693
|
+
logger.error('failed to update federated sites', {
|
|
694
|
+
error,
|
|
695
|
+
teamDid,
|
|
696
|
+
sites,
|
|
697
|
+
});
|
|
698
|
+
}
|
|
446
699
|
})
|
|
447
700
|
);
|
|
448
701
|
const resList = await Promise.all(pendingSiteList);
|
|
449
702
|
resultData.sites = resList;
|
|
450
703
|
}
|
|
451
704
|
|
|
705
|
+
// users 支持增量更新
|
|
452
706
|
if (!isNil(users)) {
|
|
453
707
|
if (Array.isArray(users)) {
|
|
454
708
|
const limitSync = pLimit(FEDERATED.SYNC_LIMIT);
|
|
@@ -458,14 +712,23 @@ module.exports = {
|
|
|
458
712
|
for (const user of users) {
|
|
459
713
|
pendingUserList.push(
|
|
460
714
|
limitSync(async () => {
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
715
|
+
try {
|
|
716
|
+
const result = await syncUserFnMaps[user.action]?.(
|
|
717
|
+
{
|
|
718
|
+
...user,
|
|
719
|
+
sourceAppPid: user.sourceAppPid === teamDid ? null : user.sourceAppPid,
|
|
720
|
+
},
|
|
721
|
+
{ node, teamDid, dataDir, blocklet }
|
|
722
|
+
);
|
|
723
|
+
return result;
|
|
724
|
+
} catch (error) {
|
|
725
|
+
logger.error('failed to update federated users', {
|
|
726
|
+
error,
|
|
727
|
+
user,
|
|
728
|
+
});
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
return null;
|
|
469
732
|
})
|
|
470
733
|
);
|
|
471
734
|
}
|
|
@@ -474,6 +737,7 @@ module.exports = {
|
|
|
474
737
|
}
|
|
475
738
|
}
|
|
476
739
|
|
|
740
|
+
// userSessions 支持增量更新
|
|
477
741
|
if (!isNil(userSessions)) {
|
|
478
742
|
if (Array.isArray(userSessions)) {
|
|
479
743
|
const pendingUserSessionList = [];
|
|
@@ -482,14 +746,27 @@ module.exports = {
|
|
|
482
746
|
const { action, ...userSessionItem } = userSession;
|
|
483
747
|
pendingUserSessionList.push(
|
|
484
748
|
limitSync(async () => {
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
749
|
+
try {
|
|
750
|
+
if (action === 'login') {
|
|
751
|
+
const result = await node.upsertUserSession({ ...userSessionItem, teamDid, status: 'online' });
|
|
752
|
+
return result;
|
|
753
|
+
}
|
|
754
|
+
if (action === 'logout') {
|
|
755
|
+
const result = await node.logoutUser({
|
|
756
|
+
...userSessionItem,
|
|
757
|
+
teamDid,
|
|
758
|
+
});
|
|
759
|
+
return result;
|
|
760
|
+
}
|
|
761
|
+
} catch (error) {
|
|
762
|
+
logger.error('failed to update federated userSession', {
|
|
763
|
+
error,
|
|
764
|
+
action,
|
|
765
|
+
userSessionItem,
|
|
490
766
|
teamDid,
|
|
491
767
|
});
|
|
492
768
|
}
|
|
769
|
+
return null;
|
|
493
770
|
})
|
|
494
771
|
);
|
|
495
772
|
}
|
|
@@ -509,344 +786,23 @@ module.exports = {
|
|
|
509
786
|
res.json(resultData);
|
|
510
787
|
});
|
|
511
788
|
|
|
512
|
-
//
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
const {
|
|
516
|
-
const { createSessionToken } = initJwt(node, options);
|
|
517
|
-
const createToken = createTokenFn(createSessionToken);
|
|
518
|
-
const { secret } = await req.getBlockletInfo();
|
|
519
|
-
const { blocklet } = req;
|
|
520
|
-
const teamDid = blocklet.appPid;
|
|
521
|
-
|
|
522
|
-
const sessionConfig = blocklet.settings?.session || {};
|
|
523
|
-
const trustedPassports = blocklet.trustedPassports || [];
|
|
524
|
-
// HACK: 这里只对比 pid,因为自动生成的数据只有 master-site 的 pid
|
|
525
|
-
const masterPassport = trustedPassports.find((item) => item.issuerDid === masterPid);
|
|
526
|
-
const findMapping = masterPassport ? masterPassport.mappings.find((item) => item.from.passport === role) : null;
|
|
527
|
-
const targetPassport = findMapping
|
|
528
|
-
? {
|
|
529
|
-
role: findMapping.to?.role || 'guest',
|
|
530
|
-
name: findMapping.to?.role || 'Guest',
|
|
531
|
-
id: passport?.id || '',
|
|
532
|
-
}
|
|
533
|
-
: { role: 'guest', name: 'Guest' };
|
|
534
|
-
let { avatar } = user || {};
|
|
535
|
-
if (avatar) {
|
|
536
|
-
try {
|
|
537
|
-
avatar = await getAvatarByUrl(user.avatar);
|
|
538
|
-
const nodeInfo = await req.getNodeInfo();
|
|
539
|
-
|
|
540
|
-
const { dataDir } = await getApplicationInfo({ node, nodeInfo, teamDid });
|
|
541
|
-
avatar = await extractUserAvatar(avatar, { dataDir });
|
|
542
|
-
} catch (err) {
|
|
543
|
-
logger.error('Failed to convert user avatar', { error: err });
|
|
544
|
-
}
|
|
545
|
-
}
|
|
546
|
-
const doc = await node.loginUser({
|
|
547
|
-
teamDid,
|
|
548
|
-
user: {
|
|
549
|
-
...user,
|
|
550
|
-
avatar,
|
|
551
|
-
// HACK: @zhanghan 这里会将 passport 插入到当前用户的 passport 列表中,federated 登录不应该插入 passport
|
|
552
|
-
// passport: findMapping ? targetPassport : null,
|
|
553
|
-
sourceAppPid: masterPid,
|
|
554
|
-
connectedAccount: {
|
|
555
|
-
provider: provider || LOGIN_PROVIDER.WALLET,
|
|
556
|
-
id: masterPid,
|
|
557
|
-
did: user.did,
|
|
558
|
-
pk: user.pk,
|
|
559
|
-
},
|
|
560
|
-
},
|
|
561
|
-
});
|
|
562
|
-
const { sessionToken, refreshToken } = createToken(
|
|
563
|
-
doc.did,
|
|
564
|
-
{
|
|
565
|
-
secret,
|
|
566
|
-
role: targetPassport.role,
|
|
567
|
-
passport: targetPassport,
|
|
568
|
-
fullName: doc.fullName,
|
|
569
|
-
provider: provider || LOGIN_PROVIDER.WALLET,
|
|
570
|
-
walletOS,
|
|
571
|
-
emailVerified: doc.emailVerified,
|
|
572
|
-
phoneVerified: doc.phoneVerified,
|
|
573
|
-
},
|
|
574
|
-
{
|
|
575
|
-
...sessionConfig,
|
|
576
|
-
didConnectVersion: getDidConnectVersion(req),
|
|
577
|
-
}
|
|
578
|
-
);
|
|
579
|
-
await node.createAuditLog(
|
|
580
|
-
{
|
|
581
|
-
action: 'loginByMaster',
|
|
582
|
-
args: { masterSite: verifySite, teamDid },
|
|
583
|
-
context: {
|
|
584
|
-
user: doc,
|
|
585
|
-
},
|
|
586
|
-
result: blocklet,
|
|
587
|
-
},
|
|
588
|
-
node
|
|
589
|
-
);
|
|
590
|
-
|
|
591
|
-
res.json({ sessionToken, refreshToken });
|
|
592
|
-
});
|
|
593
|
-
|
|
594
|
-
// member 主动调起 master 登录(实现登录 member 时,自动登录 master)
|
|
595
|
-
// member 传递过来的 user.did 和 user.pk 均为 master-site 与钱包生成的
|
|
596
|
-
server.post(`${prefix}/loginByMember`, ensureBlocklet(), verifyFederatedCall(), async (req, res) => {
|
|
597
|
-
const { verifySite } = req.body;
|
|
598
|
-
const { user, passport, walletOS, provider } = req.body.verifyData;
|
|
599
|
-
const { createSessionToken } = initJwt(node, options);
|
|
600
|
-
const createToken = createTokenFn(createSessionToken);
|
|
601
|
-
const { secret } = await req.getBlockletInfo();
|
|
602
|
-
const { blocklet } = req;
|
|
603
|
-
const teamDid = blocklet.appPid;
|
|
604
|
-
|
|
605
|
-
const sessionConfig = blocklet.settings?.session || {};
|
|
606
|
-
const prevUser = await node.getUser({
|
|
607
|
-
teamDid,
|
|
608
|
-
user: { did: user.did },
|
|
609
|
-
options: { enableConnectedAccount: true },
|
|
610
|
-
});
|
|
611
|
-
// HACK: member 调用 master 时,将 passport 的 role 还原为 master 中原有的 role
|
|
612
|
-
const targetPassport = passport?.id ? (prevUser?.passports || []).find((item) => item.id === passport.id) : null;
|
|
613
|
-
|
|
614
|
-
// HACK: 用户在 master 中存在时,不更新任何用户信息;不存在时,将新增一个用户
|
|
615
|
-
const filterUserInfo = prevUser ? {} : user;
|
|
616
|
-
if (filterUserInfo.avatar) {
|
|
617
|
-
let avatar = await getAvatarByUrl(filterUserInfo.avatar);
|
|
618
|
-
const nodeInfo = await req.getNodeInfo();
|
|
619
|
-
|
|
620
|
-
const { dataDir } = await getApplicationInfo({ node, nodeInfo, teamDid });
|
|
621
|
-
avatar = await extractUserAvatar(avatar, { dataDir });
|
|
622
|
-
filterUserInfo.avatar = avatar;
|
|
623
|
-
}
|
|
624
|
-
const realDid = prevUser?.did || user.did;
|
|
625
|
-
const realPk = prevUser?.pk || user.pk;
|
|
626
|
-
// NOTICE: 这里是 Master 登录,不需要 sourceAppPid 字段
|
|
627
|
-
const newUser = await node.loginUser({
|
|
628
|
-
teamDid,
|
|
629
|
-
user: {
|
|
630
|
-
...filterUserInfo,
|
|
631
|
-
did: realDid,
|
|
632
|
-
pk: realPk,
|
|
633
|
-
passport: targetPassport,
|
|
634
|
-
connectedAccount: {
|
|
635
|
-
provider: provider || LOGIN_PROVIDER.WALLET,
|
|
636
|
-
did: user.did,
|
|
637
|
-
pk: user.pk,
|
|
638
|
-
},
|
|
639
|
-
},
|
|
640
|
-
});
|
|
641
|
-
|
|
642
|
-
const { sessionToken, refreshToken } = createToken(
|
|
643
|
-
user.did,
|
|
644
|
-
{
|
|
645
|
-
secret,
|
|
646
|
-
passport: targetPassport,
|
|
647
|
-
role: targetPassport?.role || 'guest',
|
|
648
|
-
fullName: newUser.fullName,
|
|
649
|
-
// 这里是 member 登录了 master 的账号,对于 master 来说,其实还是使用 wallet 来登录的
|
|
650
|
-
provider: LOGIN_PROVIDER.WALLET,
|
|
651
|
-
walletOS,
|
|
652
|
-
emailVerified: newUser.emailVerified,
|
|
653
|
-
phoneVerified: newUser.phoneVerified,
|
|
654
|
-
},
|
|
655
|
-
{
|
|
656
|
-
...sessionConfig,
|
|
657
|
-
didConnectVersion: getDidConnectVersion(req),
|
|
658
|
-
}
|
|
659
|
-
);
|
|
660
|
-
|
|
661
|
-
await node.createAuditLog(
|
|
662
|
-
{
|
|
663
|
-
action: 'loginByMember',
|
|
664
|
-
args: { memberSite: verifySite, teamDid },
|
|
665
|
-
context: {
|
|
666
|
-
user: newUser,
|
|
667
|
-
},
|
|
668
|
-
result: blocklet,
|
|
669
|
-
},
|
|
670
|
-
node
|
|
671
|
-
);
|
|
672
|
-
|
|
673
|
-
res.json({ sessionToken, refreshToken });
|
|
674
|
-
});
|
|
675
|
-
|
|
676
|
-
// 用于在 master 站点登录页面获取 member 登录的 token
|
|
677
|
-
server.post(`${prefix}/loginByMaster`, ensureBlocklet(), verifyFederatedCall(), async (req, res) => {
|
|
678
|
-
const { verifySite } = req.body;
|
|
679
|
-
const { passport, user, walletOS, provider } = req.body.verifyData;
|
|
680
|
-
const { createSessionToken } = initJwt(node, options);
|
|
681
|
-
const createToken = createTokenFn(createSessionToken);
|
|
682
|
-
const { secret } = await req.getBlockletInfo();
|
|
683
|
-
const { blocklet } = req;
|
|
789
|
+
// 获取指定 passportId 的内容
|
|
790
|
+
// 站点群互相可以任意获取
|
|
791
|
+
server.post(`${prefixApi}/getPassport`, ensureBlocklet(), checkFederatedCall(), async (req, res) => {
|
|
792
|
+
const { blocklet, verifyData } = req;
|
|
684
793
|
const teamDid = blocklet.appPid;
|
|
685
|
-
|
|
686
|
-
const sessionConfig = blocklet.settings?.session || {};
|
|
687
|
-
const prevUser = await getUserWithinFederated(
|
|
688
|
-
{
|
|
689
|
-
teamDid,
|
|
690
|
-
sourceAppPid: verifySite.appPid,
|
|
691
|
-
userDid: user.did,
|
|
692
|
-
userPk: user.pk,
|
|
693
|
-
},
|
|
694
|
-
{
|
|
695
|
-
node,
|
|
696
|
-
blocklet,
|
|
697
|
-
}
|
|
698
|
-
);
|
|
699
|
-
if (prevUser?.approved === false) {
|
|
700
|
-
res.status(401).json({ error: messages.notAllowedAppUser.en });
|
|
701
|
-
return;
|
|
702
|
-
}
|
|
703
|
-
// HACK: member 调用 master 时,将 passport 的 role 还原为 master 中原有的 role
|
|
704
|
-
const targetPassport = passport?.id ? (prevUser?.passports || []).find((item) => item.id === passport.id) : null;
|
|
705
|
-
|
|
706
|
-
// HACK: 用户在 master 中存在时,不更新任何用户信息;不存在时,将新增一个用户
|
|
707
|
-
const filterUserInfo = prevUser ? {} : user;
|
|
708
|
-
if (filterUserInfo.avatar) {
|
|
709
|
-
let avatar = await getAvatarByUrl(filterUserInfo.avatar);
|
|
710
|
-
const nodeInfo = await req.getNodeInfo();
|
|
711
|
-
|
|
712
|
-
const { dataDir } = await getApplicationInfo({ node, nodeInfo, teamDid });
|
|
713
|
-
avatar = await extractUserAvatar(avatar, { dataDir });
|
|
714
|
-
filterUserInfo.avatar = avatar;
|
|
715
|
-
}
|
|
716
|
-
const realDid = prevUser?.did || user.did;
|
|
717
|
-
const realPk = prevUser?.pk || user.pk;
|
|
718
|
-
const newUser = await node.loginUser({
|
|
719
|
-
teamDid,
|
|
720
|
-
user: {
|
|
721
|
-
...filterUserInfo,
|
|
722
|
-
did: realDid,
|
|
723
|
-
pk: realPk,
|
|
724
|
-
passport: targetPassport,
|
|
725
|
-
sourceAppPid: verifySite.appPid,
|
|
726
|
-
connectedAccount: {
|
|
727
|
-
provider: provider || LOGIN_PROVIDER.WALLET,
|
|
728
|
-
did: user.did,
|
|
729
|
-
pk: user.pk,
|
|
730
|
-
},
|
|
731
|
-
},
|
|
732
|
-
});
|
|
733
|
-
|
|
734
|
-
const { sessionToken, refreshToken } = createToken(
|
|
735
|
-
user.did,
|
|
736
|
-
{
|
|
737
|
-
secret,
|
|
738
|
-
passport: targetPassport,
|
|
739
|
-
role: targetPassport?.role || 'guest',
|
|
740
|
-
fullName: newUser.fullName,
|
|
741
|
-
provider: provider || LOGIN_PROVIDER.WALLET,
|
|
742
|
-
walletOS,
|
|
743
|
-
sourceAppPid: verifySite.appPid,
|
|
744
|
-
emailVerified: newUser.emailVerified,
|
|
745
|
-
phoneVerified: newUser.phoneVerified,
|
|
746
|
-
},
|
|
747
|
-
{
|
|
748
|
-
...sessionConfig,
|
|
749
|
-
didConnectVersion: getDidConnectVersion(req),
|
|
750
|
-
}
|
|
751
|
-
);
|
|
752
|
-
|
|
753
|
-
await node.createAuditLog(
|
|
754
|
-
{
|
|
755
|
-
action: 'loginByMaster',
|
|
756
|
-
args: { masterSite: verifySite, teamDid },
|
|
757
|
-
context: {
|
|
758
|
-
user: newUser,
|
|
759
|
-
},
|
|
760
|
-
result: blocklet,
|
|
761
|
-
},
|
|
762
|
-
node
|
|
763
|
-
);
|
|
764
|
-
|
|
765
|
-
res.json({ sessionToken, refreshToken });
|
|
766
|
-
});
|
|
767
|
-
|
|
768
|
-
// member 向 master 申请 auth0 账号的 migrate
|
|
769
|
-
server.post(`${prefix}/migrateAuth0`, ensureBlocklet(), verifyFederatedCall(), async (req, res) => {
|
|
770
|
-
const { blocklet } = req;
|
|
771
|
-
const { verifySite } = req.body;
|
|
772
|
-
const { did: teamDid, wallet: blockletWallet } = await req.getBlockletInfo();
|
|
773
|
-
const { fromUserDid, toUserDid, toUserPk } = req.body.verifyData;
|
|
774
|
-
const oauthUser = await node.getUser({ teamDid, user: { did: fromUserDid } });
|
|
775
|
-
const connectedAccounts = oauthUser?.connectedAccounts || [];
|
|
776
|
-
const sourceProvider = oauthUser?.sourceProvider;
|
|
777
|
-
const oauthAccount = connectedAccounts.find((item) => item.provider === sourceProvider);
|
|
778
|
-
const userWallet = fromAppDid(oauthAccount.id, blockletWallet.secretKey);
|
|
779
|
-
|
|
780
|
-
const bindUser = {
|
|
781
|
-
did: toUserDid,
|
|
782
|
-
pk: toUserPk,
|
|
783
|
-
};
|
|
784
|
-
await declareAccount({ wallet: userWallet, blocklet });
|
|
785
|
-
await migrateAccount({ wallet: userWallet, blocklet, user: bindUser });
|
|
786
|
-
await node.createAuditLog(
|
|
787
|
-
{
|
|
788
|
-
action: 'migrateFederatedAuth0',
|
|
789
|
-
args: { fromUserDid, toUserDid, callerSite: verifySite, teamDid },
|
|
790
|
-
context: {
|
|
791
|
-
user: getAuditLogActorByFederatedSite(verifySite),
|
|
792
|
-
},
|
|
793
|
-
},
|
|
794
|
-
node
|
|
795
|
-
);
|
|
796
|
-
res.json({});
|
|
797
|
-
});
|
|
798
|
-
|
|
799
|
-
// member 去登录 master
|
|
800
|
-
// 该监听是由 member 站点来做的,member 向自己的后端来申请要登录 master,member 的后端组装加密数据,由 Master 来接收并执行相应操作
|
|
801
|
-
server.post(`${prefix}/loginMaster`, ensureBlocklet(), async (req, res) => {
|
|
802
|
-
if (!req.user) {
|
|
803
|
-
res.status(401).send('Unauthorized');
|
|
804
|
-
return;
|
|
805
|
-
}
|
|
806
|
-
const { blocklet } = req;
|
|
807
|
-
const masterSite = getFederatedMaster(blocklet);
|
|
808
|
-
if (!masterSite) {
|
|
809
|
-
res.status(400).send('No federated context found');
|
|
810
|
-
return;
|
|
811
|
-
}
|
|
812
|
-
|
|
813
|
-
const { did: teamDid, permanentWallet } = await req.getBlockletInfo();
|
|
814
|
-
const user = await node.getUser({ teamDid, user: { did: req.user.did } });
|
|
815
|
-
const { passport, walletOS, provider } = req.user;
|
|
816
|
-
const url = joinURL(masterSite.appUrl, prefix, 'loginByMember');
|
|
817
|
-
const postData = {
|
|
818
|
-
signer: permanentWallet.address,
|
|
819
|
-
data: signV2(permanentWallet.address, permanentWallet.secretKey, { user, passport, walletOS, provider }),
|
|
820
|
-
};
|
|
821
|
-
|
|
822
|
-
const { data } = await api.post(url, postData);
|
|
823
|
-
await node.createAuditLog(
|
|
824
|
-
{
|
|
825
|
-
action: 'loginFederatedMaster',
|
|
826
|
-
args: { masterSite, teamDid },
|
|
827
|
-
context: {
|
|
828
|
-
user,
|
|
829
|
-
},
|
|
830
|
-
result: blocklet,
|
|
831
|
-
},
|
|
832
|
-
node
|
|
833
|
-
);
|
|
834
|
-
res.json(data);
|
|
835
|
-
});
|
|
836
|
-
|
|
837
|
-
server.post(`${prefix}/getPassport`, ensureBlocklet(), verifyFederatedCall(), async (req, res) => {
|
|
838
|
-
const { blocklet } = req;
|
|
839
|
-
const teamDid = blocklet.appPid;
|
|
840
|
-
const { passportId } = req.body.verifyData;
|
|
794
|
+
const { passportId } = verifyData;
|
|
841
795
|
const result = await node.getPassportById({ teamDid, passportId });
|
|
842
796
|
res.json(result);
|
|
843
797
|
});
|
|
844
798
|
|
|
845
|
-
|
|
846
|
-
server.get(`${prefix}/getTrustedDomains`, ensureBlocklet(), async (req, res) => {
|
|
799
|
+
server.post(`${prefixApi}/getConfig`, ensureBlocklet(), checkFederatedCall(), async (req, res) => {
|
|
847
800
|
const { blocklet } = req;
|
|
848
|
-
const
|
|
849
|
-
|
|
801
|
+
const nodeInfo = await node.getNodeInfo();
|
|
802
|
+
const domainAliases = await node.getBlockletDomainAliases({ blocklet, nodeInfo });
|
|
803
|
+
|
|
804
|
+
const siteInfo = await generateSiteInfo({ nodeInfo, blocklet, domainAliases });
|
|
805
|
+
res.json(siteInfo);
|
|
850
806
|
});
|
|
851
807
|
},
|
|
852
808
|
};
|