@abtnode/blocklet-services 1.16.26-beta-818ea1c5 → 1.16.26-beta-cca12425
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/auth/adapters/apple.js +78 -0
- package/api/libs/auth/adapters/auth0.js +56 -0
- package/api/libs/auth/adapters/facebook.js +34 -0
- package/api/libs/auth/adapters/github.js +75 -0
- package/api/libs/auth/adapters/google.js +66 -0
- package/api/libs/auth/adapters/twitter.js +22 -0
- package/api/libs/auth/index.js +170 -0
- package/api/routes/federated.js +23 -1
- package/api/routes/oauth.js +257 -102
- package/api/services/auth/connect/receive-transfer-app-owner.js +7 -1
- package/api/services/oauth/index.js +70 -0
- package/api/util/federated.js +2 -2
- package/dist/assets/{Add-DgrYlJHm.js → Add-B1KQFZbB.js} +1 -1
- package/dist/assets/{AddBox-Cqkk9Zb6.js → AddBox-C_rCPKut.js} +1 -1
- package/dist/assets/{Alert-CJmzHVEH.js → Alert-D7OuAtqq.js} +1 -1
- package/dist/assets/{ArrowDropDown-qzt62tXO.js → ArrowDropDown-DDSSUsgw.js} +1 -1
- package/dist/assets/{Avatar-VThXe6vp.js → Avatar-BKvod5qm.js} +1 -1
- package/dist/assets/{ButtonGroup-crNqYhpS.js → ButtonGroup-B93e6tqm.js} +1 -1
- package/dist/assets/{CheckCircle-hTa9NuuL.js → CheckCircle-DgHejmJm.js} +1 -1
- package/dist/assets/{ChevronRight-Zd4sj4Ik.js → ChevronRight-KVhjO69S.js} +1 -1
- package/dist/assets/{CloseOutlined-DzkxsEbx.js → CloseOutlined-BdzvaiT0.js} +1 -1
- package/dist/assets/{Delete-FPkQEM7j.js → Delete-Cmb6a-TW.js} +1 -1
- package/dist/assets/{DeleteOutline-BgceRLMI.js → DeleteOutline-C_JPQWoC.js} +1 -1
- package/dist/assets/{Done-Dw6uaCDC.js → Done-Cqcgj3XK.js} +1 -1
- package/dist/assets/{Download-D4aLfdYz.js → Download-DYDCm5jq.js} +1 -1
- package/dist/assets/{Edit-BQ8r9eYD.js → Edit-JQ58DRtF.js} +1 -1
- package/dist/assets/{EditIcon-DonYKsD8.js → EditIcon-BuHKvSX-.js} +1 -1
- package/dist/assets/Error-bprXV3Qz.js +1 -0
- package/dist/assets/{ExpandMore-BgRJle39.js → ExpandMore-CMOFmrRl.js} +1 -1
- package/dist/assets/{FilterList-Cr_Ge89T.js → FilterList-MfdHX_OT.js} +4 -4
- package/dist/assets/{FormControl-D-JqMY5K.js → FormControl-BrDVvV0w.js} +1 -1
- package/dist/assets/{FormControlLabel-CxQTOZJ1.js → FormControlLabel-Bj1raPoa.js} +1 -1
- package/dist/assets/{FormGroup-C-BEyape.js → FormGroup-CTmu8GWz.js} +1 -1
- package/dist/assets/{Google-DBpd-Csd.js → Google-B8EaETJY.js} +4 -4
- package/dist/assets/{Grid-BKo3Eu4m.js → Grid-BtGjPvuC.js} +1 -1
- package/dist/assets/{Hidden-BIcc-Ri_.js → Hidden-DWKJv_Ts.js} +1 -1
- package/dist/assets/{InfoOutlined-BAo9kLny.js → InfoOutlined-BItr8vqq.js} +1 -1
- package/dist/assets/{InputAdornment-eRc8XOzM.js → InputAdornment-CGuzdfXX.js} +1 -1
- package/dist/assets/{InputLabel-DIt1gEGj.js → InputLabel-DA3u5GP-.js} +1 -1
- package/dist/assets/{LastPage-DBc4oFoT.js → LastPage-DzK9EKF-.js} +1 -1
- package/dist/assets/{Launch-Cb7jRIVL.js → Launch-p5mGEt8g.js} +1 -1
- package/dist/assets/{LaunchOutlined-T5Mcb8X-.js → LaunchOutlined-BiGPJuP-.js} +1 -1
- package/dist/assets/{Link-BP6MkNEU.js → Link-C1R9I8T5.js} +1 -1
- package/dist/assets/{ListItemText-nUHfvFm4.js → ListItemText-9kG4LhTP.js} +1 -1
- package/dist/assets/{LockIcon-8lU2ELwJ.js → LockIcon-BYVTkf1W.js} +1 -1
- package/dist/assets/{Loop-BmbGUwLx.js → Loop-DoUT9kIB.js} +1 -1
- package/dist/assets/{MoreHoriz-Cr0ijI9A.js → MoreHoriz-B921hlWY.js} +1 -1
- package/dist/assets/{MoreVert-B1iH4_5V.js → MoreVert-C4XqRKE4.js} +1 -1
- package/dist/assets/{OpenInNew-CuPWiq3c.js → OpenInNew-DjHvMAdQ.js} +1 -1
- package/dist/assets/{Pagination-DcDob8Pn.js → Pagination-BlJxwbJW.js} +2 -2
- package/dist/assets/{PlayArrow-BMdF4bh0.js → PlayArrow-D4vxqsKR.js} +1 -1
- package/dist/assets/{RadioGroup-DjjhaMO1.js → RadioGroup-DFQHgpUl.js} +1 -1
- package/dist/assets/{Search-D5RGjNs-.js → Search-BuZJTzDq.js} +1 -1
- package/dist/assets/{Select-DCojKr5m.js → Select-0rvptrXH.js} +2 -2
- package/dist/assets/{ServerLogo-B8biNuwQ.js → ServerLogo-BS1tW7SN.js} +1 -1
- package/dist/assets/{Skeleton-D7s7WiMT.js → Skeleton-BQyN-0sJ.js} +3 -3
- package/dist/assets/{Slider-CQHQc72o.js → Slider-DaMMponj.js} +1 -1
- package/dist/assets/{Stepper-7vJEQecO.js → Stepper-ASzJY9Wh.js} +1 -1
- package/dist/assets/{TableRow-G7CkKHMa.js → TableRow-DQB9jM8W.js} +2 -2
- package/dist/assets/{TextField-BiWs3Roa.js → TextField-BHg3uTSC.js} +1 -1
- package/dist/assets/{Toolbar-BIHRXxj8.js → Toolbar-C3gbqZgN.js} +1 -1
- package/dist/assets/{ViewList-BlQf9CJF.js → ViewList-D9nsZOsI.js} +1 -1
- package/dist/assets/access-control-CZnhbObg.js +13 -0
- package/dist/assets/{actions-qRYQXtmd.js → actions-CFxlQnVb.js} +1 -1
- package/dist/assets/{add-component-core-Dk3cdqQl.js → add-component-core-CUisTrXt.js} +28 -28
- package/dist/assets/add-resource-Cg68DwqT.js +1 -0
- package/dist/assets/{addon-D37LISTV.js → addon-htB6vNOx.js} +1 -1
- package/dist/assets/{analytics-BVTyrWL4.js → analytics-D0Q9Rbgs.js} +8 -8
- package/dist/assets/api-DZcbXOwe.js +1 -0
- package/dist/assets/ar-B34f4HdK.js +1 -0
- package/dist/assets/ar-D80LEtfP.js +1 -0
- package/dist/assets/{audit-logs-DYpquiBv.js → audit-logs-DsHwARYT.js} +4 -4
- package/dist/assets/{button-8D8Sy6Jr.js → button-CtcdFik9.js} +1 -1
- package/dist/assets/{click-to-copy-BuvkZSYS.js → click-to-copy-DJVlTNr8.js} +1 -1
- package/dist/assets/{complete-C1W5A3f0.js → complete-CGMY06_W.js} +4 -4
- package/dist/assets/{component-D-wlgWPx.js → component-C8WremgG.js} +4 -4
- package/dist/assets/{config-BWOSsVWv.js → config-J8uHydLG.js} +2 -2
- package/dist/assets/{config-BBK_6yxt.js → config-ggazJABW.js} +1 -1
- package/dist/assets/{config-navigation-CCSF4RHD.js → config-navigation-COwAaVq0.js} +3 -3
- package/dist/assets/{config-space-DQlVUMKm.js → config-space-CPyb_eZ-.js} +1 -1
- package/dist/assets/confirm-BjHkE8rM.js +7 -0
- package/dist/assets/{connect-BkB_iVwc.js → connect-BbzlMR5b.js} +1 -1
- package/dist/assets/{connect-Cz-uMP2K.js → connect-BuLrPUuZ.js} +1 -1
- package/dist/assets/connect-to-BQINcy1q.js +54 -0
- package/dist/assets/{content-layout-BYCcnYXE.js → content-layout-af8Tk37j.js} +1 -1
- package/dist/assets/{dashboard-Bv2HZZCV.js → dashboard-CMs2secm.js} +8 -8
- package/dist/assets/de-CbWSpQPN.js +1 -0
- package/dist/assets/de-R8SpyfWD.js +1 -0
- package/dist/assets/{did-address-DZIM4xfX.js → did-address-BTH0hYaF.js} +1 -1
- package/dist/assets/domain-CMHk_z2Z.js +9 -0
- package/dist/assets/domain-list-DFffhAi2.js +12 -0
- package/dist/assets/es-D2WPMiOg.js +1 -0
- package/dist/assets/es-DQJXbL8c.js +1 -0
- package/dist/assets/exchange-passport-CQ4sTk73.js +1 -0
- package/dist/assets/{fallback-UK-V5wy0.js → fallback-BCzfpkx_.js} +1 -1
- package/dist/assets/fr-BU_67rSB.js +1 -0
- package/dist/assets/fr-ojA_joLk.js +1 -0
- package/dist/assets/{fuel-DYF8oUki.js → fuel-DAtablaD.js} +1 -1
- package/dist/assets/{fullpage-bvTUfN0w.js → fullpage-DY6OHAG0.js} +1 -1
- package/dist/assets/hi-BQAxHgmg.js +1 -0
- package/dist/assets/hi-D5wWKqkp.js +1 -0
- package/dist/assets/home-BfnWYBKb.js +1 -0
- package/dist/assets/id-BerMjI8d.js +1 -0
- package/dist/assets/id-Do44PG5N.js +1 -0
- package/dist/assets/iframe-Cet_1xjB.js +1 -0
- package/dist/assets/{index-CSYh4gtP.js → index-6HBsHgLl.js} +1 -1
- package/dist/assets/index-A5YVryx_.js +13 -0
- package/dist/assets/{index-BXhBzR7Q.js → index-BXCKXS5j.js} +7 -7
- package/dist/assets/index-BqsMd8kb.js +1290 -0
- package/dist/assets/{index-CCY6RJsj.js → index-Bt4rb2Bc.js} +1 -1
- package/dist/assets/index-BxJWfUoy.js +262 -0
- package/dist/assets/{index-Bw_Ej9Cn.js → index-ByPqHR4r.js} +9 -9
- package/dist/assets/{index-BdxvQHKQ.js → index-C5WzGzSj.js} +1 -1
- package/dist/assets/{index-C2vBcXqD.js → index-C9d9WjZ0.js} +1 -1
- package/dist/assets/index-CHX9AKKy.js +221 -0
- package/dist/assets/{index-B0WIUFz1.js → index-CKhzUQzq.js} +7 -7
- package/dist/assets/{index-XV3z9IXt.js → index-CZ9EO740.js} +7 -7
- package/dist/assets/{index-DMSZt2ZE.js → index-CgXB8tNh.js} +2 -2
- package/dist/assets/{index-DWCMi3WL.js → index-Cn1zzQRb.js} +1 -1
- package/dist/assets/{index-Ok0xRBbf.js → index-CnV_HSYC.js} +1 -1
- package/dist/assets/{index-DPLdk86R.js → index-D0TsVpOv.js} +1 -1
- package/dist/assets/{index-CNHAiDvM.js → index-DG2_Yw8Q.js} +1 -1
- package/dist/assets/index-DJI8p4CV.js +54 -0
- package/dist/assets/{index-C00VKsL6.js → index-DJvJ2Tmc.js} +1 -1
- package/dist/assets/{index-BgNMSa3N.js → index-DMPZsfun.js} +1 -1
- package/dist/assets/{index-BQaoZKI6.js → index-Dbqss1Fe.js} +8 -8
- package/dist/assets/index-DcHRVIKm.js +12 -0
- package/dist/assets/{index-DXjXo6f0.js → index-DtNxMhKO.js} +1 -1
- package/dist/assets/{index-BZzKaGvd.js → index-DthjsZ09.js} +1 -1
- package/dist/assets/{index-mNlCpV8P.js → index-Dylzk7Aa.js} +2 -2
- package/dist/assets/{index-dUNOHPzk.js → index-LSzcGKHj.js} +4 -4
- package/dist/assets/index-NdCq_QfL.js +234 -0
- package/dist/assets/{index-BKdL2tN6.js → index-e7NHyY1q.js} +15 -17
- package/dist/assets/{index-DuoMkzRH.js → index-o-Ihmjeu.js} +1 -1
- package/dist/assets/index-zxzrHJEP.js +11 -0
- package/dist/assets/{index.es-B_ckeqWW.js → index.es-BEaw1DFj.js} +3 -3
- package/dist/assets/index.esm-C9zb95qH.js +1 -0
- package/dist/assets/info-outline-rounded-BTpTFmEK.js +57 -0
- package/dist/assets/{invitation-DlUxWMm0.js → invitation-3r-X891j.js} +5 -5
- package/dist/assets/{invite-DVE8FTA3.js → invite-CrWjnaC0.js} +1 -1
- package/dist/assets/{issue-passport-DTrWwTY_.js → issue-passport-CCGBLWf8.js} +1 -1
- package/dist/assets/item-BNHxZM2p.js +1 -0
- package/dist/assets/ja-BO4aqMDb.js +1 -0
- package/dist/assets/ja-D8qblxbX.js +1 -0
- package/dist/assets/{jss-plugin-props-sort.esm-r4rT6imo.js → jss-plugin-props-sort.esm-CjzdPk2L.js} +4 -4
- package/dist/assets/ko-C8eR3MIF.js +1 -0
- package/dist/assets/ko-Cv-NiLYG.js +1 -0
- package/dist/assets/{launch-result-message-DKVZaiuQ.js → launch-result-message-D2CQfmUY.js} +1 -1
- package/dist/assets/{layout-r1uFQEiA.js → layout--pblhAfc.js} +2 -2
- package/dist/assets/{list-header-Bqj4L1f9.js → list-header-Br5YHewG.js} +1 -1
- package/dist/assets/localization-BwDw74Zq.js +1 -0
- package/dist/assets/{log-6WvRhIsI.js → log-BJjAfVl8.js} +1 -1
- package/dist/assets/{login-Cv7Mu9fV.js → login-BQQD6meW.js} +1 -1
- package/dist/assets/login-oauth-callback-Dmleuitf.js +1 -0
- package/dist/assets/logo-uploader-eDNDJkbn.js +127 -0
- package/dist/assets/{lost-passport-D1SohDZY.js → lost-passport-BWTuZR78.js} +3 -3
- package/dist/assets/{lottie-DGWD8Sx6.js → lottie-VJFQ68oA.js} +1 -1
- package/dist/assets/{notifications-B2-qZM1R.js → notifications-DwecRDR9.js} +2 -2
- package/dist/assets/overview-BMcMnUtN.js +12 -0
- package/dist/assets/{page-header-CNlMYlWe.js → page-header-EqcdM7n1.js} +1 -1
- package/dist/assets/{permission-rTeG4c6s.js → permission-D9TNO0kT.js} +1 -1
- package/dist/assets/{preferences-uQd05OUd.js → preferences-CN9EJ9NX.js} +1 -1
- package/dist/assets/pt-DfarVqto.js +1 -0
- package/dist/assets/pt-Dly5Myel.js +1 -0
- package/dist/assets/publish-resource-D7WXvm6u.js +1 -0
- package/dist/assets/{react-Cv1mxS7R.js → react-DP2ngoHF.js} +15 -15
- package/dist/assets/{redux-YC_VNDAW.js → redux-BpyOm6pS.js} +1 -1
- package/dist/assets/ru-C9Wh9IKf.js +1 -0
- package/dist/assets/ru-DeqfYyhe.js +1 -0
- package/dist/assets/{selector-UANcYMI5.js → selector-Dpt9nBq7.js} +3 -3
- package/dist/assets/session-DESbRLD5.js +1 -0
- package/dist/assets/setup-DFybTsc-.js +19 -0
- package/dist/assets/{slicedToArray-BDirS3b-.js → slicedToArray-SBrU6gJV.js} +2 -2
- package/dist/assets/spaces-DNtrZi8N.js +1 -0
- package/dist/assets/start-CgH7B6u8.js +186 -0
- package/dist/assets/{step-actions-DBbKtvUA.js → step-actions-BNn2aM9R.js} +1 -1
- package/dist/assets/{studio-DseQhKM-.js → studio-8gthozLh.js} +1 -1
- package/dist/assets/{switch-control-ChRbLafp.js → switch-control-DO3LxG2v.js} +1 -1
- package/dist/assets/th-B6Z2fc62.js +1 -0
- package/dist/assets/th-BEfUwHXu.js +1 -0
- package/dist/assets/{toUpper-aYHMIsgS.js → toUpper-C0A9jQTp.js} +1 -1
- package/dist/assets/transfer-Blq_vH7z.js +16 -0
- package/dist/assets/uniqBy-DN9WBw_C.js +1 -0
- package/dist/assets/{unsubscribe-CD5-lgl8.js → unsubscribe-CkiFEJUY.js} +1 -1
- package/dist/assets/{use-blocklet-info-for-connect-did-spaces-BZgwpcda.js → use-blocklet-info-for-connect-did-spaces-Car-GPAS.js} +1 -1
- package/dist/assets/useAsync-D0lrbkdE.js +1 -0
- package/dist/assets/{useFormControl-Dg1dn0q0.js → useFormControl-b_gcFCyO.js} +1 -1
- package/dist/assets/{useLocalStorage-Cz7o0KhC.js → useLocalStorage-Cvbq9kSP.js} +1 -1
- package/dist/assets/{useSetState-CabR74SD.js → useSetState-p_ztAK1J.js} +1 -1
- package/dist/assets/useSlot-MeMXV443.js +1 -0
- package/dist/assets/user-center-B0jK0JhV.js +1 -0
- package/dist/assets/user-sessions-gd1hKrWX.js +1 -0
- package/dist/assets/{util-nCKofCSa.js → util-BkBoAuZA.js} +1 -1
- package/dist/assets/vi-CVN1WwF4.js +1 -0
- package/dist/assets/vi-Di0ynKe6.js +1 -0
- package/dist/assets/wrap-locale-BONrbXck.js +1 -0
- package/dist/assets/{zh-BjdUZ9y0.js → zh-Bgfgr3pp.js} +2 -2
- package/dist/assets/zh-e04FR-Ps.js +1 -0
- package/dist/assets/zh-tw-DlepKNg6.js +1 -0
- package/dist/assets/zh-tw-kaMajsUI.js +1 -0
- package/dist/index.html +1 -1
- package/dist/service-worker.js +1 -1
- package/package.json +28 -27
- package/dist/assets/access-control-2ITAVZFE.js +0 -13
- package/dist/assets/add-resource-DXNOMO-U.js +0 -1
- package/dist/assets/api-DbKOEDhE.js +0 -1
- package/dist/assets/ar-CxvIl-Ji.js +0 -1
- package/dist/assets/ar-DkKlynAd.js +0 -1
- package/dist/assets/confirm-B_AqBUcU.js +0 -7
- package/dist/assets/connect-to-DY7ehzSR.js +0 -54
- package/dist/assets/de-3qOdEa6P.js +0 -1
- package/dist/assets/de-6SF_cfoR.js +0 -1
- package/dist/assets/domain-DhXcq2zb.js +0 -9
- package/dist/assets/domain-list-DgsYQNVw.js +0 -12
- package/dist/assets/es-7PLonVLT.js +0 -1
- package/dist/assets/es-Cgmj9Jck.js +0 -1
- package/dist/assets/exchange-passport-B9snHp27.js +0 -1
- package/dist/assets/fr-1I2E8gH_.js +0 -1
- package/dist/assets/fr-CEcEkJ0j.js +0 -1
- package/dist/assets/hi-B2Zih4k5.js +0 -1
- package/dist/assets/hi-O7fF0c9u.js +0 -1
- package/dist/assets/home-CU_IGJyv.js +0 -1
- package/dist/assets/id-BF9h-bev.js +0 -1
- package/dist/assets/id-Cvddby74.js +0 -1
- package/dist/assets/iframe-COW-8OqG.js +0 -1
- package/dist/assets/index-7_LDggGs.js +0 -11
- package/dist/assets/index-BiG0eNQl.js +0 -233
- package/dist/assets/index-Cqc114Nl.js +0 -54
- package/dist/assets/index-D04f13KU.js +0 -1304
- package/dist/assets/index-DGFV1Kbv.js +0 -13
- package/dist/assets/index-De-cDFqF.js +0 -262
- package/dist/assets/index-cOMrpLvw.js +0 -221
- package/dist/assets/index.esm-CymxS9uw.js +0 -1
- package/dist/assets/item-DJ0IfbAJ.js +0 -1
- package/dist/assets/ja-BRl6JgyC.js +0 -1
- package/dist/assets/ja-D-8llXBd.js +0 -1
- package/dist/assets/ko-BjJKFx_R.js +0 -1
- package/dist/assets/ko-wij13JCo.js +0 -1
- package/dist/assets/localization-CWTtfgBA.js +0 -1
- package/dist/assets/logo-uploader-Bd9nGCUT.js +0 -127
- package/dist/assets/overview--CbrsoGh.js +0 -12
- package/dist/assets/pt-CkaW7MUR.js +0 -1
- package/dist/assets/pt-DwFQV4Br.js +0 -1
- package/dist/assets/publish-resource-DOdKon0e.js +0 -1
- package/dist/assets/ru-1GZMliq9.js +0 -1
- package/dist/assets/ru-D1AQvTQo.js +0 -1
- package/dist/assets/session-CNTfeDhH.js +0 -1
- package/dist/assets/setup-Cv13s2jR.js +0 -19
- package/dist/assets/spaces-BRT7WRxg.js +0 -1
- package/dist/assets/start-Bcl56tnq.js +0 -186
- package/dist/assets/th-BXoQZNC4.js +0 -1
- package/dist/assets/th-Bc32gh20.js +0 -1
- package/dist/assets/transfer-DTM2UHnW.js +0 -16
- package/dist/assets/ua-parser-Ca9ZhtBr.js +0 -57
- package/dist/assets/uniqBy-BkV8rpNe.js +0 -1
- package/dist/assets/useAsync-COTc7rmY.js +0 -1
- package/dist/assets/useSlot-Ceul9GiJ.js +0 -1
- package/dist/assets/user-center-6Xre-wMU.js +0 -1
- package/dist/assets/user-sessions-B85QTl3T.js +0 -1
- package/dist/assets/vi-BnooUqta.js +0 -1
- package/dist/assets/vi-CRasBMRh.js +0 -1
- package/dist/assets/wrap-locale-bIxHxEdd.js +0 -1
- package/dist/assets/zh-B75pu7gp.js +0 -1
- package/dist/assets/zh-tw-BYDo5dcg.js +0 -1
- package/dist/assets/zh-tw-prJAtGne.js +0 -1
- /package/api/libs/auth/adapters/{auth0 → auth0-legacy}/authentication-client.js +0 -0
- /package/api/libs/auth/adapters/{auth0 → auth0-legacy}/index.js +0 -0
- /package/api/libs/auth/adapters/{auth0 → auth0-legacy}/management-client.js +0 -0
package/api/routes/oauth.js
CHANGED
|
@@ -10,25 +10,27 @@ const last = require('lodash/last');
|
|
|
10
10
|
const pick = require('lodash/pick');
|
|
11
11
|
const uniqBy = require('lodash/uniqBy');
|
|
12
12
|
const sortBy = require('lodash/sortBy');
|
|
13
|
+
const cloneDeep = require('lodash/cloneDeep');
|
|
13
14
|
const joinUrl = require('url-join');
|
|
14
|
-
const { getWalletDid } = require('@blocklet/meta/lib/did-utils');
|
|
15
|
+
const { getWalletDid, getConnectedAccounts, getSourceProvider } = require('@blocklet/meta/lib/did-utils');
|
|
15
16
|
const formatContext = require('@abtnode/util/lib/format-context');
|
|
16
17
|
const createTranslator = require('@abtnode/util/lib/translate');
|
|
17
18
|
const { LOGIN_PROVIDER } = require('@blocklet/constant');
|
|
19
|
+
const { withHttps, withTrailingSlash } = require('ufo');
|
|
18
20
|
|
|
19
21
|
const logger = require('../libs/logger')('oauth');
|
|
20
|
-
const {
|
|
22
|
+
const { OAuthClient } = require('../libs/auth');
|
|
23
|
+
const OAuthAuth0 = require('../libs/auth/adapters/auth0');
|
|
24
|
+
const OAuthAuth0Legacy = require('../libs/auth/adapters/auth0-legacy');
|
|
25
|
+
const OAuthGithub = require('../libs/auth/adapters/github');
|
|
26
|
+
const OAuthGoogle = require('../libs/auth/adapters/google');
|
|
27
|
+
const OAuthApple = require('../libs/auth/adapters/apple');
|
|
21
28
|
const { getAvatarByEmail, transferPassport, getAvatarByUrl } = require('../libs/auth/utils');
|
|
22
29
|
const initJwt = require('../libs/jwt');
|
|
23
30
|
const { sendToUser } = require('../libs/notification');
|
|
24
31
|
const { isInvitedUserOnly, createTokenFn, getDidConnectVersion } = require('../util');
|
|
25
32
|
const { ApiError } = require('../util/error');
|
|
26
|
-
const
|
|
27
|
-
getFederatedMaster,
|
|
28
|
-
getOAuthUserInfo,
|
|
29
|
-
shouldSyncFederated,
|
|
30
|
-
getUserWithinFederated,
|
|
31
|
-
} = require('../util/federated');
|
|
33
|
+
const federatedUtil = require('../util/federated');
|
|
32
34
|
|
|
33
35
|
const PREFIX = WELLKNOWN_SERVICE_PATH_PREFIX;
|
|
34
36
|
|
|
@@ -40,65 +42,142 @@ const translations = {
|
|
|
40
42
|
needInviteToLogin: '你需要被邀请才可以登录此应用',
|
|
41
43
|
alreadyMainAccount: '当前邮箱已经绑定过该应用,不过你可以先以此邮箱登陆,然后再绑定钱包账户',
|
|
42
44
|
alreadyBindWallet: '当前邮箱已经绑定过钱包账户 {did}。',
|
|
45
|
+
alreadyExist: '当前账户已存在,无法完成绑定操作。',
|
|
46
|
+
alreadyBindProvider: '当前账户绑定过 {provider},无法完成绑定操作。',
|
|
43
47
|
oauthCantBeOwner: '第三方登录的账户不能成为应用的拥有者',
|
|
44
48
|
oauthCantBindOauth: '第三方登录的账户无法绑定另一个第三方登录的账户',
|
|
49
|
+
cantUnbindWalletAccount: '不能解绑钱包账户',
|
|
50
|
+
cantUnbindSourceProvider: '不能解绑源账户',
|
|
51
|
+
accountNotExist: '第三方登录的账户不存在,无法完成解绑操作',
|
|
45
52
|
},
|
|
46
53
|
en: {
|
|
47
54
|
needInviteToLogin: 'You need to be invited to login in to this app',
|
|
48
55
|
alreadyMainAccount:
|
|
49
56
|
'Your email has already logged in to the app, so binding cannot be completed. However, you can first log in with this email and then bind your wallet account.',
|
|
50
57
|
alreadyBindWallet: 'Your account is already bond to wallet account {did}, so binding can not be completed.',
|
|
58
|
+
alreadyExist: 'Your account already exists, so binding cannot be completed.',
|
|
59
|
+
alreadyBindProvider: 'Your account is already bind to {provider}, so binding can not be completed.',
|
|
51
60
|
oauthCantBeOwner: "Can't login oauth account as owner",
|
|
52
61
|
oauthCantBindOauth: "Current account can't bind to a third party account",
|
|
62
|
+
cantUnbindWalletAccount: 'Cannot unbind wallet provider',
|
|
63
|
+
cantUnbindSourceProvider: 'Cannot unbind source provider',
|
|
64
|
+
accountNotExist: "Connected account is not exist, can't finish disconnect",
|
|
53
65
|
},
|
|
54
66
|
};
|
|
55
67
|
|
|
56
68
|
const t = createTranslator({ translations });
|
|
57
69
|
|
|
58
|
-
function
|
|
59
|
-
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
}
|
|
64
|
-
const authClient = new AuthenticationClient({
|
|
65
|
-
domain: providerConfig.domain,
|
|
70
|
+
async function getOAuthUserInfo({ blocklet, provider, token, idToken, code, appPid }) {
|
|
71
|
+
let oauthInfo;
|
|
72
|
+
const authClient = getAuthClient(blocklet, provider, {
|
|
73
|
+
appPid,
|
|
74
|
+
legacy: Boolean(token && provider === 'auth0'),
|
|
66
75
|
});
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
+
// FIXME: @zhanghan 临时兼容 auth0 这种直接传 token 的方式,将来要废弃这种方式
|
|
77
|
+
if (token && provider === 'auth0') {
|
|
78
|
+
oauthInfo = await authClient.getProfile(token);
|
|
79
|
+
} else if (idToken) {
|
|
80
|
+
// FIXME: @zhanghan 临时提供 id_token 方案,将来要废弃这种方式
|
|
81
|
+
oauthInfo = await authClient.getProfile({ id_token: idToken });
|
|
82
|
+
} else if (code) {
|
|
83
|
+
const oauthToken = await authClient.getToken({ code });
|
|
84
|
+
oauthInfo = await authClient.getProfile(oauthToken);
|
|
76
85
|
}
|
|
77
|
-
|
|
86
|
+
return oauthInfo;
|
|
87
|
+
}
|
|
78
88
|
|
|
89
|
+
async function getOAuthFederatedUserInfo(req, { blocklet }) {
|
|
79
90
|
let userWallet;
|
|
80
91
|
let oauthInfo;
|
|
92
|
+
const { token, idToken, code, provider, sourceAppPid = null } = req.body;
|
|
93
|
+
|
|
94
|
+
// appUrl
|
|
95
|
+
const { wallet: blockletWallet } = await req.getBlockletInfo();
|
|
81
96
|
|
|
82
97
|
// NOTICE: 如果是统一登录,则向 master 站点发起 oauth 用户信息查询请求,auth0 的账户信息必须由 master 来生成
|
|
83
98
|
if (sourceAppPid) {
|
|
84
|
-
const data = await getOAuthUserInfo({
|
|
99
|
+
const data = await federatedUtil.getOAuthUserInfo({
|
|
85
100
|
request: req,
|
|
86
101
|
blocklet,
|
|
87
102
|
provider,
|
|
88
|
-
token,
|
|
89
103
|
sourceAppPid,
|
|
104
|
+
// 三种用于获取用户信息的方式,任选其一即可
|
|
105
|
+
token,
|
|
106
|
+
idToken,
|
|
107
|
+
code,
|
|
90
108
|
});
|
|
91
109
|
userWallet = data.wallet;
|
|
92
110
|
oauthInfo = data.info;
|
|
93
111
|
} else {
|
|
94
|
-
|
|
95
|
-
oauthInfo = await authClient.getProfile(token);
|
|
112
|
+
oauthInfo = await getOAuthUserInfo({ blocklet, provider, code, idToken, token });
|
|
96
113
|
userWallet = fromAppDid(oauthInfo.sub, blockletWallet.secretKey);
|
|
97
114
|
}
|
|
115
|
+
return { info: oauthInfo, wallet: userWallet };
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function getAuthClient(blocklet, provider, { legacy = false, appPid } = {}) {
|
|
119
|
+
const oauthConfig = cloneDeep(blocklet?.settings?.oauth || {});
|
|
120
|
+
const providerConfig = oauthConfig?.[provider];
|
|
121
|
+
if (!providerConfig) {
|
|
122
|
+
throw new ApiError(400, `Provider ${provider} is not valid`);
|
|
123
|
+
}
|
|
124
|
+
let appUrl = blocklet?.environmentObj?.BLOCKLET_APP_URL;
|
|
125
|
+
if (appPid) {
|
|
126
|
+
const federatedSites = blocklet.settings?.federated?.sites || [];
|
|
127
|
+
const loginSite = federatedSites.find((x) => x.appPid === appPid);
|
|
128
|
+
appUrl = loginSite.appUrl;
|
|
129
|
+
}
|
|
130
|
+
providerConfig.callbackUrl = `${appUrl}/.well-known/service/oauth/callback/${provider}`;
|
|
131
|
+
|
|
132
|
+
if (provider === 'auth0') {
|
|
133
|
+
if (legacy) {
|
|
134
|
+
// FIXME: @zhanghan 将来需要移除 legacy auth0 的支持
|
|
135
|
+
return new OAuthAuth0Legacy.AuthenticationClient({
|
|
136
|
+
domain: providerConfig.domain,
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
if (!providerConfig.clientSecret) {
|
|
140
|
+
throw new Error('missing client secret');
|
|
141
|
+
}
|
|
142
|
+
return new OAuthClient({
|
|
143
|
+
provider: OAuthAuth0({
|
|
144
|
+
// HACK: auth0 比较奇葩,它的 issuer 有斜杠后缀
|
|
145
|
+
issuer: withTrailingSlash(withHttps(providerConfig.domain)),
|
|
146
|
+
clientId: providerConfig.clientId,
|
|
147
|
+
clientSecret: providerConfig.clientSecret,
|
|
148
|
+
callbackUrl: providerConfig.callbackUrl,
|
|
149
|
+
}),
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (provider === 'github') {
|
|
154
|
+
return new OAuthClient({ provider: OAuthGithub(providerConfig) });
|
|
155
|
+
}
|
|
156
|
+
if (provider === 'google') {
|
|
157
|
+
return new OAuthClient({ provider: OAuthGoogle(providerConfig) });
|
|
158
|
+
}
|
|
159
|
+
if (provider === 'apple') {
|
|
160
|
+
return new OAuthClient({ provider: OAuthApple(providerConfig) });
|
|
161
|
+
}
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
async function login(req, node, options) {
|
|
166
|
+
const blocklet = await req.getBlocklet();
|
|
167
|
+
const { locale = 'en', provider, componentId, sourceAppPid = null, visitorId } = req.body;
|
|
168
|
+
if (!blocklet.settings?.owner) {
|
|
169
|
+
throw new ApiError(400, t('oauthCantBeOwner', locale));
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const { did: teamDid, secret, appUrl } = await req.getBlockletInfo();
|
|
173
|
+
const { info: oauthInfo, wallet: userWallet } = await getOAuthFederatedUserInfo(req, {
|
|
174
|
+
blocklet,
|
|
175
|
+
});
|
|
98
176
|
|
|
99
177
|
const userDid = userWallet.address;
|
|
100
178
|
const userPk = userWallet.publicKey;
|
|
101
179
|
|
|
180
|
+
// FIXME: @zhanghan 这里通过 componentId 来判断权限的方式实际上没有意义,因为用户可以尝试从别的 url 来登录
|
|
102
181
|
const config = await req.getServiceConfig(NODE_SERVICES.AUTH, { componentId });
|
|
103
182
|
const nodeInfo = await req.getNodeInfo();
|
|
104
183
|
const { dataDir } = await getApplicationInfo({ node, nodeInfo, teamDid });
|
|
@@ -106,17 +185,21 @@ async function login(req, node, options) {
|
|
|
106
185
|
|
|
107
186
|
const lastLoginIp = get(req, 'headers[x-real-ip]') || '';
|
|
108
187
|
let passport = { name: 'Guest', role: 'guest' };
|
|
109
|
-
let currentUser = await getUserWithinFederated(
|
|
188
|
+
let currentUser = await federatedUtil.getUserWithinFederated(
|
|
189
|
+
{ sourceAppPid, teamDid, userDid, userPk },
|
|
190
|
+
{ node, blocklet }
|
|
191
|
+
);
|
|
110
192
|
let doc;
|
|
111
193
|
let passportForLog;
|
|
112
|
-
const fullName = currentUser?.fullName || oauthInfo?.
|
|
194
|
+
const fullName = currentUser?.fullName || oauthInfo?.name;
|
|
113
195
|
const connectedAccount = {
|
|
114
196
|
provider,
|
|
115
197
|
did: userDid,
|
|
116
198
|
pk: userPk,
|
|
117
199
|
id: oauthInfo.sub,
|
|
200
|
+
userInfo: oauthInfo,
|
|
118
201
|
};
|
|
119
|
-
const masterSite = getFederatedMaster(blocklet);
|
|
202
|
+
const masterSite = federatedUtil.getFederatedMaster(blocklet);
|
|
120
203
|
let profile;
|
|
121
204
|
// 当前账户已存在,更新账户信息
|
|
122
205
|
if (currentUser) {
|
|
@@ -159,7 +242,7 @@ async function login(req, node, options) {
|
|
|
159
242
|
|
|
160
243
|
passportForLog = { name: 'Guest', role: 'guest' };
|
|
161
244
|
profile = {
|
|
162
|
-
fullName: oauthInfo.
|
|
245
|
+
fullName: oauthInfo.name,
|
|
163
246
|
email: oauthInfo.email,
|
|
164
247
|
avatar,
|
|
165
248
|
};
|
|
@@ -202,7 +285,7 @@ async function login(req, node, options) {
|
|
|
202
285
|
},
|
|
203
286
|
});
|
|
204
287
|
|
|
205
|
-
if (shouldSyncFederated(sourceAppPid, blocklet)) {
|
|
288
|
+
if (federatedUtil.shouldSyncFederated(sourceAppPid, blocklet)) {
|
|
206
289
|
const syncUserData = {
|
|
207
290
|
did: userDid,
|
|
208
291
|
pk: userPk,
|
|
@@ -270,38 +353,14 @@ async function login(req, node, options) {
|
|
|
270
353
|
}
|
|
271
354
|
|
|
272
355
|
async function invite(req, node, options) {
|
|
273
|
-
const {
|
|
274
|
-
locale,
|
|
275
|
-
inviteId,
|
|
276
|
-
token,
|
|
277
|
-
baseUrl,
|
|
278
|
-
provider = LOGIN_PROVIDER.AUTH0,
|
|
279
|
-
sourceAppPid = null,
|
|
280
|
-
visitorId,
|
|
281
|
-
} = req.body;
|
|
356
|
+
const { locale, inviteId, baseUrl, provider = LOGIN_PROVIDER.AUTH0, sourceAppPid = null, visitorId } = req.body;
|
|
282
357
|
const blocklet = await req.getBlocklet();
|
|
283
|
-
let userWallet;
|
|
284
|
-
let oauthInfo;
|
|
285
358
|
|
|
286
|
-
const { did: teamDid,
|
|
359
|
+
const { did: teamDid, secret } = await req.getBlockletInfo();
|
|
287
360
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
request: req,
|
|
292
|
-
blocklet,
|
|
293
|
-
provider,
|
|
294
|
-
token,
|
|
295
|
-
sourceAppPid,
|
|
296
|
-
locale,
|
|
297
|
-
});
|
|
298
|
-
userWallet = data.wallet;
|
|
299
|
-
oauthInfo = data.info;
|
|
300
|
-
} else {
|
|
301
|
-
const authClient = getAuthClient(blocklet, provider);
|
|
302
|
-
oauthInfo = await authClient.getProfile(token);
|
|
303
|
-
userWallet = fromAppDid(oauthInfo.sub, blockletWallet.secretKey);
|
|
304
|
-
}
|
|
361
|
+
const { info: oauthInfo, wallet: userWallet } = await getOAuthFederatedUserInfo(req, {
|
|
362
|
+
blocklet,
|
|
363
|
+
});
|
|
305
364
|
|
|
306
365
|
const nodeInfo = await req.getNodeInfo();
|
|
307
366
|
let userDid = userWallet.address;
|
|
@@ -309,7 +368,10 @@ async function invite(req, node, options) {
|
|
|
309
368
|
|
|
310
369
|
let profile;
|
|
311
370
|
|
|
312
|
-
const currentUser = await getUserWithinFederated(
|
|
371
|
+
const currentUser = await federatedUtil.getUserWithinFederated(
|
|
372
|
+
{ sourceAppPid, teamDid, userDid, userPk },
|
|
373
|
+
{ node, blocklet }
|
|
374
|
+
);
|
|
313
375
|
|
|
314
376
|
const { dataDir, name: applicationName } = await getApplicationInfo({ node, nodeInfo, teamDid });
|
|
315
377
|
if (currentUser) {
|
|
@@ -321,12 +383,11 @@ async function invite(req, node, options) {
|
|
|
321
383
|
userDid = currentUser.did;
|
|
322
384
|
userPk = currentUser.pk;
|
|
323
385
|
} else {
|
|
324
|
-
|
|
325
|
-
let avatar = picture ? await getAvatarByUrl(picture) : await getAvatarByEmail(email);
|
|
386
|
+
let avatar = oauthInfo.picture ? await getAvatarByUrl(oauthInfo.picture) : await getAvatarByEmail(oauthInfo.email);
|
|
326
387
|
avatar = await extractUserAvatar(avatar, { dataDir });
|
|
327
388
|
profile = {
|
|
328
|
-
email,
|
|
329
|
-
fullName,
|
|
389
|
+
email: oauthInfo.email,
|
|
390
|
+
fullName: oauthInfo.name,
|
|
330
391
|
avatar: getUserAvatarUrl(baseUrl, avatar),
|
|
331
392
|
};
|
|
332
393
|
}
|
|
@@ -348,7 +409,7 @@ async function invite(req, node, options) {
|
|
|
348
409
|
locale,
|
|
349
410
|
provider,
|
|
350
411
|
});
|
|
351
|
-
const masterSite = getFederatedMaster(blocklet);
|
|
412
|
+
const masterSite = federatedUtil.getFederatedMaster(blocklet);
|
|
352
413
|
const syncData = {
|
|
353
414
|
users: [],
|
|
354
415
|
};
|
|
@@ -381,6 +442,7 @@ async function invite(req, node, options) {
|
|
|
381
442
|
id: oauthInfo.sub,
|
|
382
443
|
did: userWallet.address,
|
|
383
444
|
pk: userWallet.publicKey,
|
|
445
|
+
userInfo: oauthInfo,
|
|
384
446
|
};
|
|
385
447
|
await node.loginUser({
|
|
386
448
|
teamDid,
|
|
@@ -391,7 +453,7 @@ async function invite(req, node, options) {
|
|
|
391
453
|
sourceAppPid,
|
|
392
454
|
},
|
|
393
455
|
});
|
|
394
|
-
if (shouldSyncFederated(sourceAppPid, blocklet)) {
|
|
456
|
+
if (federatedUtil.shouldSyncFederated(sourceAppPid, blocklet)) {
|
|
395
457
|
const syncUserData = {
|
|
396
458
|
did: userDid,
|
|
397
459
|
pk: userPk,
|
|
@@ -422,7 +484,7 @@ async function invite(req, node, options) {
|
|
|
422
484
|
},
|
|
423
485
|
});
|
|
424
486
|
|
|
425
|
-
if (shouldSyncFederated(sourceAppPid, blocklet)) {
|
|
487
|
+
if (federatedUtil.shouldSyncFederated(sourceAppPid, blocklet)) {
|
|
426
488
|
node
|
|
427
489
|
.syncFederated({
|
|
428
490
|
did: teamDid,
|
|
@@ -470,22 +532,12 @@ async function invite(req, node, options) {
|
|
|
470
532
|
// 给 DID Wallet 绑定 Auth0 的流程
|
|
471
533
|
// eslint-disable-next-line no-unused-vars
|
|
472
534
|
async function bind(req, node, options) {
|
|
473
|
-
const {
|
|
535
|
+
const { locale = 'en', provider, sourceAppPid } = req.body;
|
|
474
536
|
const blocklet = await req.getBlocklet();
|
|
475
|
-
const { did: teamDid,
|
|
537
|
+
const { did: teamDid, appUrl } = await req.getBlockletInfo();
|
|
476
538
|
const userDid = req.user.did;
|
|
477
539
|
|
|
478
|
-
|
|
479
|
-
let userInfo;
|
|
480
|
-
if (sourceAppPid) {
|
|
481
|
-
const data = await getOAuthUserInfo({ blocklet, provider, token, request: req, sourceAppPid });
|
|
482
|
-
userWallet = data.wallet;
|
|
483
|
-
userInfo = data.info;
|
|
484
|
-
} else {
|
|
485
|
-
const authClient = getAuthClient(blocklet, provider);
|
|
486
|
-
userInfo = await authClient.getProfile(token);
|
|
487
|
-
userWallet = fromAppDid(userInfo.sub, blockletWallet.secretKey);
|
|
488
|
-
}
|
|
540
|
+
const { info: oauthInfo, wallet: userWallet } = await getOAuthFederatedUserInfo(req, { blocklet });
|
|
489
541
|
let oauthUser = await node.getUser({
|
|
490
542
|
teamDid,
|
|
491
543
|
user: { did: userWallet.address },
|
|
@@ -494,17 +546,16 @@ async function bind(req, node, options) {
|
|
|
494
546
|
},
|
|
495
547
|
});
|
|
496
548
|
if (oauthUser) {
|
|
497
|
-
|
|
498
|
-
throw new ApiError(400, t('alreadyMainAccount', locale, { email: userInfo.email }));
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
throw new ApiError(400, t('alreadyBindWallet', locale, { email: userInfo.email, did: oauthUser.did }));
|
|
549
|
+
throw new ApiError(400, t('alreadyExist', locale, { email: oauthInfo.email, did: oauthUser.did }));
|
|
502
550
|
}
|
|
503
551
|
|
|
504
552
|
// NOTICE: 这里获得的 did 是当前登录用户的永久 did,无需再去查询 connectedAccount
|
|
505
553
|
const bindUser = await node.getUser({ teamDid, user: { did: userDid } });
|
|
506
|
-
|
|
507
|
-
|
|
554
|
+
|
|
555
|
+
const connectAccounts = getConnectedAccounts(bindUser);
|
|
556
|
+
|
|
557
|
+
if (connectAccounts.some((x) => x.provider === provider)) {
|
|
558
|
+
throw new ApiError(400, t('alreadyBindProvider', locale, { provider }));
|
|
508
559
|
}
|
|
509
560
|
|
|
510
561
|
const mergePassport = (oauthUser?.passports || []).reduce((sum, cur) => {
|
|
@@ -515,13 +566,13 @@ async function bind(req, node, options) {
|
|
|
515
566
|
if (!avatar) {
|
|
516
567
|
const nodeInfo = await req.getNodeInfo();
|
|
517
568
|
const { dataDir } = await getApplicationInfo({ node, nodeInfo, teamDid });
|
|
518
|
-
avatar =
|
|
569
|
+
avatar = oauthInfo.picture ? await getAvatarByUrl(oauthInfo.picture) : await getAvatarByEmail(oauthInfo.email);
|
|
519
570
|
avatar = await extractUserAvatar(avatar, { dataDir });
|
|
520
571
|
}
|
|
521
572
|
|
|
522
573
|
const mergeProfile = {
|
|
523
|
-
fullName: bindUser.fullName ||
|
|
524
|
-
email: bindUser.email ||
|
|
574
|
+
fullName: bindUser.fullName || oauthInfo.name,
|
|
575
|
+
email: bindUser.email || oauthInfo.email,
|
|
525
576
|
avatar,
|
|
526
577
|
};
|
|
527
578
|
|
|
@@ -529,11 +580,12 @@ async function bind(req, node, options) {
|
|
|
529
580
|
|
|
530
581
|
const connectedAccount = {
|
|
531
582
|
provider,
|
|
532
|
-
id:
|
|
583
|
+
id: oauthInfo.sub,
|
|
533
584
|
did: userWallet.address,
|
|
534
585
|
pk: userWallet.publicKey,
|
|
535
586
|
firstLoginAt: currentTime,
|
|
536
587
|
lastLoginAt: currentTime,
|
|
588
|
+
userInfo: oauthInfo,
|
|
537
589
|
};
|
|
538
590
|
|
|
539
591
|
await node.updateUser({
|
|
@@ -548,8 +600,8 @@ async function bind(req, node, options) {
|
|
|
548
600
|
},
|
|
549
601
|
});
|
|
550
602
|
|
|
551
|
-
const masterSite = getFederatedMaster(blocklet);
|
|
552
|
-
if (shouldSyncFederated(sourceAppPid, blocklet)) {
|
|
603
|
+
const masterSite = federatedUtil.getFederatedMaster(blocklet);
|
|
604
|
+
if (federatedUtil.shouldSyncFederated(sourceAppPid, blocklet)) {
|
|
553
605
|
// NOTICE: 采用异步来更新,不阻塞接口的正常响应
|
|
554
606
|
const syncUserData = {
|
|
555
607
|
did: bindUser.did,
|
|
@@ -593,6 +645,55 @@ async function bind(req, node, options) {
|
|
|
593
645
|
);
|
|
594
646
|
}
|
|
595
647
|
|
|
648
|
+
async function unbind(req, node) {
|
|
649
|
+
const { locale = 'en', connectedAccount, sourceAppPid } = req.body;
|
|
650
|
+
|
|
651
|
+
const userDid = req.user.did;
|
|
652
|
+
const blocklet = await req.getBlocklet();
|
|
653
|
+
const { did: teamDid } = await req.getBlockletInfo();
|
|
654
|
+
const bindUser = await node.getUser({ teamDid, user: { did: userDid } });
|
|
655
|
+
if (connectedAccount.provider === LOGIN_PROVIDER.WALLET) {
|
|
656
|
+
throw new Error(t('cantUnbindWalletAccount', locale));
|
|
657
|
+
}
|
|
658
|
+
if (getSourceProvider(bindUser) === connectedAccount.provider) {
|
|
659
|
+
throw new Error(t('cantUnbindSourceProvider', locale));
|
|
660
|
+
}
|
|
661
|
+
if (
|
|
662
|
+
!getConnectedAccounts(bindUser).some(
|
|
663
|
+
(x) => x.provider === connectedAccount.provider && x.did === connectedAccount.did && x.pk === connectedAccount.pk
|
|
664
|
+
)
|
|
665
|
+
) {
|
|
666
|
+
throw new Error(t('accountNotExist', locale));
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
await node.disconnectUserAccount({
|
|
670
|
+
teamDid,
|
|
671
|
+
connectedAccount,
|
|
672
|
+
});
|
|
673
|
+
|
|
674
|
+
const masterSite = federatedUtil.getFederatedMaster(blocklet);
|
|
675
|
+
if (federatedUtil.shouldSyncFederated(sourceAppPid, blocklet)) {
|
|
676
|
+
// NOTICE: 采用异步来更新,不阻塞接口的正常响应
|
|
677
|
+
const syncUserData = {
|
|
678
|
+
did: bindUser.did,
|
|
679
|
+
pk: bindUser.pk,
|
|
680
|
+
disconnectedAccount: connectedAccount,
|
|
681
|
+
};
|
|
682
|
+
node.syncFederated({
|
|
683
|
+
did: teamDid,
|
|
684
|
+
data: {
|
|
685
|
+
users: [
|
|
686
|
+
{
|
|
687
|
+
...syncUserData,
|
|
688
|
+
action: 'disconnectAccount',
|
|
689
|
+
sourceAppPid: sourceAppPid || masterSite?.appPid,
|
|
690
|
+
},
|
|
691
|
+
],
|
|
692
|
+
},
|
|
693
|
+
});
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
|
|
596
697
|
module.exports = {
|
|
597
698
|
init(server, node, options) {
|
|
598
699
|
async function configsFn(req, res) {
|
|
@@ -686,6 +787,22 @@ module.exports = {
|
|
|
686
787
|
server.post(`${prefix}/bind`, bindFn);
|
|
687
788
|
server.post(`${prefixApi}/bind`, bindFn);
|
|
688
789
|
|
|
790
|
+
async function unbindFn(req, res) {
|
|
791
|
+
try {
|
|
792
|
+
await unbind(req, node, options);
|
|
793
|
+
res.status(200).json({});
|
|
794
|
+
} catch (err) {
|
|
795
|
+
logger.error('Failed unbind oauth', { error: err });
|
|
796
|
+
if (err instanceof ApiError) {
|
|
797
|
+
res.status(err.code).send(err.message);
|
|
798
|
+
return;
|
|
799
|
+
}
|
|
800
|
+
throw err;
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
server.post(`${prefixApi}/unbind`, unbindFn);
|
|
805
|
+
|
|
689
806
|
async function switchFn(req, res) {
|
|
690
807
|
const { did: userDid, provider } = req.user;
|
|
691
808
|
const { passportId } = req.body;
|
|
@@ -751,11 +868,10 @@ module.exports = {
|
|
|
751
868
|
server.post(`${prefixApi}/login`, loginFn);
|
|
752
869
|
|
|
753
870
|
async function getUserFn(req, res) {
|
|
754
|
-
const { token,
|
|
755
|
-
const { wallet: blockletWallet } = await req.getBlockletInfo();
|
|
871
|
+
const { provider, token, idToken, code, appPid } = req.body;
|
|
756
872
|
const blocklet = await req.getBlocklet();
|
|
757
|
-
const
|
|
758
|
-
const
|
|
873
|
+
const oauthInfo = await getOAuthUserInfo({ blocklet, provider, token, idToken, code, appPid });
|
|
874
|
+
const { wallet: blockletWallet } = await req.getBlockletInfo();
|
|
759
875
|
const userWallet = fromAppDid(oauthInfo.sub, blockletWallet.secretKey);
|
|
760
876
|
|
|
761
877
|
res.json({
|
|
@@ -765,5 +881,44 @@ module.exports = {
|
|
|
765
881
|
}
|
|
766
882
|
server.post(`${prefix}/getUser`, getUserFn);
|
|
767
883
|
server.post(`${prefixApi}/getUser`, getUserFn);
|
|
884
|
+
|
|
885
|
+
server.get(`${prefix}/login/:provider`, async (req, res) => {
|
|
886
|
+
const { provider } = req.params;
|
|
887
|
+
const blocklet = await req.getBlocklet();
|
|
888
|
+
const avaliableProviderList = Object.keys(blocklet.settings?.oauth).filter(
|
|
889
|
+
(x) => blocklet.settings?.oauth[x]?.enabled === true
|
|
890
|
+
);
|
|
891
|
+
if (!avaliableProviderList.includes(provider)) {
|
|
892
|
+
res.status(400).send(`Provider: ${provider} is not supported`);
|
|
893
|
+
return;
|
|
894
|
+
}
|
|
895
|
+
const client = getAuthClient(blocklet, provider);
|
|
896
|
+
const authUrl = client.getAuthorizationUrl();
|
|
897
|
+
res.redirect(authUrl);
|
|
898
|
+
});
|
|
899
|
+
// HACK: apple 需要特殊处理,callback 使用的是 post 请求返回的,通过特殊处理转为 get 请求,转由前端继续处理
|
|
900
|
+
// 此处改为所有 provider 都兼容的模式
|
|
901
|
+
server.post(`${prefix}/callback/:provider`, (req, res) => {
|
|
902
|
+
/**
|
|
903
|
+
* @type {{code?: string, user?: {name: {firstName: string, lastName: string}, email: string}}}
|
|
904
|
+
*/
|
|
905
|
+
const { code, user } = req.body;
|
|
906
|
+
// HACK: URL 构造函数必须传入一个域名
|
|
907
|
+
const redirectUrl = new URL(req.url, 'http://127.0.0.1');
|
|
908
|
+
if (code) {
|
|
909
|
+
redirectUrl.searchParams.set('code', code);
|
|
910
|
+
if (user) {
|
|
911
|
+
// FIXME: @zhanghan apple 的用户名信息只会在首次获取 code 时出现,该如何将这个值传递给另一个接口中?
|
|
912
|
+
// 即使如此处理,也无法完全解决后续无法获取到用户名的问题。如果一个已有的 oauth 配置配置到了另一个应用中,对于 apple 来说,该用户已经不是第一次登录了,就不会返回用户名信息
|
|
913
|
+
// redirectUrl.searchParams.set('name', `${user.name.firstName} ${user.name.lastName}`);
|
|
914
|
+
}
|
|
915
|
+
} else {
|
|
916
|
+
const error = 'true';
|
|
917
|
+
const errorDescription = 'invalid code';
|
|
918
|
+
redirectUrl.searchParams.set('error', error);
|
|
919
|
+
redirectUrl.searchParams.set('error_description', errorDescription);
|
|
920
|
+
}
|
|
921
|
+
res.redirect(`${redirectUrl.pathname}${redirectUrl.search}`);
|
|
922
|
+
});
|
|
768
923
|
},
|
|
769
924
|
};
|
|
@@ -252,7 +252,13 @@ module.exports = function createRoutes(node, _, createSessionToken) {
|
|
|
252
252
|
locale,
|
|
253
253
|
lastLoginIp: get(req, 'headers[x-real-ip]') || '',
|
|
254
254
|
passports: [passport],
|
|
255
|
-
connectedAccounts: [
|
|
255
|
+
connectedAccounts: [
|
|
256
|
+
{
|
|
257
|
+
provider: LOGIN_PROVIDER.WALLET,
|
|
258
|
+
did: userDid,
|
|
259
|
+
pk: userPk,
|
|
260
|
+
},
|
|
261
|
+
],
|
|
256
262
|
...profile,
|
|
257
263
|
avatar,
|
|
258
264
|
},
|
|
@@ -3,6 +3,8 @@ const { default: urlFriendly } = require('@blocklet/meta/lib/url-friendly');
|
|
|
3
3
|
const { slugify } = require('transliteration');
|
|
4
4
|
const { MAIN_CHAIN_ENDPOINT } = require('@abtnode/constant');
|
|
5
5
|
const { getBlockletChainInfo } = require('@blocklet/meta/lib/util');
|
|
6
|
+
const jwt = require('jsonwebtoken');
|
|
7
|
+
const jwksClient = require('jwks-rsa');
|
|
6
8
|
|
|
7
9
|
const logger = require('../../libs/logger')('blocklet-services:oauth');
|
|
8
10
|
|
|
@@ -78,7 +80,75 @@ async function migrateAccount({ wallet, blocklet, user }) {
|
|
|
78
80
|
await Promise.all(waitingList);
|
|
79
81
|
}
|
|
80
82
|
|
|
83
|
+
async function getJWK(kid, jwksUri) {
|
|
84
|
+
const client = jwksClient({
|
|
85
|
+
cache: true,
|
|
86
|
+
jwksUri,
|
|
87
|
+
});
|
|
88
|
+
const key = await new Promise((resolve, reject) => {
|
|
89
|
+
client.getSigningKey(kid, (error, result) => {
|
|
90
|
+
if (error) {
|
|
91
|
+
return reject(error);
|
|
92
|
+
}
|
|
93
|
+
return resolve(result);
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
return {
|
|
97
|
+
publicKey: key.getPublicKey(),
|
|
98
|
+
kid: key.kid,
|
|
99
|
+
alg: key.alg,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Verify the authenticity of a token by decoding, verifying the algorithm, and matching claims.
|
|
105
|
+
*
|
|
106
|
+
* @param {Object} params - Object containing idToken, jwksUri, nonce, iss, clientId
|
|
107
|
+
* @param {string} params.idToken - JWT token
|
|
108
|
+
* @param {string} params.jwksUri - JWK set URI
|
|
109
|
+
* @param {string} params.nonce - Nonce
|
|
110
|
+
* @param {string} params.iss - Issuer
|
|
111
|
+
* @param {string} params.clientId - Client ID
|
|
112
|
+
* @return {Object} Decoded JWT claims if token is valid
|
|
113
|
+
*/
|
|
114
|
+
async function verifyIdToken(params) {
|
|
115
|
+
const decoded = jwt.decode(params.idToken, { complete: true });
|
|
116
|
+
const { kid, alg: jwtAlg } = decoded.header;
|
|
117
|
+
|
|
118
|
+
const { publicKey, alg: jwkAlg } = await getJWK(kid, params.jwksUri);
|
|
119
|
+
|
|
120
|
+
if (jwtAlg !== jwkAlg) {
|
|
121
|
+
throw new Error(`The alg does not match the jwk configuration - alg: ${jwtAlg} | expected: ${jwkAlg}`);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const jwtClaims = jwt.verify(params.idToken, publicKey, {
|
|
125
|
+
algorithms: [jwkAlg],
|
|
126
|
+
nonce: params.nonce,
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
if (jwtClaims?.iss !== params.iss) {
|
|
130
|
+
throw new Error(`The iss does not match the Apple URL - iss: ${jwtClaims.iss} | expected: ${params.iss}`);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const isFounded = [].concat(jwtClaims.aud).some((aud) => [].concat(params.clientId).includes(aud));
|
|
134
|
+
|
|
135
|
+
if (isFounded) {
|
|
136
|
+
['email_verified', 'is_private_email'].forEach((field) => {
|
|
137
|
+
if (jwtClaims[field] !== undefined) {
|
|
138
|
+
jwtClaims[field] = Boolean(jwtClaims[field]);
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
return jwtClaims;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
throw new Error(
|
|
146
|
+
`The aud parameter does not include this client - is: ${jwtClaims.aud} | expected: ${params.clientId}`
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
|
|
81
150
|
module.exports = {
|
|
82
151
|
declareAccount,
|
|
83
152
|
migrateAccount,
|
|
153
|
+
verifyIdToken,
|
|
84
154
|
};
|