@openstax/ts-utils 1.33.1 → 1.34.0
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/.cfnlintrc +2 -0
- package/.github/CODEOWNERS +1 -0
- package/.github/workflows/ci.yml +36 -0
- package/.github/workflows/lint.yml +55 -0
- package/.nvmrc +1 -0
- package/.syncignore +4 -0
- package/.syncpackrc +18 -0
- package/CONTRIBUTING.md +96 -0
- package/LICENSE +661 -0
- package/Procfile +1 -0
- package/README.md +62 -90
- package/app.json +23 -0
- package/cspell.json +32 -0
- package/deploy/constants.env +21 -0
- package/deploy/deploy.bash +157 -0
- package/deploy/deployment-alt-region.cfn.yml +70 -0
- package/deploy/deployment.cfn.yml +650 -0
- package/deploy/destroy-deployment.bash +23 -0
- package/deploy/shared.cfn.yml +94 -0
- package/docs/lambda-build.md +35 -0
- package/package.json +12 -228
- package/packages/frontend/README.md +46 -0
- package/packages/frontend/package.json +101 -0
- package/packages/frontend/public/favicon.ico +0 -0
- package/packages/frontend/public/index.html +107 -0
- package/packages/frontend/public/maintenance.html +59 -0
- package/packages/frontend/public/manifest.json +15 -0
- package/packages/frontend/public/robots.txt +3 -0
- package/packages/frontend/script/make-certificate.bash +49 -0
- package/packages/frontend/script/server/cli.js +11 -0
- package/packages/frontend/script/server/index.js +47 -0
- package/packages/frontend/script/start.bash +22 -0
- package/packages/frontend/script/trust-localhost.bash +7 -0
- package/packages/frontend/src/auth/authProvider.ts +10 -0
- package/packages/frontend/src/auth/useAuth.ts +33 -0
- package/packages/frontend/src/components/Pagination.tsx +26 -0
- package/packages/frontend/src/configProvider/index.ts +53 -0
- package/packages/frontend/src/configProvider/use.ts +41 -0
- package/packages/frontend/src/core/context/services.spec.tsx +39 -0
- package/packages/frontend/src/core/context/services.tsx +16 -0
- package/packages/frontend/src/core/index.spec.ts +7 -0
- package/packages/frontend/src/core/index.ts +20 -0
- package/packages/frontend/src/core/services.tsx +14 -0
- package/packages/frontend/src/core/types.ts +3 -0
- package/packages/frontend/src/example/api.ts +28 -0
- package/packages/frontend/src/example/components/Layout.tsx +23 -0
- package/packages/frontend/src/example/screens/Home.spec.tsx +68 -0
- package/packages/frontend/src/example/screens/Home.tsx +78 -0
- package/packages/frontend/src/example/screens/ThingList.spec.tsx +60 -0
- package/packages/frontend/src/example/screens/ThingList.tsx +75 -0
- package/packages/frontend/src/example/screens/ThingView.spec.tsx +71 -0
- package/packages/frontend/src/example/screens/ThingView.tsx +47 -0
- package/packages/frontend/src/example/screens/index.ts +9 -0
- package/packages/frontend/src/index.css +159 -0
- package/packages/frontend/src/index.tsx +67 -0
- package/packages/frontend/src/react-app-env.d.ts +1 -0
- package/packages/frontend/src/routing/components/RouteLink.spec.tsx +55 -0
- package/packages/frontend/src/routing/components/RouteLink.tsx +35 -0
- package/packages/frontend/src/routing/middleware.ts +6 -0
- package/packages/frontend/src/routing/useQuery.ts +14 -0
- package/packages/frontend/src/setupProxy.js +19 -0
- package/packages/frontend/src/setupTests.ts +9 -0
- package/packages/frontend/src/tests/testServices.tsx +23 -0
- package/packages/frontend/tsconfig.json +27 -0
- package/packages/lambda/.eslintrc.js +64 -0
- package/packages/lambda/jest-global-setup.js +3 -0
- package/packages/lambda/jest-setup-after-env.js +1 -0
- package/packages/lambda/jest.config.js +31 -0
- package/packages/lambda/jest.resolver.js +17 -0
- package/packages/lambda/package.json +68 -0
- package/packages/lambda/script/build.bash +19 -0
- package/packages/lambda/script/bundle-functions.bash +10 -0
- package/packages/lambda/script/lambdaLocalProxy.js +16 -0
- package/packages/lambda/script/lambdaLocalProxy.spec.ts +147 -0
- package/packages/lambda/script/utils/getRouteData.ts +7 -0
- package/packages/lambda/script/utils/routeDataLoader.js +8 -0
- package/packages/lambda/script/utils/routeDataLoader.spec.ts +8 -0
- package/packages/lambda/src/functions/serviceApi/core/index.ts +7 -0
- package/packages/lambda/src/functions/serviceApi/core/request.spec.ts +38 -0
- package/packages/lambda/src/functions/serviceApi/core/request.ts +42 -0
- package/packages/lambda/src/functions/serviceApi/core/routes.spec.ts +7 -0
- package/packages/lambda/src/functions/serviceApi/core/routes.ts +10 -0
- package/packages/lambda/src/functions/serviceApi/core/services.ts +9 -0
- package/packages/lambda/src/functions/serviceApi/core/types.ts +13 -0
- package/packages/lambda/src/functions/serviceApi/entry/lambda/https-xray.ts +4 -0
- package/packages/lambda/src/functions/serviceApi/entry/lambda/index.spec.ts +48 -0
- package/packages/lambda/src/functions/serviceApi/entry/lambda/index.ts +58 -0
- package/packages/lambda/src/functions/serviceApi/entry/lambda/services.ts +36 -0
- package/packages/lambda/src/functions/serviceApi/entry/local.ts +71 -0
- package/packages/lambda/src/functions/serviceApi/versions/v0/example/documentSearchMiddleware.spec.ts +16 -0
- package/packages/lambda/src/functions/serviceApi/versions/v0/example/documentSearchMiddleware.ts +41 -0
- package/packages/lambda/src/functions/serviceApi/versions/v0/example/documentStoreMiddleware.spec.ts +78 -0
- package/packages/lambda/src/functions/serviceApi/versions/v0/example/documentStoreMiddleware.ts +70 -0
- package/packages/lambda/src/functions/serviceApi/versions/v0/example/routes.spec.ts +306 -0
- package/packages/lambda/src/functions/serviceApi/versions/v0/example/routes.ts +176 -0
- package/packages/lambda/src/functions/serviceApi/versions/v0/index.spec.ts +263 -0
- package/packages/lambda/src/functions/serviceApi/versions/v0/index.ts +134 -0
- package/packages/lambda/src/functions/serviceApi/versions/v0/middleware/authMiddleware.spec.ts +23 -0
- package/packages/lambda/src/functions/serviceApi/versions/v0/middleware/authMiddleware.ts +32 -0
- package/packages/lambda/src/functions/serviceApi/versions/v0/middleware/configMiddleware.spec.ts +10 -0
- package/packages/lambda/src/functions/serviceApi/versions/v0/middleware/configMiddleware.ts +7 -0
- package/packages/lambda/src/functions/serviceApi/versions/v0/middleware/frontendFileServerMiddleware.spec.ts +13 -0
- package/packages/lambda/src/functions/serviceApi/versions/v0/middleware/frontendFileServerMiddleware.ts +23 -0
- package/packages/lambda/src/functions/serviceApi/versions/v0/middleware/paginationMiddleware.spec.ts +9 -0
- package/packages/lambda/src/functions/serviceApi/versions/v0/middleware/paginationMiddleware.ts +9 -0
- package/packages/lambda/src/functions/serviceApi/versions/v0/middleware/searchMiddleware.spec.ts +12 -0
- package/packages/lambda/src/functions/serviceApi/versions/v0/middleware/searchMiddleware.ts +21 -0
- package/packages/lambda/src/functions/serviceApi/versions/v0/middleware/userRoleValidatorMiddleware.spec.ts +21 -0
- package/packages/lambda/src/functions/serviceApi/versions/v0/middleware/userRoleValidatorMiddleware.ts +18 -0
- package/packages/lambda/tsconfig.json +30 -0
- package/packages/lambda/webpack.config.js +97 -0
- package/packages/utils/.eslintrc.js +64 -0
- package/packages/utils/README.md +118 -0
- package/packages/utils/jest-global-setup.js +3 -0
- package/packages/utils/jest.config.js +25 -0
- package/packages/utils/jest.resolver.js +17 -0
- package/packages/utils/package.json +238 -0
- package/packages/utils/src/assertions/index.spec.ts +126 -0
- package/{dist/esm/assertions/index.js → packages/utils/src/assertions/index.ts} +64 -49
- package/packages/utils/src/aws/ssmService.ts +7 -0
- package/packages/utils/src/config/awsParameterConfig.ts +24 -0
- package/packages/utils/src/config/envConfig.ts +58 -0
- package/packages/utils/src/config/index.spec.ts +165 -0
- package/{dist/esm/config/index.d.ts → packages/utils/src/config/index.ts} +29 -13
- package/packages/utils/src/config/lambdaParameterConfig.ts +49 -0
- package/{dist/esm/config/replaceConfig.js → packages/utils/src/config/replaceConfig.ts} +16 -6
- package/packages/utils/src/config/resolveConfigValue.ts +10 -0
- package/packages/utils/src/errors/index.spec.ts +35 -0
- package/{dist/esm/errors/index.js → packages/utils/src/errors/index.ts} +57 -41
- package/packages/utils/src/fetch/fetchStatusRetry.spec.ts +197 -0
- package/packages/utils/src/fetch/fetchStatusRetry.ts +33 -0
- package/packages/utils/src/fetch/index.spec.ts +34 -0
- package/packages/utils/src/fetch/index.ts +87 -0
- package/packages/utils/src/guards/index.spec.ts +58 -0
- package/{dist/esm/guards/index.d.ts → packages/utils/src/guards/index.ts} +10 -7
- package/packages/utils/src/index.spec.ts +471 -0
- package/packages/utils/src/middleware/apiErrorHandler.spec.ts +65 -0
- package/packages/utils/src/middleware/apiErrorHandler.ts +67 -0
- package/packages/utils/src/middleware/apiSlowResponseMiddleware.spec.ts +184 -0
- package/packages/utils/src/middleware/apiSlowResponseMiddleware.ts +71 -0
- package/packages/utils/src/middleware/index.spec.ts +99 -0
- package/{dist/cjs/middleware/index.d.ts → packages/utils/src/middleware/index.ts} +53 -5
- package/packages/utils/src/middleware/lambdaCorsResponseMiddleware.spec.ts +103 -0
- package/packages/utils/src/middleware/lambdaCorsResponseMiddleware.ts +52 -0
- package/packages/utils/src/middleware/throwNotFoundMiddleware.spec.ts +20 -0
- package/packages/utils/src/middleware/throwNotFoundMiddleware.ts +11 -0
- package/packages/utils/src/misc/hashValue.ts +18 -0
- package/packages/utils/src/misc/helpers.ts +259 -0
- package/packages/utils/src/misc/merge.ts +48 -0
- package/{dist/esm/misc/partitionSequence.js → packages/utils/src/misc/partitionSequence.ts} +23 -15
- package/packages/utils/src/pagination/index.spec.ts +150 -0
- package/packages/utils/src/pagination/index.ts +117 -0
- package/{dist/esm/routing/helpers.js → packages/utils/src/routing/helpers.ts} +42 -30
- package/packages/utils/src/routing/index.spec.ts +553 -0
- package/packages/utils/src/routing/index.ts +424 -0
- package/packages/utils/src/routing/validators/zod.spec.ts +16 -0
- package/packages/utils/src/routing/validators/zod.ts +14 -0
- package/packages/utils/src/services/accountsGateway/README.md +3 -0
- package/packages/utils/src/services/accountsGateway/index.spec.ts +518 -0
- package/packages/utils/src/services/accountsGateway/index.ts +251 -0
- package/packages/utils/src/services/apiGateway/README.md +93 -0
- package/packages/utils/src/services/apiGateway/index.spec.ts +254 -0
- package/packages/utils/src/services/apiGateway/index.ts +189 -0
- package/packages/utils/src/services/authProvider/README.md +21 -0
- package/packages/utils/src/services/authProvider/browser.spec.ts +391 -0
- package/packages/utils/src/services/authProvider/browser.ts +209 -0
- package/packages/utils/src/services/authProvider/decryption.spec.ts +337 -0
- package/packages/utils/src/services/authProvider/decryption.ts +98 -0
- package/packages/utils/src/services/authProvider/index.ts +93 -0
- package/packages/utils/src/services/authProvider/stub.spec.ts +29 -0
- package/packages/utils/src/services/authProvider/subrequest.spec.ts +105 -0
- package/packages/utils/src/services/authProvider/subrequest.ts +68 -0
- package/packages/utils/src/services/authProvider/utils/decryptAndVerify.spec.ts +128 -0
- package/packages/utils/src/services/authProvider/utils/decryptAndVerify.ts +106 -0
- package/packages/utils/src/services/authProvider/utils/embeddedAuthProvider.spec.ts +26 -0
- package/packages/utils/src/services/authProvider/utils/embeddedAuthProvider.ts +57 -0
- package/packages/utils/src/services/authProvider/utils/userRoleValidator.spec.ts +135 -0
- package/packages/utils/src/services/authProvider/utils/userRoleValidator.ts +49 -0
- package/packages/utils/src/services/authProvider/utils/userSubrequest.spec.ts +26 -0
- package/packages/utils/src/services/authProvider/utils/userSubrequest.ts +10 -0
- package/packages/utils/src/services/documentStore/dynamoEncoding.ts +57 -0
- package/packages/utils/src/services/documentStore/fileSystemAssert.spec.ts +43 -0
- package/packages/utils/src/services/documentStore/fileSystemAssert.ts +10 -0
- package/{dist/cjs/services/documentStore/index.d.ts → packages/utils/src/services/documentStore/index.ts} +8 -8
- package/packages/utils/src/services/documentStore/unversioned/README.md +13 -0
- package/packages/utils/src/services/documentStore/unversioned/dynamodb.spec.ts +859 -0
- package/packages/utils/src/services/documentStore/unversioned/dynamodb.ts +243 -0
- package/packages/utils/src/services/documentStore/unversioned/file-system.spec.ts +629 -0
- package/packages/utils/src/services/documentStore/unversioned/file-system.ts +194 -0
- package/{dist/cjs/services/documentStore/unversioned/index.d.ts → packages/utils/src/services/documentStore/unversioned/index.ts} +2 -0
- package/packages/utils/src/services/documentStore/versioned/README.md +13 -0
- package/packages/utils/src/services/documentStore/versioned/dynamodb.spec.ts +376 -0
- package/packages/utils/src/services/documentStore/versioned/dynamodb.ts +167 -0
- package/packages/utils/src/services/documentStore/versioned/file-system.spec.ts +262 -0
- package/packages/utils/src/services/documentStore/versioned/file-system.ts +90 -0
- package/packages/utils/src/services/documentStore/versioned/index.ts +25 -0
- package/packages/utils/src/services/exercisesGateway/README.md +5 -0
- package/packages/utils/src/services/exercisesGateway/index.spec.ts +326 -0
- package/packages/utils/src/services/exercisesGateway/index.ts +163 -0
- package/packages/utils/src/services/fileServer/index.spec.ts +88 -0
- package/packages/utils/src/services/fileServer/index.ts +43 -0
- package/packages/utils/src/services/fileServer/localFileServer.spec.ts +182 -0
- package/packages/utils/src/services/fileServer/localFileServer.ts +159 -0
- package/packages/utils/src/services/fileServer/s3FileServer.spec.ts +266 -0
- package/packages/utils/src/services/fileServer/s3FileServer.ts +155 -0
- package/packages/utils/src/services/launchParams/index.spec.ts +366 -0
- package/packages/utils/src/services/launchParams/signer.ts +73 -0
- package/packages/utils/src/services/launchParams/verifier.ts +120 -0
- package/packages/utils/src/services/logger/console.spec.ts +29 -0
- package/{dist/esm/services/logger/console.js → packages/utils/src/services/logger/console.ts} +5 -2
- package/packages/utils/src/services/logger/index.spec.ts +65 -0
- package/{dist/esm/services/logger/index.d.ts → packages/utils/src/services/logger/index.ts} +23 -9
- package/packages/utils/src/services/lrsGateway/README.md +5 -0
- package/packages/utils/src/services/lrsGateway/addStatementDefaultFields.ts +22 -0
- package/packages/utils/src/services/lrsGateway/attempt-utils.spec.ts +847 -0
- package/packages/utils/src/services/lrsGateway/attempt-utils.ts +358 -0
- package/packages/utils/src/services/lrsGateway/file-system.spec.ts +363 -0
- package/packages/utils/src/services/lrsGateway/file-system.ts +165 -0
- package/packages/utils/src/services/lrsGateway/index.spec.ts +194 -0
- package/packages/utils/src/services/lrsGateway/index.ts +257 -0
- package/packages/utils/src/services/lrsGateway/xapiUtils.spec.ts +887 -0
- package/packages/utils/src/services/lrsGateway/xapiUtils.ts +262 -0
- package/packages/utils/src/services/postgresConnection/index.spec.ts +170 -0
- package/packages/utils/src/services/postgresConnection/index.ts +84 -0
- package/packages/utils/src/services/searchProvider/README.md +3 -0
- package/packages/utils/src/services/searchProvider/index.ts +59 -0
- package/packages/utils/src/services/searchProvider/memorySearchTheBadWay.spec.ts +526 -0
- package/packages/utils/src/services/searchProvider/memorySearchTheBadWay.ts +223 -0
- package/packages/utils/src/services/searchProvider/openSearch.spec.ts +926 -0
- package/packages/utils/src/services/searchProvider/openSearch.ts +195 -0
- package/{dist/esm/types.d.ts → packages/utils/src/types.ts} +34 -6
- package/packages/utils/tsconfig.json +31 -0
- package/packages/utils/tsconfig.without-specs.cjs.json +7 -0
- package/packages/utils/tsconfig.without-specs.esm.json +7 -0
- package/packages/utils/tsconfig.without-specs.json +6 -0
- package/scripts/build.bash +24 -0
- package/scripts/ci.bash +10 -0
- package/scripts/start.bash +29 -0
- package/dist/cjs/assertions/index.d.ts +0 -89
- package/dist/cjs/assertions/index.js +0 -157
- package/dist/cjs/aws/ssmService.d.ts +0 -5
- package/dist/cjs/aws/ssmService.js +0 -9
- package/dist/cjs/config/awsParameterConfig.d.ts +0 -10
- package/dist/cjs/config/awsParameterConfig.js +0 -26
- package/dist/cjs/config/envConfig.d.ts +0 -24
- package/dist/cjs/config/envConfig.js +0 -57
- package/dist/cjs/config/index.d.ts +0 -48
- package/dist/cjs/config/index.js +0 -35
- package/dist/cjs/config/lambdaParameterConfig.d.ts +0 -12
- package/dist/cjs/config/lambdaParameterConfig.js +0 -45
- package/dist/cjs/config/replaceConfig.d.ts +0 -14
- package/dist/cjs/config/replaceConfig.js +0 -22
- package/dist/cjs/config/resolveConfigValue.d.ts +0 -5
- package/dist/cjs/config/resolveConfigValue.js +0 -12
- package/dist/cjs/errors/index.d.ts +0 -88
- package/dist/cjs/errors/index.js +0 -123
- package/dist/cjs/fetch/fetchStatusRetry.d.ts +0 -8
- package/dist/cjs/fetch/fetchStatusRetry.js +0 -27
- package/dist/cjs/fetch/index.d.ts +0 -64
- package/dist/cjs/fetch/index.js +0 -55
- package/dist/cjs/guards/index.d.ts +0 -38
- package/dist/cjs/guards/index.js +0 -44
- package/dist/cjs/index.js +0 -20
- package/dist/cjs/middleware/apiErrorHandler.d.ts +0 -24
- package/dist/cjs/middleware/apiErrorHandler.js +0 -42
- package/dist/cjs/middleware/apiSlowResponseMiddleware.d.ts +0 -23
- package/dist/cjs/middleware/apiSlowResponseMiddleware.js +0 -54
- package/dist/cjs/middleware/index.js +0 -48
- package/dist/cjs/middleware/lambdaCorsResponseMiddleware.d.ts +0 -20
- package/dist/cjs/middleware/lambdaCorsResponseMiddleware.js +0 -44
- package/dist/cjs/middleware/throwNotFoundMiddleware.d.ts +0 -4
- package/dist/cjs/middleware/throwNotFoundMiddleware.js +0 -14
- package/dist/cjs/misc/hashValue.d.ts +0 -10
- package/dist/cjs/misc/hashValue.js +0 -17
- package/dist/cjs/misc/helpers.d.ts +0 -124
- package/dist/cjs/misc/helpers.js +0 -214
- package/dist/cjs/misc/merge.d.ts +0 -21
- package/dist/cjs/misc/merge.js +0 -45
- package/dist/cjs/misc/partitionSequence.d.ts +0 -35
- package/dist/cjs/misc/partitionSequence.js +0 -55
- package/dist/cjs/pagination/index.d.ts +0 -91
- package/dist/cjs/pagination/index.js +0 -83
- package/dist/cjs/routing/helpers.d.ts +0 -57
- package/dist/cjs/routing/helpers.js +0 -90
- package/dist/cjs/routing/index.d.ts +0 -290
- package/dist/cjs/routing/index.js +0 -295
- package/dist/cjs/routing/validators/zod.d.ts +0 -4
- package/dist/cjs/routing/validators/zod.js +0 -14
- package/dist/cjs/services/accountsGateway/index.d.ts +0 -92
- package/dist/cjs/services/accountsGateway/index.js +0 -138
- package/dist/cjs/services/apiGateway/index.d.ts +0 -68
- package/dist/cjs/services/apiGateway/index.js +0 -118
- package/dist/cjs/services/authProvider/browser.d.ts +0 -40
- package/dist/cjs/services/authProvider/browser.js +0 -155
- package/dist/cjs/services/authProvider/decryption.d.ts +0 -19
- package/dist/cjs/services/authProvider/decryption.js +0 -73
- package/dist/cjs/services/authProvider/index.d.ts +0 -63
- package/dist/cjs/services/authProvider/index.js +0 -34
- package/dist/cjs/services/authProvider/subrequest.d.ts +0 -13
- package/dist/cjs/services/authProvider/subrequest.js +0 -49
- package/dist/cjs/services/authProvider/utils/decryptAndVerify.d.ts +0 -28
- package/dist/cjs/services/authProvider/utils/decryptAndVerify.js +0 -91
- package/dist/cjs/services/authProvider/utils/embeddedAuthProvider.d.ts +0 -26
- package/dist/cjs/services/authProvider/utils/embeddedAuthProvider.js +0 -47
- package/dist/cjs/services/authProvider/utils/userRoleValidator.d.ts +0 -13
- package/dist/cjs/services/authProvider/utils/userRoleValidator.js +0 -37
- package/dist/cjs/services/authProvider/utils/userSubrequest.d.ts +0 -3
- package/dist/cjs/services/authProvider/utils/userSubrequest.js +0 -13
- package/dist/cjs/services/documentStore/dynamoEncoding.d.ts +0 -10
- package/dist/cjs/services/documentStore/dynamoEncoding.js +0 -52
- package/dist/cjs/services/documentStore/fileSystemAssert.d.ts +0 -1
- package/dist/cjs/services/documentStore/fileSystemAssert.js +0 -14
- package/dist/cjs/services/documentStore/index.js +0 -2
- package/dist/cjs/services/documentStore/unversioned/dynamodb.d.ts +0 -31
- package/dist/cjs/services/documentStore/unversioned/dynamodb.js +0 -233
- package/dist/cjs/services/documentStore/unversioned/file-system.d.ts +0 -32
- package/dist/cjs/services/documentStore/unversioned/file-system.js +0 -214
- package/dist/cjs/services/documentStore/unversioned/index.js +0 -2
- package/dist/cjs/services/documentStore/versioned/dynamodb.d.ts +0 -25
- package/dist/cjs/services/documentStore/versioned/dynamodb.js +0 -143
- package/dist/cjs/services/documentStore/versioned/file-system.d.ts +0 -25
- package/dist/cjs/services/documentStore/versioned/file-system.js +0 -73
- package/dist/cjs/services/documentStore/versioned/index.d.ts +0 -17
- package/dist/cjs/services/documentStore/versioned/index.js +0 -2
- package/dist/cjs/services/exercisesGateway/index.d.ts +0 -67
- package/dist/cjs/services/exercisesGateway/index.js +0 -107
- package/dist/cjs/services/fileServer/index.d.ts +0 -30
- package/dist/cjs/services/fileServer/index.js +0 -19
- package/dist/cjs/services/fileServer/localFileServer.d.ts +0 -13
- package/dist/cjs/services/fileServer/localFileServer.js +0 -132
- package/dist/cjs/services/fileServer/s3FileServer.d.ts +0 -14
- package/dist/cjs/services/fileServer/s3FileServer.js +0 -132
- package/dist/cjs/services/launchParams/index.js +0 -7
- package/dist/cjs/services/launchParams/signer.d.ts +0 -23
- package/dist/cjs/services/launchParams/signer.js +0 -58
- package/dist/cjs/services/launchParams/verifier.d.ts +0 -21
- package/dist/cjs/services/launchParams/verifier.js +0 -129
- package/dist/cjs/services/logger/console.d.ts +0 -4
- package/dist/cjs/services/logger/console.js +0 -12
- package/dist/cjs/services/logger/index.d.ts +0 -39
- package/dist/cjs/services/logger/index.js +0 -31
- package/dist/cjs/services/lrsGateway/addStatementDefaultFields.d.ts +0 -5
- package/dist/cjs/services/lrsGateway/addStatementDefaultFields.js +0 -21
- package/dist/cjs/services/lrsGateway/attempt-utils.d.ts +0 -70
- package/dist/cjs/services/lrsGateway/attempt-utils.js +0 -258
- package/dist/cjs/services/lrsGateway/file-system.d.ts +0 -15
- package/dist/cjs/services/lrsGateway/file-system.js +0 -150
- package/dist/cjs/services/lrsGateway/index.d.ts +0 -122
- package/dist/cjs/services/lrsGateway/index.js +0 -148
- package/dist/cjs/services/lrsGateway/xapiUtils.d.ts +0 -68
- package/dist/cjs/services/lrsGateway/xapiUtils.js +0 -109
- package/dist/cjs/services/postgresConnection/index.d.ts +0 -28
- package/dist/cjs/services/postgresConnection/index.js +0 -65
- package/dist/cjs/services/searchProvider/index.d.ts +0 -67
- package/dist/cjs/services/searchProvider/index.js +0 -2
- package/dist/cjs/services/searchProvider/memorySearchTheBadWay.d.ts +0 -20
- package/dist/cjs/services/searchProvider/memorySearchTheBadWay.js +0 -191
- package/dist/cjs/services/searchProvider/openSearch.d.ts +0 -28
- package/dist/cjs/services/searchProvider/openSearch.js +0 -154
- package/dist/cjs/tsconfig.without-specs.cjs.tsbuildinfo +0 -1
- package/dist/cjs/types.d.ts +0 -31
- package/dist/cjs/types.js +0 -2
- package/dist/esm/assertions/index.d.ts +0 -89
- package/dist/esm/aws/ssmService.d.ts +0 -5
- package/dist/esm/aws/ssmService.js +0 -6
- package/dist/esm/config/awsParameterConfig.d.ts +0 -10
- package/dist/esm/config/awsParameterConfig.js +0 -22
- package/dist/esm/config/envConfig.d.ts +0 -24
- package/dist/esm/config/envConfig.js +0 -53
- package/dist/esm/config/index.js +0 -17
- package/dist/esm/config/lambdaParameterConfig.d.ts +0 -12
- package/dist/esm/config/lambdaParameterConfig.js +0 -38
- package/dist/esm/config/replaceConfig.d.ts +0 -14
- package/dist/esm/config/resolveConfigValue.d.ts +0 -5
- package/dist/esm/config/resolveConfigValue.js +0 -8
- package/dist/esm/errors/index.d.ts +0 -88
- package/dist/esm/fetch/fetchStatusRetry.d.ts +0 -8
- package/dist/esm/fetch/fetchStatusRetry.js +0 -23
- package/dist/esm/fetch/index.d.ts +0 -64
- package/dist/esm/fetch/index.js +0 -46
- package/dist/esm/guards/index.js +0 -36
- package/dist/esm/index.d.ts +0 -4
- package/dist/esm/index.js +0 -4
- package/dist/esm/middleware/apiErrorHandler.d.ts +0 -24
- package/dist/esm/middleware/apiErrorHandler.js +0 -38
- package/dist/esm/middleware/apiSlowResponseMiddleware.d.ts +0 -23
- package/dist/esm/middleware/apiSlowResponseMiddleware.js +0 -50
- package/dist/esm/middleware/index.d.ts +0 -47
- package/dist/esm/middleware/index.js +0 -44
- package/dist/esm/middleware/lambdaCorsResponseMiddleware.d.ts +0 -20
- package/dist/esm/middleware/lambdaCorsResponseMiddleware.js +0 -40
- package/dist/esm/middleware/throwNotFoundMiddleware.d.ts +0 -4
- package/dist/esm/middleware/throwNotFoundMiddleware.js +0 -10
- package/dist/esm/misc/hashValue.d.ts +0 -10
- package/dist/esm/misc/hashValue.js +0 -13
- package/dist/esm/misc/helpers.d.ts +0 -124
- package/dist/esm/misc/helpers.js +0 -199
- package/dist/esm/misc/merge.d.ts +0 -21
- package/dist/esm/misc/merge.js +0 -40
- package/dist/esm/misc/partitionSequence.d.ts +0 -35
- package/dist/esm/pagination/index.d.ts +0 -91
- package/dist/esm/pagination/index.js +0 -77
- package/dist/esm/routing/helpers.d.ts +0 -57
- package/dist/esm/routing/index.d.ts +0 -290
- package/dist/esm/routing/index.js +0 -246
- package/dist/esm/routing/validators/zod.d.ts +0 -4
- package/dist/esm/routing/validators/zod.js +0 -10
- package/dist/esm/services/accountsGateway/index.d.ts +0 -92
- package/dist/esm/services/accountsGateway/index.js +0 -131
- package/dist/esm/services/apiGateway/index.d.ts +0 -68
- package/dist/esm/services/apiGateway/index.js +0 -77
- package/dist/esm/services/authProvider/browser.d.ts +0 -40
- package/dist/esm/services/authProvider/browser.js +0 -151
- package/dist/esm/services/authProvider/decryption.d.ts +0 -19
- package/dist/esm/services/authProvider/decryption.js +0 -69
- package/dist/esm/services/authProvider/index.d.ts +0 -63
- package/dist/esm/services/authProvider/index.js +0 -26
- package/dist/esm/services/authProvider/subrequest.d.ts +0 -13
- package/dist/esm/services/authProvider/subrequest.js +0 -45
- package/dist/esm/services/authProvider/utils/decryptAndVerify.d.ts +0 -28
- package/dist/esm/services/authProvider/utils/decryptAndVerify.js +0 -85
- package/dist/esm/services/authProvider/utils/embeddedAuthProvider.d.ts +0 -26
- package/dist/esm/services/authProvider/utils/embeddedAuthProvider.js +0 -40
- package/dist/esm/services/authProvider/utils/userRoleValidator.d.ts +0 -13
- package/dist/esm/services/authProvider/utils/userRoleValidator.js +0 -33
- package/dist/esm/services/authProvider/utils/userSubrequest.d.ts +0 -3
- package/dist/esm/services/authProvider/utils/userSubrequest.js +0 -6
- package/dist/esm/services/documentStore/dynamoEncoding.d.ts +0 -10
- package/dist/esm/services/documentStore/dynamoEncoding.js +0 -45
- package/dist/esm/services/documentStore/fileSystemAssert.d.ts +0 -1
- package/dist/esm/services/documentStore/fileSystemAssert.js +0 -10
- package/dist/esm/services/documentStore/index.d.ts +0 -14
- package/dist/esm/services/documentStore/index.js +0 -1
- package/dist/esm/services/documentStore/unversioned/dynamodb.d.ts +0 -31
- package/dist/esm/services/documentStore/unversioned/dynamodb.js +0 -226
- package/dist/esm/services/documentStore/unversioned/file-system.d.ts +0 -32
- package/dist/esm/services/documentStore/unversioned/file-system.js +0 -174
- package/dist/esm/services/documentStore/unversioned/index.d.ts +0 -2
- package/dist/esm/services/documentStore/unversioned/index.js +0 -1
- package/dist/esm/services/documentStore/versioned/dynamodb.d.ts +0 -25
- package/dist/esm/services/documentStore/versioned/dynamodb.js +0 -139
- package/dist/esm/services/documentStore/versioned/file-system.d.ts +0 -25
- package/dist/esm/services/documentStore/versioned/file-system.js +0 -69
- package/dist/esm/services/documentStore/versioned/index.d.ts +0 -17
- package/dist/esm/services/documentStore/versioned/index.js +0 -1
- package/dist/esm/services/exercisesGateway/index.d.ts +0 -67
- package/dist/esm/services/exercisesGateway/index.js +0 -70
- package/dist/esm/services/fileServer/index.d.ts +0 -30
- package/dist/esm/services/fileServer/index.js +0 -13
- package/dist/esm/services/fileServer/localFileServer.d.ts +0 -13
- package/dist/esm/services/fileServer/localFileServer.js +0 -125
- package/dist/esm/services/fileServer/s3FileServer.d.ts +0 -14
- package/dist/esm/services/fileServer/s3FileServer.js +0 -125
- package/dist/esm/services/launchParams/index.d.ts +0 -2
- package/dist/esm/services/launchParams/index.js +0 -2
- package/dist/esm/services/launchParams/signer.d.ts +0 -23
- package/dist/esm/services/launchParams/signer.js +0 -51
- package/dist/esm/services/launchParams/verifier.d.ts +0 -21
- package/dist/esm/services/launchParams/verifier.js +0 -92
- package/dist/esm/services/logger/console.d.ts +0 -4
- package/dist/esm/services/logger/index.js +0 -27
- package/dist/esm/services/lrsGateway/addStatementDefaultFields.d.ts +0 -5
- package/dist/esm/services/lrsGateway/addStatementDefaultFields.js +0 -14
- package/dist/esm/services/lrsGateway/attempt-utils.d.ts +0 -70
- package/dist/esm/services/lrsGateway/attempt-utils.js +0 -236
- package/dist/esm/services/lrsGateway/file-system.d.ts +0 -15
- package/dist/esm/services/lrsGateway/file-system.js +0 -110
- package/dist/esm/services/lrsGateway/index.d.ts +0 -122
- package/dist/esm/services/lrsGateway/index.js +0 -111
- package/dist/esm/services/lrsGateway/xapiUtils.d.ts +0 -68
- package/dist/esm/services/lrsGateway/xapiUtils.js +0 -99
- package/dist/esm/services/postgresConnection/index.d.ts +0 -28
- package/dist/esm/services/postgresConnection/index.js +0 -58
- package/dist/esm/services/searchProvider/index.d.ts +0 -67
- package/dist/esm/services/searchProvider/index.js +0 -1
- package/dist/esm/services/searchProvider/memorySearchTheBadWay.d.ts +0 -20
- package/dist/esm/services/searchProvider/memorySearchTheBadWay.js +0 -187
- package/dist/esm/services/searchProvider/openSearch.d.ts +0 -28
- package/dist/esm/services/searchProvider/openSearch.js +0 -150
- package/dist/esm/tsconfig.without-specs.esm.tsbuildinfo +0 -1
- package/dist/esm/types.js +0 -1
- package/script/bin/.init-params-script.bash.swp +0 -0
- /package/{script → packages/utils/script}/bin/copy-from-template.bash +0 -0
- /package/{script → packages/utils/script}/bin/delete-stack.bash +0 -0
- /package/{script → packages/utils/script}/bin/deploy.bash +0 -0
- /package/{script → packages/utils/script}/bin/destroy-deployment.bash +0 -0
- /package/{script → packages/utils/script}/bin/empty-bucket.bash +0 -0
- /package/{script → packages/utils/script}/bin/get-arg.bash +0 -0
- /package/{script → packages/utils/script}/bin/get-deployed-environments.bash +0 -0
- /package/{script → packages/utils/script}/bin/get-env-param.bash +0 -0
- /package/{script → packages/utils/script}/bin/get-kwarg.bash +0 -0
- /package/{script → packages/utils/script}/bin/get-stack-param.bash +0 -0
- /package/{script → packages/utils/script}/bin/has-flag.bash +0 -0
- /package/{script → packages/utils/script}/bin/init-constants-script.bash +0 -0
- /package/{script → packages/utils/script}/bin/init-params-script.bash +0 -0
- /package/{script → packages/utils/script}/bin/stack-exists.bash +0 -0
- /package/{script → packages/utils/script}/bin/update-utils.bash +0 -0
- /package/{script → packages/utils/script}/bin/upload-pager-duty-endpoints.bash +0 -0
- /package/{script → packages/utils/script}/bin/upload-params.bash +0 -0
- /package/{script → packages/utils/script}/bin/which.bash +0 -0
- /package/{script → packages/utils/script}/bin-entry.bash +0 -0
- /package/{script → packages/utils/script}/build.bash +0 -0
- /package/{dist/cjs/index.d.ts → packages/utils/src/index.ts} +0 -0
- /package/{dist/cjs/services/launchParams/index.d.ts → packages/utils/src/services/launchParams/index.ts} +0 -0
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import { once } from '../..';
|
|
2
|
+
import { ConfigProviderForConfig, resolveConfigValue } from '../../config';
|
|
3
|
+
import { FetchConfig, GenericFetch } from '../../fetch';
|
|
4
|
+
import { ifDefined } from '../../guards';
|
|
5
|
+
import { METHOD, unsafePayloadValidator } from '../../routing';
|
|
6
|
+
import { embeddedAuthProvider, PostMessageTypes, UserData } from './utils/embeddedAuthProvider';
|
|
7
|
+
import { ApiUser, AuthProvider } from '.';
|
|
8
|
+
|
|
9
|
+
type Config = {
|
|
10
|
+
accountsBase: string;
|
|
11
|
+
};
|
|
12
|
+
interface Initializer<C> {
|
|
13
|
+
configSpace?: C;
|
|
14
|
+
window: Window;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export type EventHandler = (e: {data: any; origin: string; source: Pick<Window, 'postMessage'>}) => void;
|
|
18
|
+
|
|
19
|
+
export interface Window {
|
|
20
|
+
fetch: GenericFetch;
|
|
21
|
+
parent: Pick<Window, 'postMessage'>;
|
|
22
|
+
location: {search: string};
|
|
23
|
+
document: {referrer: string};
|
|
24
|
+
postMessage: (data: any, origin: string) => void;
|
|
25
|
+
addEventListener: (event: 'message', callback: EventHandler) => void;
|
|
26
|
+
removeEventListener: (event: 'message', callback: EventHandler) => void;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const isUserData = unsafePayloadValidator<ApiUser>();
|
|
30
|
+
|
|
31
|
+
export type UpdatableUserFields = Partial<Pick<ApiUser, 'consent_preferences' | 'first_name' | 'last_name'>>;
|
|
32
|
+
|
|
33
|
+
export type BrowserAuthProvider = AuthProvider & {
|
|
34
|
+
getAuthorizedUrl: (urlString: string) => string;
|
|
35
|
+
getAuthorizedLinkUrl: (urlString: string) => string;
|
|
36
|
+
getAuthorizedEmbedUrl: (urlString: string, extraParams?: { [key: string]: string }) => string;
|
|
37
|
+
updateUser: (updates: UpdatableUserFields) => Promise<UserData<ApiUser>>;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export const browserAuthProvider = <C extends string = 'auth'>({window, configSpace}: Initializer<C>) => (configProvider: {[_key in C]: ConfigProviderForConfig<Config>}): BrowserAuthProvider => {
|
|
41
|
+
const config = configProvider[ifDefined(configSpace, 'auth' as C)];
|
|
42
|
+
const accountsBase = once(() => resolveConfigValue(config.accountsBase));
|
|
43
|
+
const queryString = window.location.search;
|
|
44
|
+
const queryKey = 'auth';
|
|
45
|
+
const urlSearchParams = new URLSearchParams(queryString);
|
|
46
|
+
const authQuery = urlSearchParams.get(queryKey);
|
|
47
|
+
const referrer = window.document.referrer ? new URL(window.document.referrer) : undefined;
|
|
48
|
+
const isEmbedded = window.parent !== window;
|
|
49
|
+
const trustedParent = isEmbedded && referrer && referrer.hostname.match(/^(openstax\.org|((.*)(\.openstax\.org|local|localhost)))$/) ? referrer : undefined;
|
|
50
|
+
const {
|
|
51
|
+
embeddedQueryKey, embeddedQueryValue, getAuthorizedEmbedUrl
|
|
52
|
+
} = embeddedAuthProvider(() => getUserData(), { authQuery: { key: queryKey, value: authQuery }, window});
|
|
53
|
+
const embeddedQuery = urlSearchParams.get(embeddedQueryKey);
|
|
54
|
+
|
|
55
|
+
let userData: UserData<ApiUser> = { token: authQuery };
|
|
56
|
+
|
|
57
|
+
const getAuthToken = async () => {
|
|
58
|
+
return (await getUserData()).token;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const getAuthorizedLinkUrl = (urlString: string) => {
|
|
62
|
+
const url = new URL(urlString);
|
|
63
|
+
|
|
64
|
+
if (userData.token) {
|
|
65
|
+
url.searchParams.set(queryKey, userData.token);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return url.href;
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const getAuthorizedUrl = (urlString: string) => {
|
|
72
|
+
const url = new URL(urlString);
|
|
73
|
+
|
|
74
|
+
if (authQuery) {
|
|
75
|
+
url.searchParams.set(queryKey, authQuery);
|
|
76
|
+
} else if (embeddedQuery) {
|
|
77
|
+
url.searchParams.set(queryKey, 'embedded');
|
|
78
|
+
}
|
|
79
|
+
if (embeddedQuery) {
|
|
80
|
+
url.searchParams.set(embeddedQueryKey, embeddedQuery);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return url.href;
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
// *note* that this does not actually prevent cookies from being sent on same-origin
|
|
87
|
+
// requests, i'm not sure if its possible to stop browsers from sending cookies in
|
|
88
|
+
// that case
|
|
89
|
+
const getAuthorizedFetchConfigFromData = (data: typeof userData): FetchConfig => {
|
|
90
|
+
const {token} = data;
|
|
91
|
+
|
|
92
|
+
return token ? {
|
|
93
|
+
headers: {Authorization: `Bearer ${token}`},
|
|
94
|
+
} : {
|
|
95
|
+
credentials: 'include',
|
|
96
|
+
};
|
|
97
|
+
};
|
|
98
|
+
const getAuthorizedFetchConfig = async(): Promise<FetchConfig> => {
|
|
99
|
+
return getAuthorizedFetchConfigFromData(userData.token ? userData : await getUserData());
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
/*
|
|
103
|
+
* requests user identity from parent window via postMessage
|
|
104
|
+
*/
|
|
105
|
+
const getParentWindowUser = () => new Promise<typeof userData>((resolve, reject) => {
|
|
106
|
+
if (!window.parent || !trustedParent) {
|
|
107
|
+
return reject(new Error('parent window is undefined or not trusted'));
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const handler: EventHandler = (event) => {
|
|
111
|
+
if (event.data.type === PostMessageTypes.ReceiveUser && event.origin === trustedParent.origin) {
|
|
112
|
+
clearTimeout(timeout);
|
|
113
|
+
window.removeEventListener('message', handler);
|
|
114
|
+
resolve(event.data.userData);
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
window.addEventListener('message', handler);
|
|
119
|
+
window.parent.postMessage({type: PostMessageTypes.RequestUser}, trustedParent.origin);
|
|
120
|
+
|
|
121
|
+
const timeout = setTimeout(() => {
|
|
122
|
+
window.removeEventListener('message', handler);
|
|
123
|
+
reject(new Error('loading user identity timed out'));
|
|
124
|
+
}, 5000);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
/*
|
|
128
|
+
* requests user identity from accounts api using given token or cookie
|
|
129
|
+
*/
|
|
130
|
+
const getFetchUser = async() => {
|
|
131
|
+
const response = await window.fetch((await accountsBase()).replace(/\/+$/, '') + '/api/user?always_200=true',
|
|
132
|
+
getAuthorizedFetchConfigFromData(userData));
|
|
133
|
+
if (response.status === 200) {
|
|
134
|
+
const body = await response.json();
|
|
135
|
+
const user = isUserData(body) ? body : undefined;
|
|
136
|
+
return {...userData, user};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const message = await response.text();
|
|
140
|
+
throw new Error(`Error response from Accounts ${response.status}: ${message}`);
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
const getUserData = once(async() => {
|
|
144
|
+
// For backwards compatibility
|
|
145
|
+
if (authQuery === 'embedded') { return getParentWindowUser(); }
|
|
146
|
+
|
|
147
|
+
// getFetchUser() will throw here if authQuery is not set
|
|
148
|
+
return await (embeddedQuery === embeddedQueryValue ? getParentWindowUser() : getFetchUser());
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
const getUser = async() => {
|
|
152
|
+
return (await getUserData()).user;
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
const updateUser = async(updates: UpdatableUserFields) => {
|
|
156
|
+
const response = await window.fetch(
|
|
157
|
+
(await accountsBase()).replace(/\/+$/, '') + '/api/user',
|
|
158
|
+
{...getAuthorizedFetchConfigFromData(userData), method: METHOD.PUT, body: JSON.stringify(updates)}
|
|
159
|
+
);
|
|
160
|
+
if (response.status === 200) {
|
|
161
|
+
const user = await response.json();
|
|
162
|
+
if (isUserData(user)) {
|
|
163
|
+
return {...userData, user};
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const message = await response.text();
|
|
168
|
+
throw new Error(`Error response from Accounts ${response.status}: ${message}`);
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
return {
|
|
172
|
+
/**
|
|
173
|
+
* gets the authentication token
|
|
174
|
+
*/
|
|
175
|
+
getAuthToken,
|
|
176
|
+
/**
|
|
177
|
+
* adds auth parameters to the url. this is only safe to use when using javascript to navigate
|
|
178
|
+
* within the current window, eg `window.location = 'https://my.otherservice.com';` anchors
|
|
179
|
+
* should use getAuthorizedLinkUrl for their href.
|
|
180
|
+
*
|
|
181
|
+
* result unreliable unless `getUser` is resolved first.
|
|
182
|
+
*/
|
|
183
|
+
getAuthorizedUrl,
|
|
184
|
+
/**
|
|
185
|
+
* all link href-s must be rendered with auth tokens so that they work when opened in a new tab
|
|
186
|
+
*
|
|
187
|
+
* result unreliable unless `getUser` is resolved first.
|
|
188
|
+
*/
|
|
189
|
+
getAuthorizedLinkUrl,
|
|
190
|
+
/**
|
|
191
|
+
* gets an authorized url for an iframe src. sets params on the url and saves its
|
|
192
|
+
* origin to trust releasing user identity to it
|
|
193
|
+
*/
|
|
194
|
+
getAuthorizedEmbedUrl,
|
|
195
|
+
/**
|
|
196
|
+
* gets second argument for `fetch` that has authentication token or cookie
|
|
197
|
+
*/
|
|
198
|
+
getAuthorizedFetchConfig,
|
|
199
|
+
/**
|
|
200
|
+
* loads current user identity. does not reflect changes in identity after being called the first time.
|
|
201
|
+
*/
|
|
202
|
+
getUser,
|
|
203
|
+
loadUserData: getUser,
|
|
204
|
+
/**
|
|
205
|
+
* updates user settings, for example the cookie consent preferences
|
|
206
|
+
*/
|
|
207
|
+
updateUser,
|
|
208
|
+
};
|
|
209
|
+
};
|
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
import { SessionExpiredError } from '../../errors';
|
|
2
|
+
import { GenericFetch } from '../../fetch';
|
|
3
|
+
import { createCoreLogger } from '../logger';
|
|
4
|
+
import { decryptionAuthProvider } from './decryption';
|
|
5
|
+
import { ApiUser, User } from '.';
|
|
6
|
+
|
|
7
|
+
describe('decryptionAuthProvider', () => {
|
|
8
|
+
let fetchSpy: jest.SpyInstance;
|
|
9
|
+
let initializer: { fetch: GenericFetch };
|
|
10
|
+
|
|
11
|
+
beforeEach(() => {
|
|
12
|
+
jest.useFakeTimers();
|
|
13
|
+
jest.setSystemTime(new Date(2023, 3, 2));
|
|
14
|
+
|
|
15
|
+
fetchSpy = jest.fn();
|
|
16
|
+
initializer = {fetch: fetchSpy as any};
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
// These values are used in the Accounts local dev environment, not any real Accounts deployments
|
|
20
|
+
const config = {
|
|
21
|
+
decryption: {
|
|
22
|
+
accountsBase: 'accountsBase',
|
|
23
|
+
cookieName: 'oxa_dev',
|
|
24
|
+
encryptionPrivateKey: 'RvGHVZ/kvzUAA5Z3t68+FNhuMCJxkzv+', // cspell:disable-line
|
|
25
|
+
signaturePublicKey: `-----BEGIN PUBLIC KEY-----
|
|
26
|
+
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7JRnvbwTd2jGDWaW5Wc3
|
|
27
|
+
HiBWd00ipH5FbmJe1fFeW/2Ji5w5MZ0evtorsV2lVBlP2G5THjmtHK1fdqC+2xiM
|
|
28
|
+
nicxqGMn3C4T8EnS86knl0Yv3VEfDRZBoWsUX2s2y0xKu8Pvt6nbhrnkS8pi8+Au
|
|
29
|
+
huT0ad/891aAhmp1QDkh+vI9NTYHb0mXYqMmJYZPJRL4eO6Z4j6djeHDz8D/TzWy
|
|
30
|
+
Ah0cDEmTncO6YuJrf6CTi9eJce8pi+X8fhNTlZdfzIFE8BShAOxieYN1OV1RYmCT
|
|
31
|
+
XD8jEL1ZgDxpIiZkB9u3tzUL1WZi7YENGouLhg9b/BUIw0dFXGkNErvtmDD7Ce8I
|
|
32
|
+
twIDAQAB
|
|
33
|
+
-----END PUBLIC KEY-----`,
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
// the below token expires at 2308840470 (2043-03-01T16:34:30.000Z)
|
|
38
|
+
// cspell:disable-next-line
|
|
39
|
+
const auth = 'eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIn0..v-Ot9t9EvGRkzXVx.D4k0ebDXUM8PNjiuvfCHBP_lNgIEzUkU9ibXLt4QxZXifd6ULAMofiWjT87L_3QKS2QfbrRz3Acah9wSNW4TFrtl5khBioWg3xjaImPtshJnBL7fPtEZWhNBkhkO1R4YK2Fr2mo5d-Y3_mkINHHyF19kIJJox6HsPqNaUSob59G2QQyza0TxJQMDjybsArL3GOT2PnVy_HQuIZmLqpypaoPnEoJ_WwvjK1oyORdUsYhv8kPzF9fPNZZjj2moqHIw41cc0ajeyw4TTvfkaYBC2Ovs2lVovjlj4PiPq9nAq-vpVII1XHp7qZQtQcWY-pGiVTFrnUErqNjZHwYKd0Y6kMgm1aqP2P3Qrt7nLCqEZf--LOpugk1Uunc_xBbPTjSBs9KJS_doREMmzvs9eqmn_V1_dxMgn3pMyMCMdD5ZKA89fpd0oT7kLDDawY_UfSEpmX8dI2ouvbW8VWtphhLGhjhssCcIv_ksGae59TS-WqGstT3Jd9D-uAAyz0wIuegokQt-9m5JT9vebDPhIgoRA-NgflQFz0xP1ERiTDbWpODYY5vkg-qzhKJPgSTLBYgGTBVLZzzwSoEOhAp5R_mfxZULXWacCqJo4GPvZ6bgSJdhFq2ZQhOgT_WNV5wYYBu_NqNh0OHZ0zzgZRX0tmsvgCFr0_VXeO0apDpg_bp7W1EF3dnUopTfdYtl0YQ8xI3dTrOX4tbRQf5QBKyXARoch3ObDtlbbcF6BN55AJXBa5bkl4m2pb3fzyoobXCFiAjTDKgRi_Qf7wnEww35gFs74ST3H-QGRBCTC2zMFRbVZ-kNXERs6Re2Ez_df-cVdfXk0CWs9T0GT6oFZOz4meT2bj7L-x8Ugerr-_CUVaSjC3NwdrtfBrw9E-k1pTeJ9_dMYJMJ6w7-sVu7X8BRof-bh3pBBWH45b9RzCvXd2d-AyIoeag2ZRfkfLk5vdiWSOtNlXTIgM8IKxZYy8MrZpXqLPBK6pAiMZN8Ou94ZBvq.eMtwHum3NKJNDt0SmqdPZw';
|
|
40
|
+
|
|
41
|
+
// cspell:disable-next-line
|
|
42
|
+
const properlyEncodedCookieWithInvalidPayload = 'eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIn0..A61VXXx1Ap9-XVPt.vbO8tIN8PK_m3Z7XyZf4Efxsj-Nc5pmPuYs8IBpymo323s9Hund_jJRAPI2TDJV-cna-Zhm2bYy6a64uCfyX-YFgrQV17cIkDOZXxV3_SdOGGcnXBe3RP-soCRY4ARlS3SWKPbjrh_1HUMZO30Rxh3r_LEKJRGiXAybrrb-Ii99ZYoy1z06iCC61aZGE-NaXYsp3mx4hdoO8HSLOLIyUa3rFJQTfKAq5GoRlsfKXZTUYiaHbLRWCY4tht7Jy8pKJp01pdFE2oP37Xf6gyvWmbnIuEyqGH3S9QSIkGM28sPjfdh5w-VYL_cF5-Cy3D6kplMra5dnZ1QIlgkJPycTxR2aQXitJXpIFOMgtD0L5-WxPRBgY_-85aHYIeZ3SA-5YrAiPDoj4H8QBZWVdbmLtJhPqtj8IBA8jV0sKbNwh2lky7bSGXEzG9jRdEE5WiD95rRV7WoEHMWtbvH8qZstzfbRmWzBNdJYLh828UpdkywrB2OzxkEiJhol8vg0GgEiaZFWhsCa5IVwfLJ_JSnR142L0znrF0DikLdFHdbIlhvxZ-yXvhlzLWRf3bCYqyuQP1Bq5J9bVGxxijWkLx8N9kB2FvhVYwa2-MLJCF2XX4NZT9w0WihSX5Rmwyeyf88OA-83Cg6ipkm-uW0Gfy2QiVacuV5hzuoPzG4WycZgXAbFHPTPN-nin_ul9tWeOpyFkWAjIuXhghUeUFl20xfZSE4xrNCN45ZJ9nxnPE4kA_g17VKSaZxzLnoHaxH4RHq2D7QydmFaxY_nqlbqz.sKv3xa1Vp4ZzZyVPpL3uXg';
|
|
43
|
+
|
|
44
|
+
describe('no authorization header or authorization header doesn\'t start with "Bearer "', () => {
|
|
45
|
+
// To show blank Authorization headers are ignored (excluding "Bearer " prefix)
|
|
46
|
+
const request = {headers: {Authorization: 'Bearer '}};
|
|
47
|
+
const logger = createCoreLogger(jest.fn());
|
|
48
|
+
const middleware = {request, logger};
|
|
49
|
+
|
|
50
|
+
it('resolves undefined without a cookie', async() => {
|
|
51
|
+
const loader = decryptionAuthProvider(initializer)(config)(middleware);
|
|
52
|
+
const exp = await loader.getTokenExpiration();
|
|
53
|
+
expect(exp).toBeUndefined();
|
|
54
|
+
const user = await loader.getUser();
|
|
55
|
+
expect(user).toBeUndefined();
|
|
56
|
+
const userData = await loader.loadUserData();
|
|
57
|
+
expect(userData).toBeUndefined();
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('resolves undefined without the right cookie', async() => {
|
|
61
|
+
const loader = decryptionAuthProvider(initializer)(config)(
|
|
62
|
+
{...middleware, request: {...request, cookies: ['bad_cookie=bad-bad-bad']}}
|
|
63
|
+
);
|
|
64
|
+
const exp = await loader.getTokenExpiration();
|
|
65
|
+
expect(exp).toBeUndefined();
|
|
66
|
+
const user = await loader.getUser();
|
|
67
|
+
expect(user).toBeUndefined();
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('resolves undefined user/null expiration with an invalid cookie', async() => {
|
|
71
|
+
const loader = decryptionAuthProvider(initializer)(config)(
|
|
72
|
+
{...middleware, request: {...request, cookies: ['bad_cookie=bad-bad-bad', 'oxa_dev=invalid']}}
|
|
73
|
+
);
|
|
74
|
+
const exp = await loader.getTokenExpiration();
|
|
75
|
+
expect(exp).toBeNull();
|
|
76
|
+
const user = await loader.getUser();
|
|
77
|
+
expect(user).toBeUndefined();
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('returns the expiration date but not the user with an expired cookie', async() => {
|
|
81
|
+
jest.setSystemTime(new Date(2043, 2, 1, 17, 0));
|
|
82
|
+
|
|
83
|
+
const loader = decryptionAuthProvider(initializer)(config)(
|
|
84
|
+
{...middleware, request: {...request, cookies: ['bad_cookie=bad-bad-bad', `oxa_dev=${auth}`]}}
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
expect(await loader.getTokenExpiration()).toBe(2308840470);
|
|
88
|
+
expect(await loader.getTokenExpiration(auth)).toBe(2308840470);
|
|
89
|
+
|
|
90
|
+
const getError = async () => {
|
|
91
|
+
try {
|
|
92
|
+
await loader.getUser();
|
|
93
|
+
throw new Error('should not be reachable');
|
|
94
|
+
} catch (e) {
|
|
95
|
+
return e;
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
expect(await getError()).toBeInstanceOf(SessionExpiredError);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it('returns empty fetch authorization', async() => {
|
|
103
|
+
const provider = decryptionAuthProvider(initializer)(config)(middleware);
|
|
104
|
+
expect(await provider.getAuthorizedFetchConfig()).toEqual({});
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('decrypts a valid SSO cookie', async() => {
|
|
108
|
+
const userResponse = {
|
|
109
|
+
applications: [],
|
|
110
|
+
id: 10001068,
|
|
111
|
+
is_test: false,
|
|
112
|
+
support_identifier: 'cs_585fb1a7',
|
|
113
|
+
uuid: '1b2dc73a-a792-462b-9b0f-59bd22bac26d',
|
|
114
|
+
} as unknown as User; // This old cookie is missing the following fields: name, faculty_status, is_admin
|
|
115
|
+
const loader = decryptionAuthProvider(initializer)(config)(
|
|
116
|
+
{...middleware, request: {...request, cookies: ['bad_cookie=bad-bad-bad', `oxa_dev=${auth}`]}}
|
|
117
|
+
);
|
|
118
|
+
const exp = await loader.getTokenExpiration();
|
|
119
|
+
expect(exp).toBe(2308840470);
|
|
120
|
+
await loader.getUser();
|
|
121
|
+
await loader.getUser();
|
|
122
|
+
const user = await loader.getUser();
|
|
123
|
+
expect(user).toStrictEqual(userResponse);
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
describe('authorization header starts with "Bearer "', () => {
|
|
128
|
+
// To show cookies are ignored when the Authorization header is present
|
|
129
|
+
const request = {cookies: ['bad_cookie=bad-bad-bad', `oxa_dev=${auth}`]};
|
|
130
|
+
const logger = createCoreLogger(jest.fn());
|
|
131
|
+
const middleware = {request, logger};
|
|
132
|
+
|
|
133
|
+
it('resolves undefined user/null expiration with an invalid token', async() => {
|
|
134
|
+
const loader = decryptionAuthProvider(initializer)(config)(
|
|
135
|
+
{...middleware, request: {...request, headers: {Authorization: 'Bearer invalid'}}}
|
|
136
|
+
);
|
|
137
|
+
const exp = await loader.getTokenExpiration();
|
|
138
|
+
expect(exp).toBeNull();
|
|
139
|
+
const user = await loader.getUser();
|
|
140
|
+
expect(user).toBeUndefined();
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it('returns the expiration date but not the user with an expired token', async() => {
|
|
144
|
+
jest.setSystemTime(new Date(2043, 2, 1, 16, 40));
|
|
145
|
+
const loader = decryptionAuthProvider(initializer)(config)(
|
|
146
|
+
{...middleware, request: {...request, headers: {Authorization: `Bearer ${auth}`}}}
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
expect(await loader.getTokenExpiration()).toBe(2308840470);
|
|
150
|
+
expect(await loader.getTokenExpiration(auth)).toBe(2308840470);
|
|
151
|
+
|
|
152
|
+
const getError = async () => {
|
|
153
|
+
try {
|
|
154
|
+
await loader.getUser();
|
|
155
|
+
throw new Error('should not be reachable');
|
|
156
|
+
} catch (e) {
|
|
157
|
+
return e;
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
expect(await getError()).toBeInstanceOf(SessionExpiredError);
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it('resolves undefined user/null expiration with wonky token', async() => {
|
|
165
|
+
jest.setSystemTime(new Date(2043, 2, 1, 16, 40));
|
|
166
|
+
const loader = decryptionAuthProvider(initializer)(config)(
|
|
167
|
+
{
|
|
168
|
+
...middleware,
|
|
169
|
+
request: { ...request, headers: { Authorization: `Bearer ${properlyEncodedCookieWithInvalidPayload}` } }
|
|
170
|
+
}
|
|
171
|
+
);
|
|
172
|
+
await loader.getUser();
|
|
173
|
+
await loader.getUser();
|
|
174
|
+
const exp = await loader.getTokenExpiration();
|
|
175
|
+
expect(exp).toBeNull();
|
|
176
|
+
const user = await loader.getUser();
|
|
177
|
+
expect(user).toBeUndefined();
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it('decrypts expired token within 5m clock tolerance', async() => {
|
|
181
|
+
jest.setSystemTime(new Date(2043, 2, 1, 16, 37));
|
|
182
|
+
const userResponse = {
|
|
183
|
+
applications: [],
|
|
184
|
+
id: 10001068,
|
|
185
|
+
is_test: false,
|
|
186
|
+
support_identifier: 'cs_585fb1a7',
|
|
187
|
+
uuid: '1b2dc73a-a792-462b-9b0f-59bd22bac26d',
|
|
188
|
+
} as unknown as User;
|
|
189
|
+
const loader = decryptionAuthProvider(initializer)(config)(
|
|
190
|
+
{...middleware, request: {...request, headers: {Authorization: `Bearer ${auth}`}}}
|
|
191
|
+
);
|
|
192
|
+
const exp = await loader.getTokenExpiration();
|
|
193
|
+
expect(exp).toBe(2308840470);
|
|
194
|
+
await loader.getUser();
|
|
195
|
+
await loader.getUser();
|
|
196
|
+
const user = await loader.getUser();
|
|
197
|
+
expect(user).toStrictEqual(userResponse);
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
it('decrypts a valid SSO token', async() => {
|
|
201
|
+
jest.setSystemTime(new Date(2043, 2, 1, 16, 30));
|
|
202
|
+
const userResponse = {
|
|
203
|
+
applications: [],
|
|
204
|
+
id: 10001068,
|
|
205
|
+
is_test: false,
|
|
206
|
+
support_identifier: 'cs_585fb1a7',
|
|
207
|
+
uuid: '1b2dc73a-a792-462b-9b0f-59bd22bac26d',
|
|
208
|
+
} as unknown as User;
|
|
209
|
+
const loader = decryptionAuthProvider(initializer)(config)(
|
|
210
|
+
{...middleware, request: {...request, headers: {Authorization: `Bearer ${auth}`}}}
|
|
211
|
+
);
|
|
212
|
+
const exp = await loader.getTokenExpiration();
|
|
213
|
+
expect(exp).toBe(2308840470);
|
|
214
|
+
await loader.getUser();
|
|
215
|
+
await loader.getUser();
|
|
216
|
+
const user = await loader.getUser();
|
|
217
|
+
expect(user).toStrictEqual(userResponse);
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
it('generates authorized fetch-config', async () => {
|
|
221
|
+
const provider = decryptionAuthProvider(initializer)(config)(
|
|
222
|
+
{...middleware, request: {...request, headers: {Authorization: `Bearer ${auth}`}}}
|
|
223
|
+
);
|
|
224
|
+
expect(await provider.getAuthorizedFetchConfig()).toEqual({headers: {Authorization: `Bearer ${auth}`}});
|
|
225
|
+
});
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
describe('auth queryString parameter', () => {
|
|
229
|
+
// To show the Authorization header and cookies are ignored when an auth queryString parameter is present
|
|
230
|
+
const request = {cookies: ['bad_cookie=bad-bad-bad', `oxa_dev=${auth}`], headers: { Authorization: 'Bearer bad' }};
|
|
231
|
+
const logger = createCoreLogger(jest.fn());
|
|
232
|
+
const middleware = {request, logger};
|
|
233
|
+
|
|
234
|
+
it('resolves undefined user/null expiration with an invalid token', async() => {
|
|
235
|
+
const loader = decryptionAuthProvider(initializer)(config)(
|
|
236
|
+
{...middleware, request: {...request, queryStringParameters: { auth: 'invalid' }}}
|
|
237
|
+
);
|
|
238
|
+
const exp = await loader.getTokenExpiration();
|
|
239
|
+
expect(exp).toBeNull();
|
|
240
|
+
const user = await loader.getUser();
|
|
241
|
+
expect(user).toBeUndefined();
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
it('returns the expiration date but not the user with an expired token', async() => {
|
|
245
|
+
jest.setSystemTime(new Date(2043, 2, 1, 16, 40));
|
|
246
|
+
const loader = decryptionAuthProvider(initializer)(config)(
|
|
247
|
+
{...middleware, request: {...request, queryStringParameters: { auth }}}
|
|
248
|
+
);
|
|
249
|
+
|
|
250
|
+
expect(await loader.getTokenExpiration()).toBe(2308840470);
|
|
251
|
+
expect(await loader.getTokenExpiration(auth)).toBe(2308840470);
|
|
252
|
+
|
|
253
|
+
const getError = async () => {
|
|
254
|
+
try {
|
|
255
|
+
await loader.getUser();
|
|
256
|
+
throw new Error('should not be reachable');
|
|
257
|
+
} catch (e) {
|
|
258
|
+
return e;
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
expect(await getError()).toBeInstanceOf(SessionExpiredError);
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
it('resolves undefined user/null expiration with wonky token', async() => {
|
|
266
|
+
jest.setSystemTime(new Date(2043, 2, 1, 16, 40));
|
|
267
|
+
const loader = decryptionAuthProvider(initializer)(config)(
|
|
268
|
+
{
|
|
269
|
+
...middleware,
|
|
270
|
+
request: { ...request, queryStringParameters: { auth: properlyEncodedCookieWithInvalidPayload } }
|
|
271
|
+
}
|
|
272
|
+
);
|
|
273
|
+
const exp = await loader.getTokenExpiration();
|
|
274
|
+
expect(exp).toBeNull();
|
|
275
|
+
await loader.getUser();
|
|
276
|
+
await loader.getUser();
|
|
277
|
+
const user = await loader.getUser();
|
|
278
|
+
expect(user).toBeUndefined();
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
it('decrypts expired token within 5m clock tolerance', async() => {
|
|
282
|
+
jest.setSystemTime(new Date(2043, 2, 1, 16, 37));
|
|
283
|
+
const userResponse = {
|
|
284
|
+
applications: [],
|
|
285
|
+
id: 10001068,
|
|
286
|
+
is_test: false,
|
|
287
|
+
support_identifier: 'cs_585fb1a7',
|
|
288
|
+
uuid: '1b2dc73a-a792-462b-9b0f-59bd22bac26d',
|
|
289
|
+
} as unknown as User;
|
|
290
|
+
const loader = decryptionAuthProvider(initializer)(config)(
|
|
291
|
+
{...middleware, request: {...request, queryStringParameters: { auth }}}
|
|
292
|
+
);
|
|
293
|
+
expect(await loader.getTokenExpiration()).toBe(2308840470);
|
|
294
|
+
expect(await loader.getTokenExpiration(auth)).toBe(2308840470);
|
|
295
|
+
await loader.getUser();
|
|
296
|
+
await loader.getUser();
|
|
297
|
+
const user = await loader.getUser();
|
|
298
|
+
expect(user).toStrictEqual(userResponse);
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
it('decrypts a valid SSO token', async() => {
|
|
302
|
+
jest.setSystemTime(new Date(2043, 2, 1, 16, 30));
|
|
303
|
+
const userResponse = {
|
|
304
|
+
applications: [],
|
|
305
|
+
id: 10001068,
|
|
306
|
+
is_test: false,
|
|
307
|
+
support_identifier: 'cs_585fb1a7',
|
|
308
|
+
uuid: '1b2dc73a-a792-462b-9b0f-59bd22bac26d',
|
|
309
|
+
} as unknown as User;
|
|
310
|
+
const loader = decryptionAuthProvider(initializer)(config)(
|
|
311
|
+
{...middleware, request: {...request, queryStringParameters: { auth }}}
|
|
312
|
+
);
|
|
313
|
+
const exp = await loader.getTokenExpiration();
|
|
314
|
+
expect(exp).toBe(2308840470);
|
|
315
|
+
await loader.getUser();
|
|
316
|
+
await loader.getUser();
|
|
317
|
+
const user = await loader.getUser();
|
|
318
|
+
expect(user).toStrictEqual(userResponse);
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
it('generates authorized fetch-config', async () => {
|
|
322
|
+
const provider = decryptionAuthProvider(initializer)(config)(
|
|
323
|
+
{...middleware, request: {...request, queryStringParameters: { auth }}}
|
|
324
|
+
);
|
|
325
|
+
expect(await provider.getAuthorizedFetchConfig()).toEqual({headers: {Authorization: `Bearer ${auth}`}});
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
it('can load the complete user data', async () => {
|
|
329
|
+
const provider = decryptionAuthProvider(initializer)(config)(
|
|
330
|
+
{...middleware, request: {...request, queryStringParameters: { auth }}}
|
|
331
|
+
);
|
|
332
|
+
const userData = { id: 1 } as ApiUser;
|
|
333
|
+
fetchSpy.mockReturnValueOnce(Promise.resolve({ json: () => userData }));
|
|
334
|
+
expect(await provider.loadUserData()).toEqual(userData);
|
|
335
|
+
});
|
|
336
|
+
});
|
|
337
|
+
});
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import type { ConfigProviderForConfig } from '../../config';
|
|
2
|
+
import { resolveConfigValue } from '../../config/resolveConfigValue';
|
|
3
|
+
import { SessionExpiredError } from '../../errors';
|
|
4
|
+
import { GenericFetch } from '../../fetch';
|
|
5
|
+
import { ifDefined } from '../../guards';
|
|
6
|
+
import { once } from '../../misc/helpers';
|
|
7
|
+
import { decryptAndVerify } from './utils/decryptAndVerify';
|
|
8
|
+
import { loadUserData } from './utils/userSubrequest';
|
|
9
|
+
import { ApiUser, AuthProvider, CookieAuthProvider, getAuthTokenOrCookie, TokenUser } from '.';
|
|
10
|
+
|
|
11
|
+
type Config = {
|
|
12
|
+
accountsBase: string;
|
|
13
|
+
cookieName: string;
|
|
14
|
+
encryptionPrivateKey: string;
|
|
15
|
+
signaturePublicKey: string;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
interface Initializer<C> {
|
|
19
|
+
configSpace?: C;
|
|
20
|
+
fetch: GenericFetch;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export type DecryptionAuthProvider = AuthProvider & {
|
|
24
|
+
/*
|
|
25
|
+
* the token can optionally be fed in via the tokenString (useful in lti-gateway)
|
|
26
|
+
* null result means no expiration
|
|
27
|
+
* undefined result means unknown (because the authProvider cannot decrypt the token, etc)
|
|
28
|
+
*/
|
|
29
|
+
getTokenExpiration: (tokenString?: string) => Promise<number | null | undefined>;
|
|
30
|
+
loadUserData: () => Promise<ApiUser | undefined>;
|
|
31
|
+
};
|
|
32
|
+
export const decryptionAuthProvider = <C extends string = 'decryption'>(initializer: Initializer<C>) => (configProvider: {[_key in C]: ConfigProviderForConfig<Config>}): CookieAuthProvider<DecryptionAuthProvider> => {
|
|
33
|
+
const config = configProvider[ifDefined(initializer.configSpace, 'decryption' as C)];
|
|
34
|
+
const accountsBase = once(() => resolveConfigValue(config.accountsBase));
|
|
35
|
+
const cookieName = once(() => resolveConfigValue(config.cookieName));
|
|
36
|
+
const encryptionPrivateKey = once(() => resolveConfigValue(config.encryptionPrivateKey));
|
|
37
|
+
const signaturePublicKey = once(() => resolveConfigValue(config.signaturePublicKey));
|
|
38
|
+
|
|
39
|
+
return ({request, logger}) => {
|
|
40
|
+
let user: TokenUser | undefined;
|
|
41
|
+
let userData: ApiUser | undefined;
|
|
42
|
+
|
|
43
|
+
const getAuthToken = async() => getAuthTokenOrCookie(request, await cookieName())[0];
|
|
44
|
+
const getAuthorizedFetchConfig = async() => {
|
|
45
|
+
const [token, headers] = getAuthTokenOrCookie(request, await cookieName());
|
|
46
|
+
if (!token) {
|
|
47
|
+
return {};
|
|
48
|
+
}
|
|
49
|
+
return { headers };
|
|
50
|
+
};
|
|
51
|
+
const getDecryptedPayload = async(tokenString?: string) => {
|
|
52
|
+
const token = tokenString ?? await getAuthToken();
|
|
53
|
+
if (!token) {
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return decryptAndVerify(token, await encryptionPrivateKey(), await signaturePublicKey());
|
|
58
|
+
};
|
|
59
|
+
const getUser = async() => {
|
|
60
|
+
if (!user) {
|
|
61
|
+
const result = await getDecryptedPayload();
|
|
62
|
+
if (!result) { return undefined; }
|
|
63
|
+
|
|
64
|
+
if ('error' in result && result.error == 'expired token') {
|
|
65
|
+
throw new SessionExpiredError();
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if ('user' in result) {
|
|
69
|
+
logger.setContext({user: result.user.uuid});
|
|
70
|
+
user = result.user;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return user;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
return {
|
|
77
|
+
getAuthToken,
|
|
78
|
+
getAuthorizedFetchConfig,
|
|
79
|
+
getTokenExpiration: async(tokenString?: string) => {
|
|
80
|
+
const payload = await getDecryptedPayload(tokenString);
|
|
81
|
+
return payload ? (payload.exp ?? null) : undefined;
|
|
82
|
+
},
|
|
83
|
+
getUser,
|
|
84
|
+
loadUserData: async() => {
|
|
85
|
+
if (!userData) {
|
|
86
|
+
const token = await getAuthToken();
|
|
87
|
+
|
|
88
|
+
if (!token) {
|
|
89
|
+
return undefined;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
userData = await loadUserData(initializer.fetch, await accountsBase(), await cookieName(), token);
|
|
93
|
+
}
|
|
94
|
+
return userData;
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
};
|
|
98
|
+
};
|