@strapi/plugin-users-permissions 0.0.0-experimental.6340da17068c3bed7fb006e7bcc554c71129e282 → 0.0.0-experimental.63624e21eb5b0713345a0cf2f68f1c40eab427bc
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/.eslintrc.cjs +2 -0
- package/admin/src/pages/EmailTemplates/components/EmailForm.jsx +3 -1
- package/admin/src/pages/Roles/pages/EditPage.jsx +1 -1
- package/admin/src/pages/Roles/pages/ListPage/index.jsx +1 -1
- package/admin/src/translations/en.json +1 -0
- package/admin/src/translations/es.json +1 -1
- package/admin/src/translations/ko.json +2 -1
- package/admin/src/translations/sv.json +1 -1
- package/admin/src/translations/uk.json +1 -1
- package/dist/admin/pages/EmailTemplates/components/EmailForm.js +2 -1
- package/dist/admin/pages/EmailTemplates/components/EmailForm.js.map +1 -1
- package/dist/admin/pages/EmailTemplates/components/EmailForm.mjs +2 -1
- package/dist/admin/pages/EmailTemplates/components/EmailForm.mjs.map +1 -1
- package/dist/admin/pages/Roles/pages/EditPage.js +1 -1
- package/dist/admin/pages/Roles/pages/EditPage.js.map +1 -1
- package/dist/admin/pages/Roles/pages/EditPage.mjs +1 -1
- package/dist/admin/pages/Roles/pages/EditPage.mjs.map +1 -1
- package/dist/admin/pages/Roles/pages/ListPage/index.js +1 -1
- package/dist/admin/pages/Roles/pages/ListPage/index.js.map +1 -1
- package/dist/admin/pages/Roles/pages/ListPage/index.mjs +1 -1
- package/dist/admin/pages/Roles/pages/ListPage/index.mjs.map +1 -1
- package/dist/admin/translations/en.json.js +1 -0
- package/dist/admin/translations/en.json.js.map +1 -1
- package/dist/admin/translations/en.json.mjs +1 -0
- package/dist/admin/translations/en.json.mjs.map +1 -1
- package/dist/admin/translations/es.json.js +1 -1
- package/dist/admin/translations/es.json.mjs +1 -1
- package/dist/admin/translations/ko.json.js +2 -1
- package/dist/admin/translations/ko.json.js.map +1 -1
- package/dist/admin/translations/ko.json.mjs +2 -1
- package/dist/admin/translations/ko.json.mjs.map +1 -1
- package/dist/admin/translations/sv.json.js +1 -1
- package/dist/admin/translations/sv.json.mjs +1 -1
- package/dist/admin/translations/uk.json.js +1 -1
- package/dist/admin/translations/uk.json.mjs +1 -1
- package/dist/server/_virtual/_node_crypto.js +10 -0
- package/dist/server/_virtual/_node_crypto.js.map +1 -0
- package/dist/server/_virtual/_node_crypto.mjs +7 -0
- package/dist/server/_virtual/_node_crypto.mjs.map +1 -0
- package/dist/server/_virtual/_node_url.js +10 -0
- package/dist/server/_virtual/_node_url.js.map +1 -0
- package/dist/server/_virtual/_node_url.mjs +7 -0
- package/dist/server/_virtual/_node_url.mjs.map +1 -0
- package/dist/server/bootstrap/index.js.map +1 -1
- package/dist/server/bootstrap/index.mjs.map +1 -1
- package/dist/server/bootstrap/users-permissions-actions.js.map +1 -1
- package/dist/server/bootstrap/users-permissions-actions.mjs.map +1 -1
- package/dist/server/config.js.map +1 -1
- package/dist/server/config.mjs.map +1 -1
- package/dist/server/content-types/index.js.map +1 -1
- package/dist/server/content-types/index.mjs.map +1 -1
- package/dist/server/content-types/permission/index.js.map +1 -1
- package/dist/server/content-types/permission/index.mjs.map +1 -1
- package/dist/server/content-types/role/index.js.map +1 -1
- package/dist/server/content-types/role/index.mjs.map +1 -1
- package/dist/server/content-types/user/index.js.map +1 -1
- package/dist/server/content-types/user/index.mjs.map +1 -1
- package/dist/server/content-types/user/schema-config.js.map +1 -1
- package/dist/server/content-types/user/schema-config.mjs.map +1 -1
- package/dist/server/controllers/auth.js +38 -30
- package/dist/server/controllers/auth.js.map +1 -1
- package/dist/server/controllers/auth.mjs +38 -28
- package/dist/server/controllers/auth.mjs.map +1 -1
- package/dist/server/controllers/content-manager-user.js.map +1 -1
- package/dist/server/controllers/content-manager-user.mjs.map +1 -1
- package/dist/server/controllers/index.js.map +1 -1
- package/dist/server/controllers/index.mjs.map +1 -1
- package/dist/server/controllers/permissions.js.map +1 -1
- package/dist/server/controllers/permissions.mjs.map +1 -1
- package/dist/server/controllers/role.js.map +1 -1
- package/dist/server/controllers/role.mjs.map +1 -1
- package/dist/server/controllers/settings.js.map +1 -1
- package/dist/server/controllers/settings.mjs.map +1 -1
- package/dist/server/controllers/user.js.map +1 -1
- package/dist/server/controllers/user.mjs.map +1 -1
- package/dist/server/controllers/validation/auth.js +6 -6
- package/dist/server/controllers/validation/auth.js.map +1 -1
- package/dist/server/controllers/validation/auth.mjs +6 -6
- package/dist/server/controllers/validation/auth.mjs.map +1 -1
- package/dist/server/controllers/validation/email-template.js +1 -4
- package/dist/server/controllers/validation/email-template.js.map +1 -1
- package/dist/server/controllers/validation/email-template.mjs +1 -3
- package/dist/server/controllers/validation/email-template.mjs.map +1 -1
- package/dist/server/controllers/validation/user.js.map +1 -1
- package/dist/server/controllers/validation/user.mjs.map +1 -1
- package/dist/server/graphql/index.js.map +1 -1
- package/dist/server/graphql/index.mjs.map +1 -1
- package/dist/server/graphql/mutations/auth/change-password.js +7 -4
- package/dist/server/graphql/mutations/auth/change-password.js.map +1 -1
- package/dist/server/graphql/mutations/auth/change-password.mjs +7 -4
- package/dist/server/graphql/mutations/auth/change-password.mjs.map +1 -1
- package/dist/server/graphql/mutations/auth/email-confirmation.js +1 -1
- package/dist/server/graphql/mutations/auth/email-confirmation.js.map +1 -1
- package/dist/server/graphql/mutations/auth/email-confirmation.mjs +1 -1
- package/dist/server/graphql/mutations/auth/email-confirmation.mjs.map +1 -1
- package/dist/server/graphql/mutations/auth/forgot-password.js +7 -4
- package/dist/server/graphql/mutations/auth/forgot-password.js.map +1 -1
- package/dist/server/graphql/mutations/auth/forgot-password.mjs +7 -4
- package/dist/server/graphql/mutations/auth/forgot-password.mjs.map +1 -1
- package/dist/server/graphql/mutations/auth/login.js +10 -7
- package/dist/server/graphql/mutations/auth/login.js.map +1 -1
- package/dist/server/graphql/mutations/auth/login.mjs +10 -7
- package/dist/server/graphql/mutations/auth/login.mjs.map +1 -1
- package/dist/server/graphql/mutations/auth/rate-limit.js +63 -0
- package/dist/server/graphql/mutations/auth/rate-limit.js.map +1 -0
- package/dist/server/graphql/mutations/auth/rate-limit.mjs +61 -0
- package/dist/server/graphql/mutations/auth/rate-limit.mjs.map +1 -0
- package/dist/server/graphql/mutations/auth/register.js +7 -4
- package/dist/server/graphql/mutations/auth/register.js.map +1 -1
- package/dist/server/graphql/mutations/auth/register.mjs +7 -4
- package/dist/server/graphql/mutations/auth/register.mjs.map +1 -1
- package/dist/server/graphql/mutations/auth/reset-password.js +7 -4
- package/dist/server/graphql/mutations/auth/reset-password.js.map +1 -1
- package/dist/server/graphql/mutations/auth/reset-password.mjs +7 -4
- package/dist/server/graphql/mutations/auth/reset-password.mjs.map +1 -1
- package/dist/server/graphql/mutations/crud/role/create-role.js +1 -1
- package/dist/server/graphql/mutations/crud/role/create-role.js.map +1 -1
- package/dist/server/graphql/mutations/crud/role/create-role.mjs +1 -1
- package/dist/server/graphql/mutations/crud/role/create-role.mjs.map +1 -1
- package/dist/server/graphql/mutations/crud/role/delete-role.js.map +1 -1
- package/dist/server/graphql/mutations/crud/role/delete-role.mjs.map +1 -1
- package/dist/server/graphql/mutations/crud/role/update-role.js.map +1 -1
- package/dist/server/graphql/mutations/crud/role/update-role.mjs.map +1 -1
- package/dist/server/graphql/mutations/crud/user/create-user.js +1 -1
- package/dist/server/graphql/mutations/crud/user/create-user.js.map +1 -1
- package/dist/server/graphql/mutations/crud/user/create-user.mjs +1 -1
- package/dist/server/graphql/mutations/crud/user/create-user.mjs.map +1 -1
- package/dist/server/graphql/mutations/crud/user/delete-user.js.map +1 -1
- package/dist/server/graphql/mutations/crud/user/delete-user.mjs.map +1 -1
- package/dist/server/graphql/mutations/crud/user/update-user.js +1 -1
- package/dist/server/graphql/mutations/crud/user/update-user.js.map +1 -1
- package/dist/server/graphql/mutations/crud/user/update-user.mjs +1 -1
- package/dist/server/graphql/mutations/crud/user/update-user.mjs.map +1 -1
- package/dist/server/graphql/mutations/index.js.map +1 -1
- package/dist/server/graphql/mutations/index.mjs.map +1 -1
- package/dist/server/graphql/queries/index.js.map +1 -1
- package/dist/server/graphql/queries/index.mjs.map +1 -1
- package/dist/server/graphql/queries/me.js.map +1 -1
- package/dist/server/graphql/queries/me.mjs.map +1 -1
- package/dist/server/graphql/resolvers-configs.js.map +1 -1
- package/dist/server/graphql/resolvers-configs.mjs.map +1 -1
- package/dist/server/graphql/types/create-role-payload.js.map +1 -1
- package/dist/server/graphql/types/create-role-payload.mjs.map +1 -1
- package/dist/server/graphql/types/delete-role-payload.js.map +1 -1
- package/dist/server/graphql/types/delete-role-payload.mjs.map +1 -1
- package/dist/server/graphql/types/index.js.map +1 -1
- package/dist/server/graphql/types/index.mjs.map +1 -1
- package/dist/server/graphql/types/login-input.js.map +1 -1
- package/dist/server/graphql/types/login-input.mjs.map +1 -1
- package/dist/server/graphql/types/login-payload.js.map +1 -1
- package/dist/server/graphql/types/login-payload.mjs.map +1 -1
- package/dist/server/graphql/types/me-role.js.map +1 -1
- package/dist/server/graphql/types/me-role.mjs.map +1 -1
- package/dist/server/graphql/types/me.js.map +1 -1
- package/dist/server/graphql/types/me.mjs.map +1 -1
- package/dist/server/graphql/types/password-payload.js.map +1 -1
- package/dist/server/graphql/types/password-payload.mjs.map +1 -1
- package/dist/server/graphql/types/register-input.js.map +1 -1
- package/dist/server/graphql/types/register-input.mjs.map +1 -1
- package/dist/server/graphql/types/update-role-payload.js.map +1 -1
- package/dist/server/graphql/types/update-role-payload.mjs.map +1 -1
- package/dist/server/graphql/types/user-input.js.map +1 -1
- package/dist/server/graphql/types/user-input.mjs.map +1 -1
- package/dist/server/graphql/utils.js +4 -4
- package/dist/server/graphql/utils.js.map +1 -1
- package/dist/server/graphql/utils.mjs +4 -4
- package/dist/server/graphql/utils.mjs.map +1 -1
- package/dist/server/index.js +2 -2
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +3 -3
- package/dist/server/index.mjs.map +1 -1
- package/dist/server/index2.js +8 -8
- package/dist/server/index2.js.map +1 -1
- package/dist/server/index2.mjs +8 -8
- package/dist/server/index2.mjs.map +1 -1
- package/dist/server/middlewares/index.js.map +1 -1
- package/dist/server/middlewares/index.mjs.map +1 -1
- package/dist/server/middlewares/rateLimit.js +5 -5
- package/dist/server/middlewares/rateLimit.js.map +1 -1
- package/dist/server/middlewares/rateLimit.mjs +5 -5
- package/dist/server/middlewares/rateLimit.mjs.map +1 -1
- package/dist/server/register.js.map +1 -1
- package/dist/server/register.mjs.map +1 -1
- package/dist/server/routes/admin/index.js.map +1 -1
- package/dist/server/routes/admin/index.mjs.map +1 -1
- package/dist/server/routes/admin/permissions.js.map +1 -1
- package/dist/server/routes/admin/permissions.mjs.map +1 -1
- package/dist/server/routes/admin/role.js.map +1 -1
- package/dist/server/routes/admin/role.mjs.map +1 -1
- package/dist/server/routes/admin/settings.js.map +1 -1
- package/dist/server/routes/admin/settings.mjs.map +1 -1
- package/dist/server/routes/content-api/auth.js.map +1 -1
- package/dist/server/routes/content-api/auth.mjs.map +1 -1
- package/dist/server/routes/content-api/index.js.map +1 -1
- package/dist/server/routes/content-api/index.mjs.map +1 -1
- package/dist/server/routes/content-api/permissions.js.map +1 -1
- package/dist/server/routes/content-api/permissions.mjs.map +1 -1
- package/dist/server/routes/content-api/role.js.map +1 -1
- package/dist/server/routes/content-api/role.mjs.map +1 -1
- package/dist/server/routes/content-api/user.js.map +1 -1
- package/dist/server/routes/content-api/user.mjs.map +1 -1
- package/dist/server/routes/content-api/validation.js.map +1 -1
- package/dist/server/routes/content-api/validation.mjs.map +1 -1
- package/dist/server/routes/index.js.map +1 -1
- package/dist/server/routes/index.mjs.map +1 -1
- package/dist/server/services/constants.js.map +1 -1
- package/dist/server/services/constants.mjs.map +1 -1
- package/dist/server/services/index.js.map +1 -1
- package/dist/server/services/index.mjs.map +1 -1
- package/dist/server/services/jwt.js.map +1 -1
- package/dist/server/services/jwt.mjs.map +1 -1
- package/dist/server/services/permission.js.map +1 -1
- package/dist/server/services/permission.mjs.map +1 -1
- package/dist/server/services/providers-registry.js +188 -248
- package/dist/server/services/providers-registry.js.map +1 -1
- package/dist/server/services/providers-registry.mjs +188 -245
- package/dist/server/services/providers-registry.mjs.map +1 -1
- package/dist/server/services/providers.js +15 -11
- package/dist/server/services/providers.js.map +1 -1
- package/dist/server/services/providers.mjs +14 -10
- package/dist/server/services/providers.mjs.map +1 -1
- package/dist/server/services/role.js +2 -2
- package/dist/server/services/role.js.map +1 -1
- package/dist/server/services/role.mjs +2 -2
- package/dist/server/services/role.mjs.map +1 -1
- package/dist/server/services/user.js +14 -14
- package/dist/server/services/user.js.map +1 -1
- package/dist/server/services/user.mjs +13 -13
- package/dist/server/services/user.mjs.map +1 -1
- package/dist/server/services/users-permissions.js +17 -20
- package/dist/server/services/users-permissions.js.map +1 -1
- package/dist/server/services/users-permissions.mjs +16 -18
- package/dist/server/services/users-permissions.mjs.map +1 -1
- package/dist/server/strategies/users-permissions.js +9 -8
- package/dist/server/strategies/users-permissions.js.map +1 -1
- package/dist/server/strategies/users-permissions.mjs +9 -8
- package/dist/server/strategies/users-permissions.mjs.map +1 -1
- package/dist/server/utils/index.js.map +1 -1
- package/dist/server/utils/index.mjs.map +1 -1
- package/dist/server/utils/oauth-connect/index.js +241 -0
- package/dist/server/utils/oauth-connect/index.js.map +1 -0
- package/dist/server/utils/oauth-connect/index.mjs +235 -0
- package/dist/server/utils/oauth-connect/index.mjs.map +1 -0
- package/dist/server/utils/oauth-connect/oauth1.js +138 -0
- package/dist/server/utils/oauth-connect/oauth1.js.map +1 -0
- package/dist/server/utils/oauth-connect/oauth1.mjs +136 -0
- package/dist/server/utils/oauth-connect/oauth1.mjs.map +1 -0
- package/dist/server/utils/oauth-connect/oauth2.js +117 -0
- package/dist/server/utils/oauth-connect/oauth2.js.map +1 -0
- package/dist/server/utils/oauth-connect/oauth2.mjs +115 -0
- package/dist/server/utils/oauth-connect/oauth2.mjs.map +1 -0
- package/dist/server/utils/oauth-connect/providers.js +109 -0
- package/dist/server/utils/oauth-connect/providers.js.map +1 -0
- package/dist/server/utils/oauth-connect/providers.mjs +107 -0
- package/dist/server/utils/oauth-connect/providers.mjs.map +1 -0
- package/dist/server/utils/provider-http.js +52 -0
- package/dist/server/utils/provider-http.js.map +1 -0
- package/dist/server/utils/provider-http.mjs +50 -0
- package/dist/server/utils/provider-http.mjs.map +1 -0
- package/dist/server/utils/refresh-cookie-options.js.map +1 -1
- package/dist/server/utils/refresh-cookie-options.mjs.map +1 -1
- package/dist/server/utils/sanitize/index.js.map +1 -1
- package/dist/server/utils/sanitize/index.mjs.map +1 -1
- package/dist/server/utils/sanitize/sanitizers.js +1 -1
- package/dist/server/utils/sanitize/sanitizers.js.map +1 -1
- package/dist/server/utils/sanitize/sanitizers.mjs +1 -1
- package/dist/server/utils/sanitize/sanitizers.mjs.map +1 -1
- package/dist/server/utils/sanitize/visitors/index.js.map +1 -1
- package/dist/server/utils/sanitize/visitors/index.mjs.map +1 -1
- package/dist/server/utils/sanitize/visitors/remove-user-relation-from-role-entities.js.map +1 -1
- package/dist/server/utils/sanitize/visitors/remove-user-relation-from-role-entities.mjs.map +1 -1
- package/dist/server/utils/trim-grant-session-response.js +67 -0
- package/dist/server/utils/trim-grant-session-response.js.map +1 -0
- package/dist/server/utils/trim-grant-session-response.mjs +65 -0
- package/dist/server/utils/trim-grant-session-response.mjs.map +1 -0
- package/dist/server/utils/verify-jwt-with-jwks.js +60 -0
- package/dist/server/utils/verify-jwt-with-jwks.js.map +1 -0
- package/dist/server/utils/verify-jwt-with-jwks.mjs +54 -0
- package/dist/server/utils/verify-jwt-with-jwks.mjs.map +1 -0
- package/jsconfig.json +7 -0
- package/package.json +28 -18
- package/rollup.config.mjs +2 -2
- package/server/{controllers → src/controllers}/auth.js +36 -29
- package/server/{controllers → src/controllers}/validation/auth.js +6 -6
- package/server/{controllers → src/controllers}/validation/email-template.js +1 -2
- package/server/{graphql → src/graphql}/mutations/auth/change-password.js +6 -6
- package/server/{graphql → src/graphql}/mutations/auth/email-confirmation.js +1 -1
- package/server/{graphql → src/graphql}/mutations/auth/forgot-password.js +6 -6
- package/server/{graphql → src/graphql}/mutations/auth/login.js +11 -7
- package/server/src/graphql/mutations/auth/rate-limit.js +62 -0
- package/server/{graphql → src/graphql}/mutations/auth/register.js +6 -6
- package/server/{graphql → src/graphql}/mutations/auth/reset-password.js +6 -6
- package/server/{graphql → src/graphql}/mutations/crud/role/create-role.js +1 -1
- package/server/{graphql → src/graphql}/mutations/crud/user/create-user.js +1 -1
- package/server/{graphql → src/graphql}/mutations/crud/user/update-user.js +1 -1
- package/server/{graphql → src/graphql}/utils.js +3 -3
- package/server/{middlewares → src/middlewares}/rateLimit.js +4 -4
- package/server/src/services/providers-registry.js +487 -0
- package/server/{services → src/services}/providers.js +9 -7
- package/server/{services → src/services}/role.js +2 -2
- package/server/{services → src/services}/user.js +16 -6
- package/server/{services → src/services}/users-permissions.js +14 -16
- package/server/{strategies → src/strategies}/users-permissions.js +14 -10
- package/server/src/utils/oauth-connect/index.js +262 -0
- package/server/src/utils/oauth-connect/oauth1.js +169 -0
- package/server/src/utils/oauth-connect/oauth2.js +123 -0
- package/server/src/utils/oauth-connect/providers.js +100 -0
- package/server/src/utils/provider-http.js +49 -0
- package/server/{utils → src/utils}/sanitize/sanitizers.js +1 -1
- package/server/src/utils/trim-grant-session-response.js +70 -0
- package/server/src/utils/verify-jwt-with-jwks.js +43 -0
- package/types/strapi-server.d.ts +65 -0
- package/server/services/providers-registry.js +0 -567
- package/server/utils/index.d.ts +0 -23
- /package/server/{bootstrap → src/bootstrap}/index.js +0 -0
- /package/server/{bootstrap → src/bootstrap}/users-permissions-actions.js +0 -0
- /package/server/{config.js → src/config.js} +0 -0
- /package/server/{content-types → src/content-types}/index.js +0 -0
- /package/server/{content-types → src/content-types}/permission/index.js +0 -0
- /package/server/{content-types → src/content-types}/role/index.js +0 -0
- /package/server/{content-types → src/content-types}/user/index.js +0 -0
- /package/server/{content-types → src/content-types}/user/schema-config.js +0 -0
- /package/server/{controllers → src/controllers}/content-manager-user.js +0 -0
- /package/server/{controllers → src/controllers}/index.js +0 -0
- /package/server/{controllers → src/controllers}/permissions.js +0 -0
- /package/server/{controllers → src/controllers}/role.js +0 -0
- /package/server/{controllers → src/controllers}/settings.js +0 -0
- /package/server/{controllers → src/controllers}/user.js +0 -0
- /package/server/{controllers → src/controllers}/validation/user.js +0 -0
- /package/server/{graphql → src/graphql}/index.js +0 -0
- /package/server/{graphql → src/graphql}/mutations/crud/role/delete-role.js +0 -0
- /package/server/{graphql → src/graphql}/mutations/crud/role/update-role.js +0 -0
- /package/server/{graphql → src/graphql}/mutations/crud/user/delete-user.js +0 -0
- /package/server/{graphql → src/graphql}/mutations/index.js +0 -0
- /package/server/{graphql → src/graphql}/queries/index.js +0 -0
- /package/server/{graphql → src/graphql}/queries/me.js +0 -0
- /package/server/{graphql → src/graphql}/resolvers-configs.js +0 -0
- /package/server/{graphql → src/graphql}/types/create-role-payload.js +0 -0
- /package/server/{graphql → src/graphql}/types/delete-role-payload.js +0 -0
- /package/server/{graphql → src/graphql}/types/index.js +0 -0
- /package/server/{graphql → src/graphql}/types/login-input.js +0 -0
- /package/server/{graphql → src/graphql}/types/login-payload.js +0 -0
- /package/server/{graphql → src/graphql}/types/me-role.js +0 -0
- /package/server/{graphql → src/graphql}/types/me.js +0 -0
- /package/server/{graphql → src/graphql}/types/password-payload.js +0 -0
- /package/server/{graphql → src/graphql}/types/register-input.js +0 -0
- /package/server/{graphql → src/graphql}/types/update-role-payload.js +0 -0
- /package/server/{graphql → src/graphql}/types/user-input.js +0 -0
- /package/server/{index.js → src/index.js} +0 -0
- /package/server/{middlewares → src/middlewares}/index.js +0 -0
- /package/server/{register.js → src/register.js} +0 -0
- /package/server/{routes → src/routes}/admin/index.js +0 -0
- /package/server/{routes → src/routes}/admin/permissions.js +0 -0
- /package/server/{routes → src/routes}/admin/role.js +0 -0
- /package/server/{routes → src/routes}/admin/settings.js +0 -0
- /package/server/{routes → src/routes}/content-api/auth.js +0 -0
- /package/server/{routes → src/routes}/content-api/index.js +0 -0
- /package/server/{routes → src/routes}/content-api/permissions.js +0 -0
- /package/server/{routes → src/routes}/content-api/role.js +0 -0
- /package/server/{routes → src/routes}/content-api/user.js +0 -0
- /package/server/{routes → src/routes}/content-api/validation.js +0 -0
- /package/server/{routes → src/routes}/index.js +0 -0
- /package/server/{services → src/services}/constants.js +0 -0
- /package/server/{services → src/services}/index.js +0 -0
- /package/server/{services → src/services}/jwt.js +0 -0
- /package/server/{services → src/services}/permission.js +0 -0
- /package/server/{utils → src/utils}/index.js +0 -0
- /package/server/{utils → src/utils}/refresh-cookie-options.js +0 -0
- /package/server/{utils → src/utils}/sanitize/index.js +0 -0
- /package/server/{utils → src/utils}/sanitize/visitors/index.js +0 -0
- /package/server/{utils → src/utils}/sanitize/visitors/remove-user-relation-from-role-entities.js +0 -0
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const _ = require('lodash');
|
|
4
|
-
const { filter, map, pipe, prop } = require('lodash/fp');
|
|
5
4
|
const urlJoin = require('url-join');
|
|
6
5
|
const {
|
|
7
6
|
template: { createStrictInterpolationRegExp },
|
|
@@ -50,7 +49,7 @@ module.exports = ({ strapi }) => ({
|
|
|
50
49
|
return action[Symbol.for('__type__')].includes('content-api');
|
|
51
50
|
};
|
|
52
51
|
|
|
53
|
-
|
|
52
|
+
for (const [apiName, api] of Object.entries(strapi.apis)) {
|
|
54
53
|
const controllers = _.reduce(
|
|
55
54
|
api.controllers,
|
|
56
55
|
(acc, controller, controllerName) => {
|
|
@@ -75,9 +74,9 @@ module.exports = ({ strapi }) => ({
|
|
|
75
74
|
if (!_.isEmpty(controllers)) {
|
|
76
75
|
actionMap[`api::${apiName}`] = { controllers };
|
|
77
76
|
}
|
|
78
|
-
}
|
|
77
|
+
}
|
|
79
78
|
|
|
80
|
-
|
|
79
|
+
for (const [pluginName, plugin] of Object.entries(strapi.plugins)) {
|
|
81
80
|
const controllers = _.reduce(
|
|
82
81
|
plugin.controllers,
|
|
83
82
|
(acc, controller, controllerName) => {
|
|
@@ -102,7 +101,7 @@ module.exports = ({ strapi }) => ({
|
|
|
102
101
|
if (!_.isEmpty(controllers)) {
|
|
103
102
|
actionMap[`plugin::${pluginName}`] = { controllers };
|
|
104
103
|
}
|
|
105
|
-
}
|
|
104
|
+
}
|
|
106
105
|
|
|
107
106
|
// Return a deeply cloned version to avoid circular references
|
|
108
107
|
return _.cloneDeep(actionMap);
|
|
@@ -111,7 +110,7 @@ module.exports = ({ strapi }) => ({
|
|
|
111
110
|
async getRoutes() {
|
|
112
111
|
const routesMap = {};
|
|
113
112
|
|
|
114
|
-
|
|
113
|
+
for (const [apiName, api] of Object.entries(strapi.apis)) {
|
|
115
114
|
const routes = _.flatMap(api.routes, (route) => {
|
|
116
115
|
if (_.has(route, 'routes')) {
|
|
117
116
|
return route.routes;
|
|
@@ -121,7 +120,7 @@ module.exports = ({ strapi }) => ({
|
|
|
121
120
|
}).filter((route) => route.info.type === 'content-api');
|
|
122
121
|
|
|
123
122
|
if (routes.length === 0) {
|
|
124
|
-
|
|
123
|
+
continue;
|
|
125
124
|
}
|
|
126
125
|
|
|
127
126
|
const apiPrefix = strapi.config.get('api.rest.prefix');
|
|
@@ -129,9 +128,9 @@ module.exports = ({ strapi }) => ({
|
|
|
129
128
|
...route,
|
|
130
129
|
path: urlJoin(apiPrefix, route.path),
|
|
131
130
|
}));
|
|
132
|
-
}
|
|
131
|
+
}
|
|
133
132
|
|
|
134
|
-
|
|
133
|
+
for (const [pluginName, plugin] of Object.entries(strapi.plugins)) {
|
|
135
134
|
const transformPrefix = transformRoutePrefixFor(pluginName);
|
|
136
135
|
|
|
137
136
|
const routes = _.flatMap(plugin.routes, (route) => {
|
|
@@ -143,7 +142,7 @@ module.exports = ({ strapi }) => ({
|
|
|
143
142
|
}).filter((route) => route.info.type === 'content-api');
|
|
144
143
|
|
|
145
144
|
if (routes.length === 0) {
|
|
146
|
-
|
|
145
|
+
continue;
|
|
147
146
|
}
|
|
148
147
|
|
|
149
148
|
const apiPrefix = strapi.config.get('api.rest.prefix');
|
|
@@ -151,7 +150,7 @@ module.exports = ({ strapi }) => ({
|
|
|
151
150
|
...route,
|
|
152
151
|
path: urlJoin(apiPrefix, route.path),
|
|
153
152
|
}));
|
|
154
|
-
}
|
|
153
|
+
}
|
|
155
154
|
|
|
156
155
|
return sanitizeRoutesMapForSerialization(routesMap);
|
|
157
156
|
},
|
|
@@ -193,10 +192,9 @@ module.exports = ({ strapi }) => ({
|
|
|
193
192
|
if (permissionsFoundInDB.length === 0) {
|
|
194
193
|
// create default permissions
|
|
195
194
|
for (const role of roles) {
|
|
196
|
-
const toCreate =
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
)(DEFAULT_PERMISSIONS);
|
|
195
|
+
const toCreate = DEFAULT_PERMISSIONS.filter(
|
|
196
|
+
({ roleType }) => roleType === role.type || roleType === null
|
|
197
|
+
).map(({ action }) => action);
|
|
200
198
|
|
|
201
199
|
await Promise.all(
|
|
202
200
|
toCreate.map((action) => {
|
|
@@ -250,7 +248,7 @@ module.exports = ({ strapi }) => ({
|
|
|
250
248
|
|
|
251
249
|
try {
|
|
252
250
|
return _.template(layout, { interpolate, evaluate: false, escape: false })(data);
|
|
253
|
-
} catch
|
|
251
|
+
} catch {
|
|
254
252
|
throw new errors.ApplicationError('Invalid email template');
|
|
255
253
|
}
|
|
256
254
|
},
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const {
|
|
3
|
+
const { map, every } = require('lodash');
|
|
4
4
|
const { ForbiddenError, UnauthorizedError } = require('@strapi/utils').errors;
|
|
5
5
|
|
|
6
6
|
const { getService } = require('../utils');
|
|
@@ -43,7 +43,11 @@ const authenticate = async (ctx) => {
|
|
|
43
43
|
// Fetch user's permissions
|
|
44
44
|
const permissions = await Promise.resolve(user.role.id)
|
|
45
45
|
.then(getService('permission').findRolePermissions)
|
|
46
|
-
.then(
|
|
46
|
+
.then((permissions) =>
|
|
47
|
+
map(permissions, (permission) =>
|
|
48
|
+
getService('permission').toContentAPIPermission(permission)
|
|
49
|
+
)
|
|
50
|
+
);
|
|
47
51
|
|
|
48
52
|
// Generate an ability (content API engine) based on the given permissions
|
|
49
53
|
const ability = await strapi.contentAPI.permissions.engine.generateAbility(permissions);
|
|
@@ -64,7 +68,11 @@ const authenticate = async (ctx) => {
|
|
|
64
68
|
|
|
65
69
|
const publicPermissions = await getService('permission')
|
|
66
70
|
.findPublicPermissions()
|
|
67
|
-
.then(
|
|
71
|
+
.then((permissions) =>
|
|
72
|
+
map(permissions, (permission) =>
|
|
73
|
+
getService('permission').toContentAPIPermission(permission)
|
|
74
|
+
)
|
|
75
|
+
);
|
|
68
76
|
|
|
69
77
|
if (publicPermissions.length === 0) {
|
|
70
78
|
return { authenticated: false };
|
|
@@ -77,7 +85,7 @@ const authenticate = async (ctx) => {
|
|
|
77
85
|
credentials: null,
|
|
78
86
|
ability,
|
|
79
87
|
};
|
|
80
|
-
} catch
|
|
88
|
+
} catch {
|
|
81
89
|
return { authenticated: false };
|
|
82
90
|
}
|
|
83
91
|
};
|
|
@@ -100,12 +108,8 @@ const verify = async (auth, config) => {
|
|
|
100
108
|
throw new UnauthorizedError();
|
|
101
109
|
}
|
|
102
110
|
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
castArray,
|
|
106
|
-
// Transform the scope array into an action array
|
|
107
|
-
every((scope) => ability.can(scope))
|
|
108
|
-
)(config.scope);
|
|
111
|
+
const scopes = Array.isArray(config.scope) ? config.scope : [config.scope];
|
|
112
|
+
const isAllowed = every(scopes, (scope) => ability.can(scope));
|
|
109
113
|
|
|
110
114
|
if (!isAllowed) {
|
|
111
115
|
throw new ForbiddenError();
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { errors } = require('@strapi/utils');
|
|
4
|
+
|
|
5
|
+
const builtinProviderEndpoints = require('./providers');
|
|
6
|
+
const oauth1 = require('./oauth1');
|
|
7
|
+
const oauth2 = require('./oauth2');
|
|
8
|
+
const { trimGrantSessionResponse } = require('../trim-grant-session-response');
|
|
9
|
+
|
|
10
|
+
const CONNECT_PREFIX = '/connect';
|
|
11
|
+
|
|
12
|
+
const parseConnectPath = (requestPath, apiPrefix) => {
|
|
13
|
+
const prefix = `${apiPrefix}${CONNECT_PREFIX}/`;
|
|
14
|
+
if (!requestPath.startsWith(prefix)) {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const remainder = requestPath.slice(prefix.length);
|
|
19
|
+
const [provider, segment] = remainder.split('/').filter(Boolean);
|
|
20
|
+
|
|
21
|
+
if (!provider) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return {
|
|
26
|
+
provider,
|
|
27
|
+
isCallback: segment === 'callback',
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Resolve OAuth endpoint config from built-ins, falling back to store-defined
|
|
33
|
+
* endpoints so custom providers registered via providers-registry still work.
|
|
34
|
+
*/
|
|
35
|
+
const buildProviderConfig = (providerName, storedConfig, redirectUri) => {
|
|
36
|
+
const defaults = builtinProviderEndpoints[providerName];
|
|
37
|
+
const endpoints = defaults || {
|
|
38
|
+
oauth: storedConfig.oauth,
|
|
39
|
+
authorize_url: storedConfig.authorize_url,
|
|
40
|
+
access_url: storedConfig.access_url,
|
|
41
|
+
request_url: storedConfig.request_url,
|
|
42
|
+
scope_delimiter: storedConfig.scope_delimiter,
|
|
43
|
+
token_endpoint_auth_method: storedConfig.token_endpoint_auth_method,
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
if (endpoints.oauth === 1) {
|
|
47
|
+
if (!endpoints.request_url || !endpoints.authorize_url || !endpoints.access_url) {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
} else if (!endpoints.authorize_url || !endpoints.access_url) {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return {
|
|
55
|
+
name: providerName,
|
|
56
|
+
...endpoints,
|
|
57
|
+
key: storedConfig.key,
|
|
58
|
+
secret: storedConfig.secret,
|
|
59
|
+
scope: storedConfig.scope,
|
|
60
|
+
subdomain: storedConfig.subdomain,
|
|
61
|
+
callback: storedConfig.callback,
|
|
62
|
+
redirect_uri: redirectUri,
|
|
63
|
+
};
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const redirectWithPayload = (ctx, callbackUrl, payload) => {
|
|
67
|
+
const url = new URL(callbackUrl);
|
|
68
|
+
const params = new URLSearchParams();
|
|
69
|
+
|
|
70
|
+
Object.entries(payload).forEach(([key, value]) => {
|
|
71
|
+
if (key === 'raw') {
|
|
72
|
+
Object.entries(value).forEach(([rawKey, rawValue]) => {
|
|
73
|
+
params.set(`raw[${rawKey}]`, String(rawValue));
|
|
74
|
+
});
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
if (value !== undefined && value !== null) {
|
|
78
|
+
params.set(key, String(value));
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
url.search = params.toString();
|
|
83
|
+
ctx.redirect(url.toString());
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
const preserveGrantDynamic = (ctx) => {
|
|
87
|
+
const dynamic = ctx.session.grant?.dynamic;
|
|
88
|
+
return dynamic ? { dynamic } : {};
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const redirectWithSessionResponse = (ctx, callbackUrl, provider, tokenResponse) => {
|
|
92
|
+
const grantResponse = oauth2.tokensToQueryPayload(provider, tokenResponse);
|
|
93
|
+
ctx.session.grant = {
|
|
94
|
+
response: trimGrantSessionResponse(grantResponse, provider.name),
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
return redirectWithPayload(ctx, callbackUrl, {});
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
const startOAuth1Flow = async (ctx, provider, parsed, redirectUri) => {
|
|
101
|
+
const requestToken = await oauth1.requestToken({
|
|
102
|
+
requestUrl: provider.request_url,
|
|
103
|
+
redirectUri,
|
|
104
|
+
consumerKey: provider.key,
|
|
105
|
+
clientCredential: provider.secret,
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
ctx.session.grant = {
|
|
109
|
+
...preserveGrantDynamic(ctx),
|
|
110
|
+
provider: parsed.provider,
|
|
111
|
+
request: requestToken,
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const authorizeUrl = `${provider.authorize_url}?oauth_token=${encodeURIComponent(requestToken.oauth_token)}`;
|
|
115
|
+
return ctx.redirect(authorizeUrl);
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
const startOAuth2Flow = (ctx, provider, parsed, redirectUri) => {
|
|
119
|
+
const state = oauth2.generateState();
|
|
120
|
+
ctx.session.grant = {
|
|
121
|
+
...preserveGrantDynamic(ctx),
|
|
122
|
+
provider: parsed.provider,
|
|
123
|
+
state,
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
let authorizeUrl = oauth2.buildAuthorizeUrl(provider, {
|
|
127
|
+
key: provider.key,
|
|
128
|
+
redirectUri,
|
|
129
|
+
scope: provider.scope,
|
|
130
|
+
subdomain: provider.subdomain,
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
authorizeUrl += `&state=${encodeURIComponent(state)}`;
|
|
134
|
+
return ctx.redirect(authorizeUrl);
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
const handleOAuth1Callback = async (ctx, provider, callbackUrl) => {
|
|
138
|
+
const session = ctx.session.grant || {};
|
|
139
|
+
const { oauth_token: oauthToken, oauth_verifier: oauthVerifier } = ctx.query;
|
|
140
|
+
const requestToken = session.request;
|
|
141
|
+
|
|
142
|
+
if (!requestToken?.oauth_token || oauthToken !== requestToken.oauth_token) {
|
|
143
|
+
throw new Error('OAuth1 token mismatch');
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const tokenResponse = await oauth1.accessToken({
|
|
147
|
+
accessUrl: provider.access_url,
|
|
148
|
+
consumerKey: provider.key,
|
|
149
|
+
clientCredential: provider.secret,
|
|
150
|
+
oauthToken,
|
|
151
|
+
oauthVerifier,
|
|
152
|
+
oauthTokenCredential: requestToken.oauth_token_secret,
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
return redirectWithSessionResponse(ctx, callbackUrl, provider, tokenResponse);
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
const handleOAuth2Callback = async (ctx, provider, callbackUrl, redirectUri) => {
|
|
159
|
+
const session = ctx.session.grant || {};
|
|
160
|
+
const { code, state: queryState, error, error_description: errorDescription } = ctx.query;
|
|
161
|
+
|
|
162
|
+
if (error) {
|
|
163
|
+
ctx.session.grant = {};
|
|
164
|
+
return redirectWithPayload(ctx, callbackUrl, {
|
|
165
|
+
error,
|
|
166
|
+
error_description: errorDescription,
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (!code) {
|
|
171
|
+
throw new Error('OAuth2 missing code parameter');
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Reject when session state is missing (not only on mismatch) to close login-CSRF.
|
|
175
|
+
if (!session.state || queryState !== session.state) {
|
|
176
|
+
throw new Error('OAuth2 state mismatch');
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const tokenResponse = await oauth2.exchangeAuthorizationCode(provider, {
|
|
180
|
+
key: provider.key,
|
|
181
|
+
secret: provider.secret,
|
|
182
|
+
redirectUri,
|
|
183
|
+
code,
|
|
184
|
+
subdomain: provider.subdomain,
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
return redirectWithSessionResponse(ctx, callbackUrl, provider, tokenResponse);
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
const createOAuthConnectMiddleware = () => {
|
|
191
|
+
return async (ctx, next) => {
|
|
192
|
+
const apiPrefix = strapi.config.get('api.rest.prefix');
|
|
193
|
+
const [requestPath] = ctx.request.url.split('?');
|
|
194
|
+
const parsed = parseConnectPath(requestPath, apiPrefix);
|
|
195
|
+
|
|
196
|
+
if (!parsed) {
|
|
197
|
+
return next();
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (!ctx.session) {
|
|
201
|
+
ctx.throw(400, 'OAuth connect requires session middleware');
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const storedProviders = await strapi
|
|
205
|
+
.store({ type: 'plugin', name: 'users-permissions', key: 'grant' })
|
|
206
|
+
.get();
|
|
207
|
+
|
|
208
|
+
const storedConfig = storedProviders?.[parsed.provider];
|
|
209
|
+
if (!storedConfig?.enabled) {
|
|
210
|
+
throw new errors.ApplicationError('This provider is disabled');
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const { getService } = require('..');
|
|
214
|
+
const redirectUri = getService('providers').buildRedirectUri(parsed.provider);
|
|
215
|
+
|
|
216
|
+
const callbackOverride =
|
|
217
|
+
ctx.state.oauthConnect?.callback ?? ctx.session.grant?.dynamic?.callback;
|
|
218
|
+
const effectiveConfig = callbackOverride
|
|
219
|
+
? { ...storedConfig, callback: callbackOverride }
|
|
220
|
+
: storedConfig;
|
|
221
|
+
|
|
222
|
+
const provider = buildProviderConfig(parsed.provider, effectiveConfig, redirectUri);
|
|
223
|
+
|
|
224
|
+
if (!provider) {
|
|
225
|
+
throw new errors.ApplicationError('Unknown OAuth provider');
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
ctx.session.grant = ctx.session.grant || {};
|
|
229
|
+
|
|
230
|
+
if (!parsed.isCallback) {
|
|
231
|
+
if (provider.oauth === 1) {
|
|
232
|
+
return startOAuth1Flow(ctx, provider, parsed, redirectUri);
|
|
233
|
+
}
|
|
234
|
+
return startOAuth2Flow(ctx, provider, parsed, redirectUri);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const callbackUrl = effectiveConfig.callback;
|
|
238
|
+
if (!callbackUrl) {
|
|
239
|
+
throw new errors.ApplicationError('Provider callback URL is not configured');
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
try {
|
|
243
|
+
if (provider.oauth === 1) {
|
|
244
|
+
return await handleOAuth1Callback(ctx, provider, callbackUrl);
|
|
245
|
+
}
|
|
246
|
+
return await handleOAuth2Callback(ctx, provider, callbackUrl, redirectUri);
|
|
247
|
+
} catch (err) {
|
|
248
|
+
ctx.session.grant = {};
|
|
249
|
+
return redirectWithPayload(ctx, callbackUrl, {
|
|
250
|
+
error: 'oauth_error',
|
|
251
|
+
error_description: err.message,
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
module.exports = {
|
|
258
|
+
createOAuthConnectMiddleware,
|
|
259
|
+
parseConnectPath,
|
|
260
|
+
buildProviderConfig,
|
|
261
|
+
redirectWithPayload,
|
|
262
|
+
};
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const crypto = require('node:crypto');
|
|
4
|
+
const { URLSearchParams } = require('node:url');
|
|
5
|
+
|
|
6
|
+
const encode = (str) =>
|
|
7
|
+
encodeURIComponent(str).replace(
|
|
8
|
+
/[!'()*]/g,
|
|
9
|
+
(c) => `%${c.codePointAt(0).toString(16).toUpperCase()}`
|
|
10
|
+
);
|
|
11
|
+
|
|
12
|
+
const sortKeys = (keys) =>
|
|
13
|
+
keys.sort((a, b) => {
|
|
14
|
+
if (a < b) return -1;
|
|
15
|
+
if (a > b) return 1;
|
|
16
|
+
return 0;
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* OAuth 1.0 (RFC 5849) request signature — HMAC-SHA1 is required by the protocol.
|
|
21
|
+
* This is not password storage or user-credential hashing (those use bcrypt).
|
|
22
|
+
*/
|
|
23
|
+
const signRfc5849BaseString = (signatureBaseString, signingMaterial) => {
|
|
24
|
+
// codeql[js/insufficient-password-hash] OAuth 1.0 signing material, not user password storage
|
|
25
|
+
return crypto.createHmac('sha1', signingMaterial).update(signatureBaseString).digest('base64');
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const buildOAuth1Header = ({
|
|
29
|
+
method,
|
|
30
|
+
url,
|
|
31
|
+
params,
|
|
32
|
+
consumerKey,
|
|
33
|
+
clientCredential,
|
|
34
|
+
token,
|
|
35
|
+
tokenCredential,
|
|
36
|
+
}) => {
|
|
37
|
+
const requestParameters = {
|
|
38
|
+
oauth_consumer_key: consumerKey,
|
|
39
|
+
oauth_nonce: crypto.randomBytes(16).toString('hex'),
|
|
40
|
+
oauth_signature_method: 'HMAC-SHA1',
|
|
41
|
+
oauth_timestamp: Math.floor(Date.now() / 1000).toString(),
|
|
42
|
+
oauth_version: '1.0',
|
|
43
|
+
...(token ? { oauth_token: token } : {}),
|
|
44
|
+
...params,
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const paramString = sortKeys(Object.keys(requestParameters))
|
|
48
|
+
.map((key) => `${encode(key)}=${encode(requestParameters[key])}`)
|
|
49
|
+
.join('&');
|
|
50
|
+
|
|
51
|
+
const signatureBaseString = [method.toUpperCase(), encode(url), encode(paramString)].join('&');
|
|
52
|
+
const signingMaterial = `${encode(clientCredential)}&${encode(tokenCredential || '')}`;
|
|
53
|
+
const signature = signRfc5849BaseString(signatureBaseString, signingMaterial);
|
|
54
|
+
|
|
55
|
+
const headerParameters = { ...requestParameters, oauth_signature: signature };
|
|
56
|
+
const header = `OAuth ${sortKeys(Object.keys(headerParameters))
|
|
57
|
+
.map((key) => `${encode(key)}="${encode(headerParameters[key])}"`)
|
|
58
|
+
.join(', ')}`;
|
|
59
|
+
|
|
60
|
+
return header;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const oauth1Request = async ({
|
|
64
|
+
method,
|
|
65
|
+
url,
|
|
66
|
+
consumerKey,
|
|
67
|
+
clientCredential,
|
|
68
|
+
token,
|
|
69
|
+
tokenCredential,
|
|
70
|
+
params = {},
|
|
71
|
+
}) => {
|
|
72
|
+
const authorization = buildOAuth1Header({
|
|
73
|
+
method,
|
|
74
|
+
url,
|
|
75
|
+
params,
|
|
76
|
+
consumerKey,
|
|
77
|
+
clientCredential,
|
|
78
|
+
token,
|
|
79
|
+
tokenCredential,
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
const response = await fetch(url, {
|
|
83
|
+
method,
|
|
84
|
+
headers: { Authorization: authorization },
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
const text = await response.text();
|
|
88
|
+
if (!response.ok) {
|
|
89
|
+
throw new Error(text || `OAuth1 request failed (${response.status})`);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return Object.fromEntries(new URLSearchParams(text));
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const requestToken = async ({ requestUrl, redirectUri, consumerKey, clientCredential }) =>
|
|
96
|
+
oauth1Request({
|
|
97
|
+
method: 'POST',
|
|
98
|
+
url: requestUrl,
|
|
99
|
+
consumerKey,
|
|
100
|
+
clientCredential,
|
|
101
|
+
params: { oauth_callback: redirectUri },
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
const accessToken = async ({
|
|
105
|
+
accessUrl,
|
|
106
|
+
consumerKey,
|
|
107
|
+
clientCredential,
|
|
108
|
+
oauthToken,
|
|
109
|
+
oauthVerifier,
|
|
110
|
+
oauthTokenCredential,
|
|
111
|
+
}) =>
|
|
112
|
+
oauth1Request({
|
|
113
|
+
method: 'POST',
|
|
114
|
+
url: accessUrl,
|
|
115
|
+
consumerKey,
|
|
116
|
+
clientCredential,
|
|
117
|
+
token: oauthToken,
|
|
118
|
+
tokenCredential: oauthTokenCredential,
|
|
119
|
+
params: { oauth_verifier: oauthVerifier },
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
const twitterGet = async ({
|
|
123
|
+
url,
|
|
124
|
+
accessToken,
|
|
125
|
+
accessCredential,
|
|
126
|
+
consumerKey,
|
|
127
|
+
clientCredential,
|
|
128
|
+
qs = {},
|
|
129
|
+
}) => {
|
|
130
|
+
const target = new URL(url);
|
|
131
|
+
const signedParams = {};
|
|
132
|
+
|
|
133
|
+
Object.entries(qs).forEach(([key, value]) => {
|
|
134
|
+
if (value !== undefined && value !== null) {
|
|
135
|
+
const stringValue = String(value);
|
|
136
|
+
target.searchParams.set(key, stringValue);
|
|
137
|
+
// RFC 5849 §3.4.1: base-string URI excludes the query; params are signed separately.
|
|
138
|
+
signedParams[key] = stringValue;
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
const authorization = buildOAuth1Header({
|
|
143
|
+
method: 'GET',
|
|
144
|
+
url: target.origin + target.pathname,
|
|
145
|
+
params: signedParams,
|
|
146
|
+
consumerKey,
|
|
147
|
+
clientCredential,
|
|
148
|
+
token: accessToken,
|
|
149
|
+
tokenCredential: accessCredential,
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
const response = await fetch(target, {
|
|
153
|
+
headers: { Authorization: authorization },
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
const body = await response.json();
|
|
157
|
+
if (!response.ok) {
|
|
158
|
+
throw new Error(body.errors?.[0]?.message || `Twitter API error (${response.status})`);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return { body };
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
module.exports = {
|
|
165
|
+
buildOAuth1Header,
|
|
166
|
+
requestToken,
|
|
167
|
+
accessToken,
|
|
168
|
+
twitterGet,
|
|
169
|
+
};
|