From baf96019a8ca706255a4ecb0848fc95e91667e6e Mon Sep 17 00:00:00 2001 From: shobhit upadhyay Date: Thu, 4 Sep 2025 13:08:51 +0530 Subject: [PATCH 1/9] feat: add build script and enhance OAuth token handling - Introduced a new build.sh script for region selection and OAuth login. - Added app.json to .gitignore and included manifest.json in API .gitignore. - Updated package dependencies for improved functionality. - Implemented saveOAuthToken endpoint for secure token handling. - Enhanced region configuration and API host management in constants. - Added error handling and logging improvements in auth service. --- .gitignore | 3 + api/.gitignore | 3 +- api/package-lock.json | 529 ++++++++++++++++++++++++- api/package.json | 2 +- api/src/constants/index.ts | 15 + api/src/controllers/auth.controller.ts | 12 + api/src/models/types.ts | 7 + api/src/routes/auth.routes.ts | 11 + api/src/services/auth.service.ts | 214 ++++++++-- api/sso.utils.js | 283 +++++++++++++ build.sh | 94 +++++ 11 files changed, 1142 insertions(+), 31 deletions(-) create mode 100644 api/sso.utils.js create mode 100755 build.sh diff --git a/.gitignore b/.gitignore index 07d1ff8d3..ff59d7935 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,9 @@ # Mono auto generated files mono_crash.* +#App JSON file +app.json + # Build results [Dd]ebug/ [Dd]ebugPublic/ diff --git a/api/.gitignore b/api/.gitignore index 736178335..a3563aa2f 100644 --- a/api/.gitignore +++ b/api/.gitignore @@ -366,5 +366,4 @@ database/ /cmsMigrationData /migration-data **/copy* -**copy.ts -manifest.json \ No newline at end of file +**copy.ts \ No newline at end of file diff --git a/api/package-lock.json b/api/package-lock.json index 8f752ca97..667d2195c 100644 --- a/api/package-lock.json +++ b/api/package-lock.json @@ -43,6 +43,7 @@ "devDependencies": { "@types/cors": "^2.8.17", "@types/express": "^4.17.21", + "@types/express-session": "^1.18.2", "@types/fs-extra": "^11.0.4", "@types/fs-readdir-recursive": "^1.1.3", "@types/jsdom": "^21.1.7", @@ -3559,6 +3560,11 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@exodus/schemasafe": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@exodus/schemasafe/-/schemasafe-1.3.0.tgz", + "integrity": "sha512-5Aap/GaRupgNx/feGBwLLTVv8OQFfv3pq2lPRzPg9R+IOBnDgghTGW7l7EuVXOvg5cc/xSAlRW8rBrjIC3Nvqw==" + }, "node_modules/@fast-csv/format": { "version": "4.3.5", "resolved": "https://registry.npmjs.org/@fast-csv/format/-/format-4.3.5.tgz", @@ -3654,6 +3660,14 @@ "url": "https://github.com/sponsors/nzakas" } }, + "node_modules/@humanwhocodes/momoa": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@humanwhocodes/momoa/-/momoa-2.0.4.tgz", + "integrity": "sha512-RE815I4arJFtt+FVeU1Tgp9/Xvecacji8w/V6XtXsWWH/wz/eNkNbhb+ny/+PlVZjV0rxQpRSQKNKE3lcktHEA==", + "engines": { + "node": ">=10.10.0" + } + }, "node_modules/@humanwhocodes/object-schema": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", @@ -4215,7 +4229,7 @@ "yarn": "^1.22.22" }, "engines": { - "node": ">=18.0.0" + "node": ">=14" } }, "node_modules/@otplib/core": { @@ -4812,6 +4826,15 @@ "@types/send": "*" } }, + "node_modules/@types/express-session": { + "version": "1.18.2", + "resolved": "https://registry.npmjs.org/@types/express-session/-/express-session-1.18.2.tgz", + "integrity": "sha512-k+I0BxwVXsnEU2hV77cCobC08kIsn4y44C3gC0b46uxZVMaXA04lSPgRLR/bSL2w0t0ShJiG8o4jPzRG/nscFg==", + "dev": true, + "dependencies": { + "@types/express": "*" + } + }, "node_modules/@types/fs-extra": { "version": "11.0.4", "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-11.0.4.tgz", @@ -4847,8 +4870,7 @@ "node_modules/@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==" }, "node_modules/@types/json5": { "version": "0.0.29", @@ -5345,6 +5367,19 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/ajv-draft-04": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz", + "integrity": "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==", + "peerDependencies": { + "ajv": "^8.5.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, "node_modules/ajv-formats": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", @@ -6000,6 +6035,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/call-me-maybe": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.2.tgz", + "integrity": "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==" + }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -6028,6 +6068,11 @@ "cdl": "bin/cdl.js" } }, + "node_modules/caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==" + }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -6334,11 +6379,40 @@ "node": ">= 0.8" } }, + "node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "engines": { + "node": ">=14" + } + }, "node_modules/commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==" }, + "node_modules/compute-gcd": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/compute-gcd/-/compute-gcd-1.2.1.tgz", + "integrity": "sha512-TwMbxBNz0l71+8Sc4czv13h4kEqnchV9igQZBi6QUaz09dnz13juGnnaWWJTRsP3brxOoxeB4SA2WELLw1hCtg==", + "dependencies": { + "validate.io-array": "^1.0.3", + "validate.io-function": "^1.0.2", + "validate.io-integer-array": "^1.0.0" + } + }, + "node_modules/compute-lcm": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/compute-lcm/-/compute-lcm-1.1.2.tgz", + "integrity": "sha512-OFNPdQAXnQhDSKioX8/XYT6sdUlXwpeMjfd6ApxMJfyZ4GxmLR1xvMERctlYhlHwIiz6CSpBc2+qYKjHGZw4TQ==", + "dependencies": { + "compute-gcd": "^1.2.1", + "validate.io-array": "^1.0.3", + "validate.io-function": "^1.0.2", + "validate.io-integer-array": "^1.0.0" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -6629,6 +6703,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/datauri": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/datauri/-/datauri-4.1.0.tgz", + "integrity": "sha512-y17kh32+I82G+ED9MNWFkZiP/Cq/vO1hN9+tSZsT9C9qn3NrvcBnh7crSepg0AQPge1hXx2Ca44s1FRdv0gFWA==", + "dependencies": { + "image-size": "1.0.0", + "mimer": "^2.0.2" + }, + "engines": { + "node": ">= 10" + } + }, "node_modules/date-fns": { "version": "1.30.1", "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.30.1.tgz", @@ -7129,11 +7215,59 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/es5-ext": { + "version": "0.10.64", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz", + "integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==", + "hasInstallScript": true, + "dependencies": { + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "esniff": "^2.0.1", + "next-tick": "^1.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", + "dependencies": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, "node_modules/es6-promise": { "version": "4.2.8", "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" }, + "node_modules/es6-symbol": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.4.tgz", + "integrity": "sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==", + "dependencies": { + "d": "^1.0.2", + "ext": "^1.7.0" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/es6-weak-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", + "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", + "dependencies": { + "d": "1", + "es5-ext": "^0.10.46", + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.1" + } + }, "node_modules/esbuild": { "version": "0.27.2", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz", @@ -7827,6 +7961,20 @@ "node": "*" } }, + "node_modules/esniff": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz", + "integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==", + "dependencies": { + "d": "^1.0.1", + "es5-ext": "^0.10.62", + "event-emitter": "^0.3.5", + "type": "^2.7.2" + }, + "engines": { + "node": ">=0.10" + } + }, "node_modules/espree": { "version": "9.6.1", "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", @@ -7909,6 +8057,15 @@ "node": ">= 0.6" } }, + "node_modules/event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", + "dependencies": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, "node_modules/execa": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", @@ -8053,6 +8210,50 @@ "url": "https://opencollective.com/express" } }, + "node_modules/express-session": { + "version": "1.18.2", + "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.18.2.tgz", + "integrity": "sha512-SZjssGQC7TzTs9rpPDuUrR23GNZ9+2+IkA/+IJWmvQilTr5OSliEHGF+D9scbIpdC6yGtTI0/VhaHoVes2AN/A==", + "dependencies": { + "cookie": "0.7.2", + "cookie-signature": "1.0.7", + "debug": "2.6.9", + "depd": "~2.0.0", + "on-headers": "~1.1.0", + "parseurl": "~1.3.3", + "safe-buffer": "5.2.1", + "uid-safe": "~2.1.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/express-session/node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express-session/node_modules/cookie-signature": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", + "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==" + }, + "node_modules/express-session/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express-session/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, "node_modules/express-validator": { "version": "7.3.1", "resolved": "https://registry.npmjs.org/express-validator/-/express-validator-7.3.1.tgz", @@ -8260,6 +8461,11 @@ "fastest-levenshtein": "^1.0.7" } }, + "node_modules/fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==" + }, "node_modules/fast-uri": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", @@ -8417,6 +8623,44 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, + "node_modules/find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + } + }, + "node_modules/find-cache-dir/node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-cache-dir/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -8581,6 +8825,23 @@ "node": ">= 6" } }, + "node_modules/form-data-encoder": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.9.0.tgz", + "integrity": "sha512-rahaRMkN8P8d/tgK/BLPX+WBVM27NbvdXBxqQujBtkDAIFspaRqN7Od7lfdGQA6KAD+f82fYCLBq1ipvcu8qLw==" + }, + "node_modules/formdata-node": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz", + "integrity": "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==", + "dependencies": { + "node-domexception": "1.0.0", + "web-streams-polyfill": "4.0.0-beta.3" + }, + "engines": { + "node": ">= 12.20" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -9179,6 +9440,11 @@ "node": ">= 14" } }, + "node_modules/http2-client": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/http2-client/-/http2-client-1.3.5.tgz", + "integrity": "sha512-EC2utToWl4RKfs5zd36Mxq7nzHHBuomZboI0yYL6Y0RmBgT7Sgkq4rQ0ezFTYoIsSs7Tm9SJe+o2FcAg6GBhGA==" + }, "node_modules/https-proxy-agent": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", @@ -9248,6 +9514,20 @@ "node": ">= 4" } }, + "node_modules/image-size": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.0.0.tgz", + "integrity": "sha512-JLJ6OwBfO1KcA+TvJT+v8gbE6iWbj24LyDNFgFEN0lzegn6cC6a/p3NIDaepMsJjQjlUWqIC7wJv8lBFxPNjcw==", + "dependencies": { + "queue": "6.0.2" + }, + "bin": { + "image-size": "bin/image-size.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/immer": { "version": "10.2.0", "resolved": "https://registry.npmjs.org/immer/-/immer-10.2.0.tgz", @@ -10454,6 +10734,15 @@ "node": ">=16" } }, + "node_modules/isomorphic-fetch": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-3.0.0.tgz", + "integrity": "sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA==", + "dependencies": { + "node-fetch": "^2.6.1", + "whatwg-fetch": "^3.4.1" + } + }, "node_modules/isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", @@ -10620,6 +10909,14 @@ "underscore": "1.12.1" } }, + "node_modules/jsonpointer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", + "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/jsonschema": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.5.0.tgz", @@ -11076,6 +11373,11 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==" + }, "node_modules/lodash.clonedeep": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", @@ -11447,6 +11749,24 @@ "node": ">= 0.6" } }, + "node_modules/memoizee": { + "version": "0.4.17", + "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.17.tgz", + "integrity": "sha512-DGqD7Hjpi/1or4F/aYAspXKNm5Yili0QDAFAY4QYvpqpgiY6+1jOfqpmByzjxbWd/T9mChbCArXAbDAsTm5oXA==", + "dependencies": { + "d": "^1.0.2", + "es5-ext": "^0.10.64", + "es6-weak-map": "^2.0.3", + "event-emitter": "^0.3.5", + "is-promise": "^2.2.2", + "lru-queue": "^0.1.0", + "next-tick": "^1.1.0", + "timers-ext": "^0.1.7" + }, + "engines": { + "node": ">=0.12" + } + }, "node_modules/merge": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/merge/-/merge-2.1.1.tgz", @@ -11529,6 +11849,17 @@ "node": ">= 0.6" } }, + "node_modules/mimer": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/mimer/-/mimer-2.0.2.tgz", + "integrity": "sha512-izxvjsB7Ur5HrTbPu6VKTrzxSMBFBqyZQc6dWlZNQ4/wAvf886fD4lrjtFd8IQ8/WmZKdxKjUtqFFNaj3hQ52g==", + "bin": { + "mimer": "bin/mimer" + }, + "engines": { + "node": ">= 12" + } + }, "node_modules/mimic-fn": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-3.1.0.tgz", @@ -11620,6 +11951,14 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, + "node_modules/mustache": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", + "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==", + "bin": { + "mustache": "bin/mustache" + } + }, "node_modules/mute-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz", @@ -11642,6 +11981,11 @@ "node": ">= 0.6" } }, + "node_modules/next-tick": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==" + }, "node_modules/nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", @@ -11672,6 +12016,30 @@ "node": ">= 10.13" } }, + "node_modules/node-abort-controller": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.1.1.tgz", + "integrity": "sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==" + }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "deprecated": "Use your platform's native DOMException instead", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "engines": { + "node": ">=10.5.0" + } + }, "node_modules/node-fetch": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", @@ -11691,6 +12059,17 @@ } } }, + "node_modules/node-fetch-h2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/node-fetch-h2/-/node-fetch-h2-2.3.0.tgz", + "integrity": "sha512-ofRW94Ab0T4AOh5Fk8t0h8OBWrmjb0SSB20xh1H8YnPV9EJ+f5AMoYSUQ2zgJ4Iq2HAK0I2l5/Nequ8YzFS3Hg==", + "dependencies": { + "http2-client": "^1.2.5" + }, + "engines": { + "node": "4.x || >=6.0.0" + } + }, "node_modules/node-fetch/node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", @@ -14410,6 +14789,14 @@ "node": ">= 0.8" } }, + "node_modules/on-headers": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", + "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -14464,6 +14851,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/openapi-types": { + "version": "12.1.3", + "resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-12.1.3.tgz", + "integrity": "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==" + }, "node_modules/optimism": { "version": "0.18.1", "resolved": "https://registry.npmjs.org/optimism/-/optimism-0.18.1.tgz", @@ -15087,6 +15479,14 @@ "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" }, + "node_modules/queue": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz", + "integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==", + "dependencies": { + "inherits": "~2.0.3" + } + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -15106,6 +15506,14 @@ } ] }, + "node_modules/random-bytes": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", + "integrity": "sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ==", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -15303,6 +15711,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/reftools": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/reftools/-/reftools-1.1.9.tgz", + "integrity": "sha512-OVede/NQE13xBQ+ob5CKd5KyeJYU2YInb1bmV4nRoOfquZPkAkxuOXicSe1PvqIuZZ4kD13sPKBbR7UFDmli6w==", + "funding": { + "url": "https://github.com/Mermade/oas-kit?sponsor=1" + } + }, "node_modules/regexp.prototype.flags": { "version": "1.5.4", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", @@ -15339,6 +15755,14 @@ } } }, + "node_modules/remove-undefined-objects": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/remove-undefined-objects/-/remove-undefined-objects-2.0.2.tgz", + "integrity": "sha512-b6x4MUtR4YBW1aCoGx3tE4mA2PFjiXSmtSdNmLexQzUdZa4ybnJAItXLKpkcVgCUJIzJtk2DFG402sMSEMlonQ==", + "engines": { + "node": ">=14" + } + }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -16479,6 +16903,32 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/swagger2openapi": { + "version": "7.0.8", + "resolved": "https://registry.npmjs.org/swagger2openapi/-/swagger2openapi-7.0.8.tgz", + "integrity": "sha512-upi/0ZGkYgEcLeGieoz8gT74oWHA0E7JivX7aN9mAf+Tc7BQoRBvnIGHoPDw+f9TXTW4s6kGYCZJtauP6OYp7g==", + "dependencies": { + "call-me-maybe": "^1.0.1", + "node-fetch": "^2.6.1", + "node-fetch-h2": "^2.3.0", + "node-readfiles": "^0.2.0", + "oas-kit-common": "^1.0.8", + "oas-resolver": "^2.5.6", + "oas-schema-walker": "^1.1.5", + "oas-validator": "^5.0.8", + "reftools": "^1.1.9", + "yaml": "^1.10.0", + "yargs": "^17.0.1" + }, + "bin": { + "boast": "boast.js", + "oas-validate": "oas-validate.js", + "swagger2openapi": "swagger2openapi.js" + }, + "funding": { + "url": "https://github.com/Mermade/oas-kit?sponsor=1" + } + }, "node_modules/symbol-observable": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz", @@ -16560,6 +17010,18 @@ "readable-stream": "2 || 3" } }, + "node_modules/timers-ext": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.8.tgz", + "integrity": "sha512-wFH7+SEAcKfJpfLPkrgMPvvwnEtj8W4IurvEyrKsDleXnKLCDw71w8jltvfLa8Rm4qQxxT4jmDBYbJG/z7qoww==", + "dependencies": { + "es5-ext": "^0.10.64", + "next-tick": "^1.1.0" + }, + "engines": { + "node": ">=0.12" + } + }, "node_modules/tiny-warning": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", @@ -16664,6 +17126,11 @@ "node": ">= 14.0.0" } }, + "node_modules/ts-algebra": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/ts-algebra/-/ts-algebra-1.2.2.tgz", + "integrity": "sha512-kloPhf1hq3JbCPOTYoOWDKxebWjNb2o/LKnNfkWhxVVisFFmMJPPdJeGoGmM+iRLyoXAR61e08Pb+vUXINg8aA==" + }, "node_modules/ts-api-utils": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz", @@ -16896,6 +17363,17 @@ "node": ">=14.17" } }, + "node_modules/uid-safe": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz", + "integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==", + "dependencies": { + "random-bytes": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/unbox-primitive": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", @@ -17013,6 +17491,38 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/validate.io-array": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/validate.io-array/-/validate.io-array-1.0.6.tgz", + "integrity": "sha512-DeOy7CnPEziggrOO5CZhVKJw6S3Yi7e9e65R1Nl/RTN1vTQKnzjfvks0/8kQ40FP/dsjRAOd4hxmJ7uLa6vxkg==" + }, + "node_modules/validate.io-function": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/validate.io-function/-/validate.io-function-1.0.2.tgz", + "integrity": "sha512-LlFybRJEriSuBnUhQyG5bwglhh50EpTL2ul23MPIuR1odjO7XaMLFV8vHGwp7AZciFxtYOeiSCT5st+XSPONiQ==" + }, + "node_modules/validate.io-integer": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/validate.io-integer/-/validate.io-integer-1.0.5.tgz", + "integrity": "sha512-22izsYSLojN/P6bppBqhgUDjCkr5RY2jd+N2a3DCAUey8ydvrZ/OkGvFPR7qfOpwR2LC5p4Ngzxz36g5Vgr/hQ==", + "dependencies": { + "validate.io-number": "^1.0.3" + } + }, + "node_modules/validate.io-integer-array": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/validate.io-integer-array/-/validate.io-integer-array-1.0.0.tgz", + "integrity": "sha512-mTrMk/1ytQHtCY0oNO3dztafHYyGU88KL+jRxWuzfOmQb+4qqnWmI+gykvGp8usKZOM0H7keJHEbRaFiYA0VrA==", + "dependencies": { + "validate.io-array": "^1.0.3", + "validate.io-integer": "^1.0.4" + } + }, + "node_modules/validate.io-number": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/validate.io-number/-/validate.io-number-1.0.3.tgz", + "integrity": "sha512-kRAyotcbNaSYoDnXvb4MHg/0a1egJdLwS6oJ38TJY7aw9n93Fl/3blIXdyYvPOp55CNxywooG/3BcrwNrBpcSg==" + }, "node_modules/validator": { "version": "13.15.26", "resolved": "https://registry.npmjs.org/validator/-/validator-13.15.26.tgz", @@ -17056,6 +17566,14 @@ "defaults": "^1.0.3" } }, + "node_modules/web-streams-polyfill": { + "version": "4.0.0-beta.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz", + "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==", + "engines": { + "node": ">= 14" + } + }, "node_modules/webidl-conversions": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", @@ -17087,6 +17605,11 @@ "node": ">=0.10.0" } }, + "node_modules/whatwg-fetch": { + "version": "3.6.20", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz", + "integrity": "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==" + }, "node_modules/whatwg-mimetype": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", diff --git a/api/package.json b/api/package.json index f5bba717b..b518c37ec 100644 --- a/api/package.json +++ b/api/package.json @@ -13,7 +13,6 @@ "lint:fix": "eslint --ext .ts --ignore-pattern './node_modules/' --ignore-pattern './dist/'", "precommit": "npm run prettify && npm run lint:fix" }, - "type": "module", "repository": { "type": "git", "url": "git+https://github.com/contentstack/migration-v2.git" @@ -59,6 +58,7 @@ "devDependencies": { "@types/cors": "^2.8.17", "@types/express": "^4.17.21", + "@types/express-session": "^1.18.2", "@types/fs-extra": "^11.0.4", "@types/fs-readdir-recursive": "^1.1.3", "@types/jsdom": "^21.1.7", diff --git a/api/src/constants/index.ts b/api/src/constants/index.ts index 777712bd6..e44f52010 100644 --- a/api/src/constants/index.ts +++ b/api/src/constants/index.ts @@ -8,6 +8,21 @@ export const DEVURLS: any = { AU: "au-developerhub-api.contentstack.com", GCP_EU: "gcp-eu-developerhub-api.contentstack.com", }; +export const CSAUTHHOST: any = { + NA:"https://app.contentstack.com/apps-api/token", + EU:"https://eu-app.contentstack.com/apps-api/token", + AZURE_NA:"https://azure-na-app.contentstack.com/apps-api/token", + AZURE_EU:"https://azure-eu-app.contentstack.com/apps-api/token", + GCP_NA:"https://gcp-na-app.contentstack.com/apps-api/token", +} + +export const regionalApiHosts = { + NA: 'api.contentstack.io', + EU: 'eu-api.contentstack.com', + AZURE_NA: 'azure-na-api.contentstack.com', + AZURE_EU: 'azure-eu-api.contentstack.com', + GCP_NA: 'gcp-na-api.contentstack.com' +}; export const CMS = { CONTENTFUL: "contentful", SITECORE_V8: "sitecore v8", diff --git a/api/src/controllers/auth.controller.ts b/api/src/controllers/auth.controller.ts index bdcbe1804..e2ecb530f 100644 --- a/api/src/controllers/auth.controller.ts +++ b/api/src/controllers/auth.controller.ts @@ -1,5 +1,6 @@ import { Request, Response } from "express"; import { authService } from "../services/auth.service.js"; +import { HTTP_CODES } from "../constants/index.js"; /** * Handles the login request. @@ -23,7 +24,18 @@ const RequestSms = async (req: Request, res: Response) => { res.status(resp.status).json(resp.data); }; + +/** + * Handles the secure, server-to-server POST request from our Launch proxy. + * This confirms to the proxy that the token was received. + */ +const saveOAuthToken = async (req: Request, res: Response) => { + await authService.saveOAuthToken(req); + res.status(HTTP_CODES.OK).json({ message: "Token received successfully." }); +}; + export const authController = { login, RequestSms, + saveOAuthToken, }; diff --git a/api/src/models/types.ts b/api/src/models/types.ts index 43e7eb049..5cd0c1ed8 100644 --- a/api/src/models/types.ts +++ b/api/src/models/types.ts @@ -45,4 +45,11 @@ export interface Locale { name: string; fallback_locale: string; uid: string; +} + +export interface RefreshTokenResponse { + access_token: string; + refresh_token?: string; + expires_in?: number; + token_type?: string; } \ No newline at end of file diff --git a/api/src/routes/auth.routes.ts b/api/src/routes/auth.routes.ts index 60b1755b9..131c26423 100644 --- a/api/src/routes/auth.routes.ts +++ b/api/src/routes/auth.routes.ts @@ -40,4 +40,15 @@ router.post( asyncRouter(authController.RequestSms) ); +/** + * The new secure endpoint that the Launch proxy will call with a POST request + * to deliver the final access token. This is NOT for browser access. + * @route POST /v2/auth/save-token + */ +router.get( + "/save-token", + asyncRouter(authController.saveOAuthToken) +); + + export default router; diff --git a/api/src/services/auth.service.ts b/api/src/services/auth.service.ts index cf512a621..f21b6d5c8 100644 --- a/api/src/services/auth.service.ts +++ b/api/src/services/auth.service.ts @@ -2,8 +2,8 @@ import { Request } from "express"; import { config } from "../config/index.js"; import { safePromise, getLogMessage } from "../utils/index.js"; import https from "../utils/https.utils.js"; -import { LoginServiceType, AppTokenPayload } from "../models/types.js"; -import { HTTP_CODES, HTTP_TEXTS } from "../constants/index.js"; +import { LoginServiceType, AppTokenPayload, RefreshTokenResponse } from "../models/types.js"; +import { HTTP_CODES, HTTP_TEXTS, CSAUTHHOST, regionalApiHosts } from "../constants/index.js"; import { generateToken } from "../utils/jwt.utils.js"; import { BadRequestError, @@ -12,23 +12,16 @@ import { } from "../utils/custom-errors.utils.js"; import AuthenticationModel from "../models/authentication.js"; import logger from "../utils/logger.js"; -// import * as configHandler from "@contentstack/cli-utilities"; +import path from "path"; +import fs from "fs"; +import axios from "axios"; +// import { createHash, randomBytes } from 'crypto'; /** - * Logs in a user with the provided request data. - * - * @param req - The request object containing user data. - * @returns A promise that resolves to a LoginServiceType object. - * @throws ExceptionFunction if an error occurs during the login process. + * Logs in a user with the provided request data. (No changes needed here) */ const login = async (req: Request): Promise => { const srcFun = "Login"; - /* - handles user authentication by making a request to an API, - performing various checks and validations, - updating a model, and generating a JWT token. - It also handles potential errors and logs appropriate messages. - */ try { const userData = req?.body; @@ -135,19 +128,10 @@ const login = async (req: Request): Promise => { }; /** - * Sends a request for SMS login token. - * @param req - The request object. - * @returns A promise that resolves to a LoginServiceType object. - * @throws {InternalServerError} If an error occurs while sending the request. + * Sends a request for SMS login token. (No changes needed here) */ const requestSms = async (req: Request): Promise => { const srcFun = "requestSms"; - - /* - handles the authentication process by making an HTTP POST request to an API endpoint, - handling any errors that occur, and returning the appropriate response or error data. - It also includes logging functionality to track the execution and potential errors. - */ try { const userData = req?.body; const [err, res] = await safePromise( @@ -187,7 +171,187 @@ const requestSms = async (req: Request): Promise => { } }; +const getAppConfig = () => { + const configPath = path.resolve(process.cwd(), '..', 'app.json'); + if (!fs.existsSync(configPath)) { + throw new InternalServerError("SSO is not configured. Please run the setup script first."); + } + const rawData = fs.readFileSync(configPath, 'utf-8'); + return JSON.parse(rawData); +}; + +/** + * Receives the final code to generate token, fetches user details, + * and saves/updates the user in the database. + */ +const saveOAuthToken = async (req: Request): Promise => { + const { code, region } = req.query; + + if (!code || !region) { + logger.error("Callback failed: Missing 'code' or 'region' in query parameters."); + throw new BadRequestError("Missing 'code' or 'region' in query parameters."); + } + + try { + // Exchange the code for access token + const appConfig = getAppConfig(); + const { client_id, client_secret, redirect_uri } = appConfig.oauthData; + const { code_verifier } = appConfig.pkce; + + const regionStr = Array.isArray(region) ? region[0] : region; + const tokenUrl = CSAUTHHOST[regionStr as keyof typeof CSAUTHHOST]; + const clientId = client_id + const clientSecret = client_secret + const redirectUri = `${redirect_uri}/v2/auth/save-token` + if (!tokenUrl || !clientId || !clientSecret) { + throw new InternalServerError(`Configuration missing for region: ${region}`); + } + + const formData = new URLSearchParams(); + formData.append('grant_type', 'authorization_code'); + formData.append('client_id', clientId); + formData.append('client_secret', clientSecret); + formData.append('redirect_uri', redirectUri); + formData.append('code', code as string); + formData.append('code_verifier', code_verifier); + const tokenResponse = await https({ + method: "POST", + url: tokenUrl, + data: formData, + headers: { 'Content-Type': 'application/x-www-form-urlencoded' } + }); + + delete (req.session as any).code_verifier; + + const { access_token, refresh_token, organization_uid } = tokenResponse.data; + + const apiHost = regionalApiHosts[region as keyof typeof regionalApiHosts]; + const [userErr, userRes] = await safePromise( + https({ + method: "GET", + url: `https://${apiHost}/v3/user`, + headers: { + 'authorization': `Bearer ${access_token}`, + }, + }) + ); + + if (userErr) { + logger.error("Error fetching user details with new token", userErr?.response?.data); + throw new InternalServerError(userErr); + } + + const csUser = userRes.data.user; + + const appTokenPayload = { + region: region as string, + user_id: csUser.uid, + }; + + await AuthenticationModel.read(); + const userIndex = AuthenticationModel.chain.get("users").findIndex({ user_id: csUser.uid }).value(); + + AuthenticationModel.update((data: any) => { + const userRecord = { + ...appTokenPayload, + email: csUser.email, + access_token: access_token, + refresh_token: refresh_token, + organization_uid: organization_uid, + updated_at: new Date().toISOString(), + }; + if (userIndex < 0) { + data.users.push({ ...userRecord, created_at: new Date().toISOString() }); + } else { + data.users[userIndex] = { ...data.users[userIndex], ...userRecord }; + } + }); + + logger.info(`Token and user data for ${csUser.email} (Region: ${region}) saved successfully.`); + + } catch (error) { + logger.error("An error occurred during token exchange and save:", error); + throw new InternalServerError("Failed to process OAuth callback."); + } +}; + +/** + * Generates a new access token using the refresh token. + * If the refresh token is not found, it throws an error. + * It updates the user record in the database with the new access token and refresh token. + * It returns the new access token. + */ +export const refreshOAuthToken = async (userId: string): Promise => { + try { + await AuthenticationModel.read(); + const userRecord = AuthenticationModel.chain.get("users").find({ user_id: userId }).value(); + + if (!userRecord) { + throw new Error(`User record not found for user_id: ${userId}`); + } + + if (!userRecord.refresh_token) { + throw new Error(`No refresh token available for user: ${userId}`); + } + + const appConfigPath = path.join(process.cwd(), "..", 'app.json'); + if (!fs.existsSync(appConfigPath)) { + throw new Error('app.json file not found - OAuth configuration required'); + } + + const appConfig = JSON.parse(fs.readFileSync(appConfigPath, 'utf8')); + const { client_id, client_secret, redirect_uri } = appConfig.oauthData; + + if (!client_id || !client_secret) { + throw new Error('OAuth client_id or client_secret not found in app.json'); + } + + console.info(`Refreshing token for user: ${userRecord.email} in region: ${userRecord.region}`); + + const appUrl = CSAUTHHOST[userRecord.region] || CSAUTHHOST['NA']; + const tokenEndpoint = `${appUrl}`; + + const formData = new URLSearchParams({ + grant_type: 'refresh_token', + client_id: client_id, + client_secret: client_secret, + redirect_uri: redirect_uri, + refresh_token: userRecord.refresh_token + }); + + const response = await axios.post(tokenEndpoint, formData, { + headers: { + 'Content-Type': 'application/x-www-form-urlencoded' + }, + timeout: 15000 + }); + + const { access_token, refresh_token } = response.data; + + AuthenticationModel.update((data: any) => { + const userIndex = data.users.findIndex((user: any) => user.user_id === userId); + if (userIndex >= 0) { + data.users[userIndex] = { + ...data.users[userIndex], + access_token: access_token, + refresh_token: refresh_token || userRecord.refresh_token, + updated_at: new Date().toISOString() + }; + } + }); + + console.info(`Token refreshed successfully for user: ${userRecord.email}`); + return access_token; + + } catch (error: any) { + console.error(`Token refresh failed for user ${userId}:`, error.response?.data || error.message); + throw new Error(`Failed to refresh token: ${error.response?.data?.error_description || error.message}`); + } +}; + export const authService = { login, requestSms, -}; + saveOAuthToken, + refreshOAuthToken, +}; \ No newline at end of file diff --git a/api/sso.utils.js b/api/sso.utils.js new file mode 100644 index 000000000..b32e49105 --- /dev/null +++ b/api/sso.utils.js @@ -0,0 +1,283 @@ +const contentstack = require("@contentstack/marketplace-sdk"); +const readline = require("readline"); +const { execSync } = require("child_process"); +const fs = require("fs"); +const crypto = require("crypto"); +const manifest = require("./manifest.json"); + + +const REGION_CONFIG = { + NA: { + name: "North America", + cma: "https://api.contentstack.io", + cda: "https://cdn.contentstack.io", + app: "https://app.contentstack.com", + developerHub: "https://developerhub-api.contentstack.com", + personalize: "https://personalize-api.contentstack.com", + launch: "https://launch-api.contentstack.com" + }, + EU: { + name: "Europe", + cma: "https://eu-api.contentstack.com", + cda: "https://eu-cdn.contentstack.com", + app: "https://eu-app.contentstack.com", + developerHub: "https://eu-developerhub-api.contentstack.com", + personalize: "https://eu-personalize-api.contentstack.com", + launch: "https://eu-launch-api.contentstack.com" + }, + "AZURE-NA": { + name: "Azure North America", + cma: "https://azure-na-api.contentstack.com", + cda: "https://azure-na-cdn.contentstack.com", + app: "https://azure-na-app.contentstack.com", + developerHub: "https://azure-na-developerhub-api.contentstack.com", + personalize: "https://azure-na-personalize-api.contentstack.com", + launch: "https://azure-na-launch-api.contentstack.com" + }, + "AZURE-EU": { + name: "Azure Europe", + cma: "https://azure-eu-api.contentstack.com", + cda: "https://azure-eu-cdn.contentstack.com", + app: "https://azure-eu-app.contentstack.com", + developerHub: "https://azure-eu-developerhub-api.contentstack.com", + personalize: "https://azure-eu-personalize-api.contentstack.com", + launch: "https://azure-eu-launch-api.contentstack.com" + }, + "GCP-NA": { + name: "GCP North America", + cma: "https://gcp-na-api.contentstack.com", + cda: "https://gcp-na-cdn.contentstack.com", + app: "https://gcp-na-app.contentstack.com", + developerHub: "https://gcp-na-developerhub-api.contentstack.com", + personalize: "https://gcp-na-personalize-api.contentstack.com", + launch: "https://gcp-na-launch-api.contentstack.com" + } +}; + +// Get region from CLI +function getCurrentRegion() { + try { + const regionOutput = execSync("csdx config:get:region", { encoding: "utf8" }).trim(); + console.log("Raw region from CSDX config:", regionOutput); + + const regionMatch = regionOutput.match(/\b(NA|EU|AZURE-NA|AZURE-EU|GCP-NA)\b/); + + if (regionMatch) { + const regionKey = regionMatch[1]; + console.log("Extracted region key:", regionKey); + return regionKey; + } + + console.warn("Could not extract region from:", regionOutput); + return "NA"; + } catch (error) { + console.warn("Could not get region from CSDX:", error.message); + return "NA"; + } +} + +module.exports = async ({ + migration, + stackSDKInstance, + managementAPIClient, +}) => { + const axiosInstance = managementAPIClient.axiosInstance; + + const regionKey = getCurrentRegion(); + const regionConfig = REGION_CONFIG[regionKey]; + + console.log(`\n=== USING REGION: ${regionConfig.name} (${regionKey}) ===`); + console.log(`CMA: ${regionConfig.cma}`); + console.log(`CDA: ${regionConfig.cda}`); + console.log(`App: ${regionConfig.app}`); + console.log("=".repeat(50)); + + try { + const user = await managementAPIClient.getUser(); + console.log(`✓ User: ${user.email} (${user.uid})`); + + if (!user.organizations || user.organizations.length === 0) { + console.log("❌ No organizations found"); + return; + } + + console.log(`\n=== YOUR ORGANIZATIONS ===`); + user.organizations.forEach((org, index) => { + console.log(`${index + 1}. ${org.name} (${org.uid})`); + }); + + const rl = readline.createInterface({ + input: process.stdin, + output: process.stdout, + }); + + const selectedOrg = await new Promise((resolve) => { + rl.question(`\nSelect organization number: `, (answer) => { + rl.close(); + const index = parseInt(answer) - 1; + if (index >= 0 && index < user.organizations.length) { + resolve(user.organizations[index]); + } else { + console.log("❌ Invalid selection"); + resolve(null); + } + }); + }); + + if (!selectedOrg) { + console.log("❌ No organization selected. Exiting..."); + return; + } + + const headers = managementAPIClient.axiosInstance.defaults.headers; + const authtoken = headers.authtoken || headers.authorization; + + console.log(`\n✓ Selected: ${selectedOrg.name} (${selectedOrg.uid})`); + console.log(`🔑 Auth token: ${authtoken ? authtoken.substring(0, 20) + '...' : 'Not found'}`); + + const orgDetails = await managementAPIClient + .organization(selectedOrg.uid) + .fetch(); + + console.log(`✓ Organization details fetched: ${orgDetails.name}`); + + const regionMapping = { + 'NA': 'NA', + 'EU': 'EU', + 'AZURE-NA': 'AZURE_NA', + 'AZURE-EU': 'AZURE_EU', + 'GCP-NA': 'GCP_NA', + 'GCP-EU': 'GCP_EU' + }; + + const sdkRegion = regionMapping[regionKey]; + + let clientConfig = { + authorization: authtoken + }; + + + if (regionKey !== 'NA' && sdkRegion) { + + clientConfig.region = contentstack.Region[sdkRegion]; + console.log(`✓ Setting SDK region to: ${sdkRegion}`); + } + + const client = contentstack.client(clientConfig); + + console.log(`✓ Contentstack client configured for ${regionKey} region`); + + // Find or create app + let existingApp = null; + + try { + console.log("🔍 Searching for existing app..."); + const allApps = await client.marketplace(selectedOrg.uid).findAllApps(); + existingApp = allApps?.items?.find((app) => app?.name === manifest?.name); + + if (!existingApp) { + console.log("📱 Creating new app..."); + existingApp = await client + .marketplace(selectedOrg.uid) + .app() + .create(manifest); + console.log(`✓ App created: ${existingApp.name} (${existingApp.uid})`); + } else { + console.log(`✓ Found existing app: ${existingApp.name} (${existingApp.uid})`); + console.log("🔄 Updating existing app with manifest..."); + + const updatedApp = await client + .marketplace(selectedOrg.uid) + .app(existingApp.uid) + .update(manifest); + + console.log(`✓ App updated: ${updatedApp.name} (${updatedApp.uid})`); + existingApp = updatedApp; + } + } catch (error) { + console.error("❌ Error with app operations:", error.message); + if (error.status === 401) { + console.error(`\n💡 Authentication Error - This usually means:`); + console.error(` • Your auth token is from a different region`); + console.error(` • Please logout and login again in the ${regionKey} region`); + console.error(` • Commands: csdx auth:logout → csdx auth:login`); + } + throw error; + } + + console.log("🔐 Fetching OAuth configuration..."); + const oauthData = await client + .marketplace(selectedOrg.uid) + .app(existingApp?.uid) + .oauth() + .fetch(); + + + console.log("🔒 Generating PKCE credentials..."); + const code_verifier = crypto.randomBytes(32).toString("hex"); + const code_challenge = crypto + .createHash("sha256") + .update(code_verifier) + .digest("base64") + .replace(/\+/g, "-") + .replace(/\//g, "_") + .replace(/=+$/, ""); + + + const appData = { + timestamp: new Date().toISOString(), + region: { + key: regionKey, + name: regionConfig.name, + endpoints: regionConfig + }, + user: { + email: user.email, + uid: user.uid + }, + organization: { + name: selectedOrg.name, + uid: selectedOrg.uid, + }, + app: { + name: existingApp?.name, + uid: existingApp?.uid, + manifest: manifest.name + }, + oauthData: oauthData, + pkce: { + code_verifier: code_verifier, + code_challenge: code_challenge, + }, + }; + + fs.writeFileSync("app.json", JSON.stringify(appData, null, 2)); + console.log("✓ OAuth data logged to app.json"); + + // Generate authorization URL + const authUrl = `${regionConfig.app}/#!/apps/${existingApp?.uid}/authorize?response_type=code&client_id=${oauthData?.client_id}&redirect_uri=${encodeURIComponent(oauthData?.redirect_uri)}&code_challenge=${code_challenge}&code_challenge_method=S256`; + + console.log(`\n🚀 Authorization URL for ${regionConfig.name}:`); + console.log(authUrl); + + + openBrowser(authUrl); + + console.log("\nNote: If the browser doesn't open automatically, please copy and paste the URL above into your browser."); + + } catch (error) { + console.error("❌ Setup failed:"); + console.error("Error:", error.message); + + if (error.errorMessage) { + console.error("Details:", error.errorMessage); + } + + console.error(`\n🔍 Debug Info:`); + console.error(`Region: ${regionKey} (${regionConfig?.name || 'Unknown'})`); + console.error(`Expected CMA: ${regionConfig?.cma || 'Unknown'}`); + console.error(`Management API URL: ${managementAPIClient.axiosInstance.defaults.baseURL}`); + + throw error; + } +}; \ No newline at end of file diff --git a/build.sh b/build.sh new file mode 100755 index 000000000..67d95ce3e --- /dev/null +++ b/build.sh @@ -0,0 +1,94 @@ +#!/bin/bash + +# --- Function to get current region --- +get_current_region() { + local region=$(csdx config:get:region 2>/dev/null) + if [ $? -eq 0 ] && [ -n "$region" ]; then + echo "$region" + return 0 + else + echo "Not set" + return 1 + fi +} + +# --- Prompt for Region --- +echo "" +echo "Please select your region:" +echo "1. NA (North America)" +echo "2. EU (Europe)" +echo "3. AZURE-NA (Azure North America)" +echo "4. AZURE-EU (Azure Europe)" +echo "5. GCP-NA (GCP North America)" +read -p "Enter region number (default: 1): " REGION_CHOICE + +case $REGION_CHOICE in + 2) REGION="EU";; + 3) REGION="AZURE-NA";; + 4) REGION="AZURE-EU";; + 5) REGION="GCP-NA";; + *) REGION="NA";; +esac + +echo "Selected region: $REGION" + +# --- Set the Region in CSDX Config --- +echo "" +echo "Setting the region in CSDX..." +if ! csdx config:set:region "$REGION"; then + echo "Failed to set the region. Please check your CSDX installation." + exit 1 +fi +echo "✓ Region set to $REGION." + +# --- Get and Verify the Region --- +echo "" +echo "Verifying the region configuration..." +CURRENT_REGION=$(csdx config:get:region) +if [ $? -eq 0 ]; then + echo "✓ Current region is set to: $CURRENT_REGION" +else + echo "⚠ Could not retrieve current region configuration" +fi + +# --- OAuth Login (Always redirect after region selection) --- +echo "" +echo "Redirecting to OAuth login..." +echo "This will open your browser for authentication in the selected region ($REGION)." +if ! csdx auth:login --oauth; then + echo "OAuth login failed. Please try again." + exit 1 +fi +echo "✓ OAuth login successful for region: $REGION" + +# Update redirect_uri in manifest.json +JSON_FILE="api/manifest.json" +if [ -f "$JSON_FILE" ]; then + echo "" + read -p "Enter new redirect_uri or press enter to use default value: " NEW_URI + + #default value + if [ -z "$NEW_URI" ]; then + NEW_URI="http://localhost:5001" + fi + + sed -i '' "s|\"redirect_uri\"[[:space:]]*:[[:space:]]*\"[^\"]*\"|\"redirect_uri\": \"$NEW_URI\"|g" "$JSON_FILE" + echo "✓ redirect_uri updated to $NEW_URI in $JSON_FILE" +else + echo "⚠ manifest.json file not found at: $JSON_FILE" +fi + +# Run the Migration Script +echo "" +echo "Running the migration..." +SCRIPT_PATH="api/sso.utils.js" +if [ -f "$SCRIPT_PATH" ]; then + csdx cm:stacks:migration --file-path "$SCRIPT_PATH" +else + echo "Migration script not found at: $SCRIPT_PATH" + echo "Please update the script path in build.sh" + exit 1 +fi + +echo "" +echo "✓ Setup script finished." \ No newline at end of file From 4720794ecdab46f6c555d76405157799411ab859 Mon Sep 17 00:00:00 2001 From: shobhit upadhyay Date: Thu, 4 Sep 2025 15:28:28 +0530 Subject: [PATCH 2/9] refactor: streamline OAuth token handling and update package dependencies - Removed redundant variables for client_id and client_secret in saveOAuthToken function. - Updated logging to use a centralized logger instead of console methods. - Removed unnecessary deletion of code_verifier from the request session. - Updated package.json to remove outdated "api" dependency. --- api/src/services/auth.service.ts | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/api/src/services/auth.service.ts b/api/src/services/auth.service.ts index f21b6d5c8..596ae4e80 100644 --- a/api/src/services/auth.service.ts +++ b/api/src/services/auth.service.ts @@ -200,17 +200,14 @@ const saveOAuthToken = async (req: Request): Promise => { const regionStr = Array.isArray(region) ? region[0] : region; const tokenUrl = CSAUTHHOST[regionStr as keyof typeof CSAUTHHOST]; - const clientId = client_id - const clientSecret = client_secret const redirectUri = `${redirect_uri}/v2/auth/save-token` - if (!tokenUrl || !clientId || !clientSecret) { + if (!tokenUrl || !client_id || !client_secret) { throw new InternalServerError(`Configuration missing for region: ${region}`); } - const formData = new URLSearchParams(); formData.append('grant_type', 'authorization_code'); - formData.append('client_id', clientId); - formData.append('client_secret', clientSecret); + formData.append('client_id', client_id); + formData.append('client_secret', client_secret); formData.append('redirect_uri', redirectUri); formData.append('code', code as string); formData.append('code_verifier', code_verifier); @@ -221,8 +218,6 @@ const saveOAuthToken = async (req: Request): Promise => { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }); - delete (req.session as any).code_verifier; - const { access_token, refresh_token, organization_uid } = tokenResponse.data; const apiHost = regionalApiHosts[region as keyof typeof regionalApiHosts]; @@ -306,7 +301,7 @@ export const refreshOAuthToken = async (userId: string): Promise => { throw new Error('OAuth client_id or client_secret not found in app.json'); } - console.info(`Refreshing token for user: ${userRecord.email} in region: ${userRecord.region}`); + logger.info(`Refreshing token for user: ${userRecord.email} in region: ${userRecord.region}`); const appUrl = CSAUTHHOST[userRecord.region] || CSAUTHHOST['NA']; const tokenEndpoint = `${appUrl}`; @@ -340,11 +335,11 @@ export const refreshOAuthToken = async (userId: string): Promise => { } }); - console.info(`Token refreshed successfully for user: ${userRecord.email}`); + logger.info(`Token refreshed successfully for user: ${userRecord.email}`); return access_token; } catch (error: any) { - console.error(`Token refresh failed for user ${userId}:`, error.response?.data || error.message); + logger.error(`Token refresh failed for user ${userId}:`, error.response?.data || error.message); throw new Error(`Failed to refresh token: ${error.response?.data?.error_description || error.message}`); } }; From 0eab509e9fc72934fbe42f35474c0015e5a85f24 Mon Sep 17 00:00:00 2001 From: shobhit upadhyay Date: Mon, 8 Sep 2025 10:46:12 +0530 Subject: [PATCH 3/9] fix: update redirect_uri in build script and auth service for OAuth flow - Modified build.sh to append '/v2/auth/save-token' to the redirect_uri. - Updated auth.service.ts to use the correct redirect_uri for token requests. - Ensured consistency in region configuration and API endpoint handling. --- api/src/services/auth.service.ts | 4 +- api/sso.utils.js | 160 ++++++++++++++++++------------- build.sh | 4 +- 3 files changed, 99 insertions(+), 69 deletions(-) diff --git a/api/src/services/auth.service.ts b/api/src/services/auth.service.ts index 596ae4e80..90bda5627 100644 --- a/api/src/services/auth.service.ts +++ b/api/src/services/auth.service.ts @@ -200,15 +200,15 @@ const saveOAuthToken = async (req: Request): Promise => { const regionStr = Array.isArray(region) ? region[0] : region; const tokenUrl = CSAUTHHOST[regionStr as keyof typeof CSAUTHHOST]; - const redirectUri = `${redirect_uri}/v2/auth/save-token` if (!tokenUrl || !client_id || !client_secret) { throw new InternalServerError(`Configuration missing for region: ${region}`); } + const formData = new URLSearchParams(); formData.append('grant_type', 'authorization_code'); formData.append('client_id', client_id); formData.append('client_secret', client_secret); - formData.append('redirect_uri', redirectUri); + formData.append('redirect_uri', redirect_uri); formData.append('code', code as string); formData.append('code_verifier', code_verifier); const tokenResponse = await https({ diff --git a/api/sso.utils.js b/api/sso.utils.js index b32e49105..1694958f1 100644 --- a/api/sso.utils.js +++ b/api/sso.utils.js @@ -4,7 +4,7 @@ const { execSync } = require("child_process"); const fs = require("fs"); const crypto = require("crypto"); const manifest = require("./manifest.json"); - +const { default: axios } = require("axios"); const REGION_CONFIG = { NA: { @@ -14,7 +14,7 @@ const REGION_CONFIG = { app: "https://app.contentstack.com", developerHub: "https://developerhub-api.contentstack.com", personalize: "https://personalize-api.contentstack.com", - launch: "https://launch-api.contentstack.com" + launch: "https://launch-api.contentstack.com", }, EU: { name: "Europe", @@ -23,7 +23,7 @@ const REGION_CONFIG = { app: "https://eu-app.contentstack.com", developerHub: "https://eu-developerhub-api.contentstack.com", personalize: "https://eu-personalize-api.contentstack.com", - launch: "https://eu-launch-api.contentstack.com" + launch: "https://eu-launch-api.contentstack.com", }, "AZURE-NA": { name: "Azure North America", @@ -32,7 +32,7 @@ const REGION_CONFIG = { app: "https://azure-na-app.contentstack.com", developerHub: "https://azure-na-developerhub-api.contentstack.com", personalize: "https://azure-na-personalize-api.contentstack.com", - launch: "https://azure-na-launch-api.contentstack.com" + launch: "https://azure-na-launch-api.contentstack.com", }, "AZURE-EU": { name: "Azure Europe", @@ -41,7 +41,7 @@ const REGION_CONFIG = { app: "https://azure-eu-app.contentstack.com", developerHub: "https://azure-eu-developerhub-api.contentstack.com", personalize: "https://azure-eu-personalize-api.contentstack.com", - launch: "https://azure-eu-launch-api.contentstack.com" + launch: "https://azure-eu-launch-api.contentstack.com", }, "GCP-NA": { name: "GCP North America", @@ -50,24 +50,28 @@ const REGION_CONFIG = { app: "https://gcp-na-app.contentstack.com", developerHub: "https://gcp-na-developerhub-api.contentstack.com", personalize: "https://gcp-na-personalize-api.contentstack.com", - launch: "https://gcp-na-launch-api.contentstack.com" - } + launch: "https://gcp-na-launch-api.contentstack.com", + }, }; -// Get region from CLI + function getCurrentRegion() { try { - const regionOutput = execSync("csdx config:get:region", { encoding: "utf8" }).trim(); + const regionOutput = execSync("csdx config:get:region", { + encoding: "utf8", + }).trim(); console.log("Raw region from CSDX config:", regionOutput); - - const regionMatch = regionOutput.match(/\b(NA|EU|AZURE-NA|AZURE-EU|GCP-NA)\b/); - + + const regionMatch = regionOutput.match( + /\b(NA|EU|AZURE-NA|AZURE-EU|GCP-NA)\b/ + ); + if (regionMatch) { const regionKey = regionMatch[1]; console.log("Extracted region key:", regionKey); return regionKey; } - + console.warn("Could not extract region from:", regionOutput); return "NA"; } catch (error) { @@ -83,9 +87,10 @@ module.exports = async ({ }) => { const axiosInstance = managementAPIClient.axiosInstance; + const regionKey = getCurrentRegion(); const regionConfig = REGION_CONFIG[regionKey]; - + console.log(`\n=== USING REGION: ${regionConfig.name} (${regionKey}) ===`); console.log(`CMA: ${regionConfig.cma}`); console.log(`CDA: ${regionConfig.cda}`); @@ -131,50 +136,52 @@ module.exports = async ({ const headers = managementAPIClient.axiosInstance.defaults.headers; const authtoken = headers.authtoken || headers.authorization; - + console.log(`\n✓ Selected: ${selectedOrg.name} (${selectedOrg.uid})`); - console.log(`🔑 Auth token: ${authtoken ? authtoken.substring(0, 20) + '...' : 'Not found'}`); + console.log( + `🔑 Auth token: ${ + authtoken ? authtoken.substring(0, 20) + "..." : "Not found" + }` + ); const orgDetails = await managementAPIClient .organization(selectedOrg.uid) .fetch(); - + console.log(`✓ Organization details fetched: ${orgDetails.name}`); const regionMapping = { - 'NA': 'NA', - 'EU': 'EU', - 'AZURE-NA': 'AZURE_NA', - 'AZURE-EU': 'AZURE_EU', - 'GCP-NA': 'GCP_NA', - 'GCP-EU': 'GCP_EU' + NA: "NA", + EU: "EU", + "AZURE-NA": "AZURE_NA", + "AZURE-EU": "AZURE_EU", + "GCP-NA": "GCP_NA", + "GCP-EU": "GCP_EU", }; - + const sdkRegion = regionMapping[regionKey]; - + let clientConfig = { - authorization: authtoken + authorization: authtoken, }; - - - if (regionKey !== 'NA' && sdkRegion) { + if (regionKey !== "NA" && sdkRegion) { clientConfig.region = contentstack.Region[sdkRegion]; console.log(`✓ Setting SDK region to: ${sdkRegion}`); } - + const client = contentstack.client(clientConfig); - + console.log(`✓ Contentstack client configured for ${regionKey} region`); // Find or create app let existingApp = null; - + try { console.log("🔍 Searching for existing app..."); const allApps = await client.marketplace(selectedOrg.uid).findAllApps(); existingApp = allApps?.items?.find((app) => app?.name === manifest?.name); - + if (!existingApp) { console.log("📱 Creating new app..."); existingApp = await client @@ -183,23 +190,46 @@ module.exports = async ({ .create(manifest); console.log(`✓ App created: ${existingApp.name} (${existingApp.uid})`); } else { - console.log(`✓ Found existing app: ${existingApp.name} (${existingApp.uid})`); + console.log( + `✓ Found existing app: ${existingApp.name} (${existingApp.uid})` + ); console.log("🔄 Updating existing app with manifest..."); - - const updatedApp = await client - .marketplace(selectedOrg.uid) - .app(existingApp.uid) - .update(manifest); - - console.log(`✓ App updated: ${updatedApp.name} (${updatedApp.uid})`); - existingApp = updatedApp; + + // Update the existing app with the current manifest + const oauthUpdatePayload = { + redirect_uri: manifest?.oauth?.redirect_uri, + app_token_config: manifest?.oauth?.app_token_config || { + enabled: false, + scopes: [], + }, + user_token_config: manifest?.oauth?.user_token_config || { + enabled: true, + scopes: manifest?.oauth?.user_token_config?.scopes || [], + allow_pkce: true, + }, + }; + const updatedApp = await axios.put( + `${regionConfig.app}/apps-api/manifests/${existingApp?.uid}/oauth`, + oauthUpdatePayload, + { + headers: { + authorization: authtoken, + "Content-Type": "application/json", + organization_uid: selectedOrg.uid, + }, + } + ); + + console.log(`✓ App updated: ${existingApp.name} (${existingApp.uid})`); } } catch (error) { console.error("❌ Error with app operations:", error.message); if (error.status === 401) { console.error(`\n💡 Authentication Error - This usually means:`); console.error(` • Your auth token is from a different region`); - console.error(` • Please logout and login again in the ${regionKey} region`); + console.error( + ` • Please logout and login again in the ${regionKey} region` + ); console.error(` • Commands: csdx auth:logout → csdx auth:login`); } throw error; @@ -212,7 +242,6 @@ module.exports = async ({ .oauth() .fetch(); - console.log("🔒 Generating PKCE credentials..."); const code_verifier = crypto.randomBytes(32).toString("hex"); const code_challenge = crypto @@ -223,17 +252,26 @@ module.exports = async ({ .replace(/\//g, "_") .replace(/=+$/, ""); + const authUrl = `${regionConfig.app}/#!/apps/${ + existingApp?.uid + }/authorize?response_type=code&client_id=${ + oauthData?.client_id + }&redirect_uri=${encodeURIComponent( + oauthData?.redirect_uri + )}&code_challenge=${code_challenge}&code_challenge_method=S256`; + console.log(`\n🚀 Authorization URL for ${regionConfig.name}:`); + console.log(authUrl); const appData = { timestamp: new Date().toISOString(), region: { key: regionKey, name: regionConfig.name, - endpoints: regionConfig + endpoints: regionConfig, }, user: { email: user.email, - uid: user.uid + uid: user.uid, }, organization: { name: selectedOrg.name, @@ -242,42 +280,34 @@ module.exports = async ({ app: { name: existingApp?.name, uid: existingApp?.uid, - manifest: manifest.name + manifest: manifest.name, }, oauthData: oauthData, pkce: { code_verifier: code_verifier, code_challenge: code_challenge, }, + authUrl: authUrl, }; fs.writeFileSync("app.json", JSON.stringify(appData, null, 2)); - console.log("✓ OAuth data logged to app.json"); - - // Generate authorization URL - const authUrl = `${regionConfig.app}/#!/apps/${existingApp?.uid}/authorize?response_type=code&client_id=${oauthData?.client_id}&redirect_uri=${encodeURIComponent(oauthData?.redirect_uri)}&code_challenge=${code_challenge}&code_challenge_method=S256`; - - console.log(`\n🚀 Authorization URL for ${regionConfig.name}:`); - console.log(authUrl); - - - openBrowser(authUrl); - - console.log("\nNote: If the browser doesn't open automatically, please copy and paste the URL above into your browser."); + console.log("✓ OAuth data & Auth URL logged to app.json"); } catch (error) { console.error("❌ Setup failed:"); console.error("Error:", error.message); - + if (error.errorMessage) { console.error("Details:", error.errorMessage); } - + console.error(`\n🔍 Debug Info:`); - console.error(`Region: ${regionKey} (${regionConfig?.name || 'Unknown'})`); - console.error(`Expected CMA: ${regionConfig?.cma || 'Unknown'}`); - console.error(`Management API URL: ${managementAPIClient.axiosInstance.defaults.baseURL}`); - + console.error(`Region: ${regionKey} (${regionConfig?.name || "Unknown"})`); + console.error(`Expected CMA: ${regionConfig?.cma || "Unknown"}`); + console.error( + `Management API URL: ${managementAPIClient.axiosInstance.defaults.baseURL}` + ); + throw error; } }; \ No newline at end of file diff --git a/build.sh b/build.sh index 67d95ce3e..4c2639826 100755 --- a/build.sh +++ b/build.sh @@ -72,8 +72,8 @@ if [ -f "$JSON_FILE" ]; then NEW_URI="http://localhost:5001" fi - sed -i '' "s|\"redirect_uri\"[[:space:]]*:[[:space:]]*\"[^\"]*\"|\"redirect_uri\": \"$NEW_URI\"|g" "$JSON_FILE" - echo "✓ redirect_uri updated to $NEW_URI in $JSON_FILE" + sed -i '' "s|\"redirect_uri\"[[:space:]]*:[[:space:]]*\"[^\"]*\"|\"redirect_uri\": \"${NEW_URI}/v2/auth/save-token\"|g" "$JSON_FILE" + echo "✓ redirect_uri updated to ${NEW_URI}/v2/auth/save-token in $JSON_FILE" else echo "⚠ manifest.json file not found at: $JSON_FILE" fi From efc49505277fa8141f726e94fc7b884d591a43ff Mon Sep 17 00:00:00 2001 From: shobhit upadhyay Date: Mon, 29 Sep 2025 14:27:03 +0530 Subject: [PATCH 4/9] refactor: enhance SSO functionality and update authentication flow - Added new endpoints for retrieving app configuration and checking SSO authentication status. - Updated authentication service to handle SSO tokens and access tokens more effectively. - Enhanced error handling for SSO-related operations. - Updated UI components to support SSO login and added corresponding styles. - Refactored API service calls to accommodate new SSO logic and improved token management. --- api/package-lock.json | 429 +--------------------- api/src/controllers/auth.controller.ts | 88 +++++ api/src/models/authentication.ts | 1 + api/src/models/types.ts | 1 + api/src/routes/auth.routes.ts | 14 + api/src/services/auth.service.ts | 93 ++++- api/src/services/contentMapper.service.ts | 25 +- api/src/services/globalField.service.ts | 28 +- api/src/services/marketplace.service.ts | 41 ++- api/src/services/migration.service.ts | 41 ++- api/src/services/org.service.ts | 134 ++++--- api/src/services/projects.service.ts | 72 ++-- api/src/services/runCli.service.ts | 20 +- api/src/services/taxonomy.service.ts | 31 +- api/src/services/user.service.ts | 17 +- api/src/utils/auth.utils.ts | 18 + api/src/utils/config-handler.util.ts | 26 ++ ui/src/pages/Login/index.scss | 46 +++ ui/src/pages/Login/index.tsx | 187 +++++++++- ui/src/services/api/login.service.ts | 26 +- upload-api/src/config/index.ts | 2 +- 21 files changed, 755 insertions(+), 585 deletions(-) create mode 100644 api/src/utils/config-handler.util.ts diff --git a/api/package-lock.json b/api/package-lock.json index 667d2195c..7251795ae 100644 --- a/api/package-lock.json +++ b/api/package-lock.json @@ -3560,11 +3560,6 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/@exodus/schemasafe": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@exodus/schemasafe/-/schemasafe-1.3.0.tgz", - "integrity": "sha512-5Aap/GaRupgNx/feGBwLLTVv8OQFfv3pq2lPRzPg9R+IOBnDgghTGW7l7EuVXOvg5cc/xSAlRW8rBrjIC3Nvqw==" - }, "node_modules/@fast-csv/format": { "version": "4.3.5", "resolved": "https://registry.npmjs.org/@fast-csv/format/-/format-4.3.5.tgz", @@ -3660,14 +3655,6 @@ "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@humanwhocodes/momoa": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@humanwhocodes/momoa/-/momoa-2.0.4.tgz", - "integrity": "sha512-RE815I4arJFtt+FVeU1Tgp9/Xvecacji8w/V6XtXsWWH/wz/eNkNbhb+ny/+PlVZjV0rxQpRSQKNKE3lcktHEA==", - "engines": { - "node": ">=10.10.0" - } - }, "node_modules/@humanwhocodes/object-schema": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", @@ -4870,7 +4857,8 @@ "node_modules/@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==" + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true }, "node_modules/@types/json5": { "version": "0.0.29", @@ -5367,19 +5355,6 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/ajv-draft-04": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz", - "integrity": "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==", - "peerDependencies": { - "ajv": "^8.5.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, "node_modules/ajv-formats": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", @@ -6035,11 +6010,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/call-me-maybe": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.2.tgz", - "integrity": "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==" - }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -6068,11 +6038,6 @@ "cdl": "bin/cdl.js" } }, - "node_modules/caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==" - }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -6379,40 +6344,11 @@ "node": ">= 0.8" } }, - "node_modules/commander": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", - "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", - "engines": { - "node": ">=14" - } - }, "node_modules/commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==" }, - "node_modules/compute-gcd": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/compute-gcd/-/compute-gcd-1.2.1.tgz", - "integrity": "sha512-TwMbxBNz0l71+8Sc4czv13h4kEqnchV9igQZBi6QUaz09dnz13juGnnaWWJTRsP3brxOoxeB4SA2WELLw1hCtg==", - "dependencies": { - "validate.io-array": "^1.0.3", - "validate.io-function": "^1.0.2", - "validate.io-integer-array": "^1.0.0" - } - }, - "node_modules/compute-lcm": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/compute-lcm/-/compute-lcm-1.1.2.tgz", - "integrity": "sha512-OFNPdQAXnQhDSKioX8/XYT6sdUlXwpeMjfd6ApxMJfyZ4GxmLR1xvMERctlYhlHwIiz6CSpBc2+qYKjHGZw4TQ==", - "dependencies": { - "compute-gcd": "^1.2.1", - "validate.io-array": "^1.0.3", - "validate.io-function": "^1.0.2", - "validate.io-integer-array": "^1.0.0" - } - }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -6703,18 +6639,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/datauri": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/datauri/-/datauri-4.1.0.tgz", - "integrity": "sha512-y17kh32+I82G+ED9MNWFkZiP/Cq/vO1hN9+tSZsT9C9qn3NrvcBnh7crSepg0AQPge1hXx2Ca44s1FRdv0gFWA==", - "dependencies": { - "image-size": "1.0.0", - "mimer": "^2.0.2" - }, - "engines": { - "node": ">= 10" - } - }, "node_modules/date-fns": { "version": "1.30.1", "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.30.1.tgz", @@ -7215,59 +7139,11 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/es5-ext": { - "version": "0.10.64", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz", - "integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==", - "hasInstallScript": true, - "dependencies": { - "es6-iterator": "^2.0.3", - "es6-symbol": "^3.1.3", - "esniff": "^2.0.1", - "next-tick": "^1.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/es6-iterator": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", - "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", - "dependencies": { - "d": "1", - "es5-ext": "^0.10.35", - "es6-symbol": "^3.1.1" - } - }, "node_modules/es6-promise": { "version": "4.2.8", "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" }, - "node_modules/es6-symbol": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.4.tgz", - "integrity": "sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==", - "dependencies": { - "d": "^1.0.2", - "ext": "^1.7.0" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/es6-weak-map": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", - "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", - "dependencies": { - "d": "1", - "es5-ext": "^0.10.46", - "es6-iterator": "^2.0.3", - "es6-symbol": "^3.1.1" - } - }, "node_modules/esbuild": { "version": "0.27.2", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz", @@ -7961,20 +7837,6 @@ "node": "*" } }, - "node_modules/esniff": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz", - "integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==", - "dependencies": { - "d": "^1.0.1", - "es5-ext": "^0.10.62", - "event-emitter": "^0.3.5", - "type": "^2.7.2" - }, - "engines": { - "node": ">=0.10" - } - }, "node_modules/espree": { "version": "9.6.1", "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", @@ -8461,11 +8323,6 @@ "fastest-levenshtein": "^1.0.7" } }, - "node_modules/fast-safe-stringify": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", - "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==" - }, "node_modules/fast-uri": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", @@ -8623,44 +8480,6 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, - "node_modules/find-cache-dir": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", - "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", - "dependencies": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/avajs/find-cache-dir?sponsor=1" - } - }, - "node_modules/find-cache-dir/node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/find-cache-dir/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -8825,23 +8644,6 @@ "node": ">= 6" } }, - "node_modules/form-data-encoder": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.9.0.tgz", - "integrity": "sha512-rahaRMkN8P8d/tgK/BLPX+WBVM27NbvdXBxqQujBtkDAIFspaRqN7Od7lfdGQA6KAD+f82fYCLBq1ipvcu8qLw==" - }, - "node_modules/formdata-node": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz", - "integrity": "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==", - "dependencies": { - "node-domexception": "1.0.0", - "web-streams-polyfill": "4.0.0-beta.3" - }, - "engines": { - "node": ">= 12.20" - } - }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -9440,11 +9242,6 @@ "node": ">= 14" } }, - "node_modules/http2-client": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/http2-client/-/http2-client-1.3.5.tgz", - "integrity": "sha512-EC2utToWl4RKfs5zd36Mxq7nzHHBuomZboI0yYL6Y0RmBgT7Sgkq4rQ0ezFTYoIsSs7Tm9SJe+o2FcAg6GBhGA==" - }, "node_modules/https-proxy-agent": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", @@ -9514,20 +9311,6 @@ "node": ">= 4" } }, - "node_modules/image-size": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.0.0.tgz", - "integrity": "sha512-JLJ6OwBfO1KcA+TvJT+v8gbE6iWbj24LyDNFgFEN0lzegn6cC6a/p3NIDaepMsJjQjlUWqIC7wJv8lBFxPNjcw==", - "dependencies": { - "queue": "6.0.2" - }, - "bin": { - "image-size": "bin/image-size.js" - }, - "engines": { - "node": ">=12.0.0" - } - }, "node_modules/immer": { "version": "10.2.0", "resolved": "https://registry.npmjs.org/immer/-/immer-10.2.0.tgz", @@ -10734,15 +10517,6 @@ "node": ">=16" } }, - "node_modules/isomorphic-fetch": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-3.0.0.tgz", - "integrity": "sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA==", - "dependencies": { - "node-fetch": "^2.6.1", - "whatwg-fetch": "^3.4.1" - } - }, "node_modules/isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", @@ -10909,14 +10683,6 @@ "underscore": "1.12.1" } }, - "node_modules/jsonpointer": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", - "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/jsonschema": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.5.0.tgz", @@ -11373,11 +11139,6 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, - "node_modules/lodash.camelcase": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", - "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==" - }, "node_modules/lodash.clonedeep": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", @@ -11749,24 +11510,6 @@ "node": ">= 0.6" } }, - "node_modules/memoizee": { - "version": "0.4.17", - "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.17.tgz", - "integrity": "sha512-DGqD7Hjpi/1or4F/aYAspXKNm5Yili0QDAFAY4QYvpqpgiY6+1jOfqpmByzjxbWd/T9mChbCArXAbDAsTm5oXA==", - "dependencies": { - "d": "^1.0.2", - "es5-ext": "^0.10.64", - "es6-weak-map": "^2.0.3", - "event-emitter": "^0.3.5", - "is-promise": "^2.2.2", - "lru-queue": "^0.1.0", - "next-tick": "^1.1.0", - "timers-ext": "^0.1.7" - }, - "engines": { - "node": ">=0.12" - } - }, "node_modules/merge": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/merge/-/merge-2.1.1.tgz", @@ -11849,17 +11592,6 @@ "node": ">= 0.6" } }, - "node_modules/mimer": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/mimer/-/mimer-2.0.2.tgz", - "integrity": "sha512-izxvjsB7Ur5HrTbPu6VKTrzxSMBFBqyZQc6dWlZNQ4/wAvf886fD4lrjtFd8IQ8/WmZKdxKjUtqFFNaj3hQ52g==", - "bin": { - "mimer": "bin/mimer" - }, - "engines": { - "node": ">= 12" - } - }, "node_modules/mimic-fn": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-3.1.0.tgz", @@ -11981,11 +11713,6 @@ "node": ">= 0.6" } }, - "node_modules/next-tick": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", - "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==" - }, "node_modules/nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", @@ -12016,30 +11743,6 @@ "node": ">= 10.13" } }, - "node_modules/node-abort-controller": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.1.1.tgz", - "integrity": "sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==" - }, - "node_modules/node-domexception": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", - "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", - "deprecated": "Use your platform's native DOMException instead", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "github", - "url": "https://paypal.me/jimmywarting" - } - ], - "engines": { - "node": ">=10.5.0" - } - }, "node_modules/node-fetch": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", @@ -12059,17 +11762,6 @@ } } }, - "node_modules/node-fetch-h2": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/node-fetch-h2/-/node-fetch-h2-2.3.0.tgz", - "integrity": "sha512-ofRW94Ab0T4AOh5Fk8t0h8OBWrmjb0SSB20xh1H8YnPV9EJ+f5AMoYSUQ2zgJ4Iq2HAK0I2l5/Nequ8YzFS3Hg==", - "dependencies": { - "http2-client": "^1.2.5" - }, - "engines": { - "node": "4.x || >=6.0.0" - } - }, "node_modules/node-fetch/node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", @@ -14851,11 +14543,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/openapi-types": { - "version": "12.1.3", - "resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-12.1.3.tgz", - "integrity": "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==" - }, "node_modules/optimism": { "version": "0.18.1", "resolved": "https://registry.npmjs.org/optimism/-/optimism-0.18.1.tgz", @@ -15479,14 +15166,6 @@ "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" }, - "node_modules/queue": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz", - "integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==", - "dependencies": { - "inherits": "~2.0.3" - } - }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -15711,14 +15390,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/reftools": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/reftools/-/reftools-1.1.9.tgz", - "integrity": "sha512-OVede/NQE13xBQ+ob5CKd5KyeJYU2YInb1bmV4nRoOfquZPkAkxuOXicSe1PvqIuZZ4kD13sPKBbR7UFDmli6w==", - "funding": { - "url": "https://github.com/Mermade/oas-kit?sponsor=1" - } - }, "node_modules/regexp.prototype.flags": { "version": "1.5.4", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", @@ -15755,14 +15426,6 @@ } } }, - "node_modules/remove-undefined-objects": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/remove-undefined-objects/-/remove-undefined-objects-2.0.2.tgz", - "integrity": "sha512-b6x4MUtR4YBW1aCoGx3tE4mA2PFjiXSmtSdNmLexQzUdZa4ybnJAItXLKpkcVgCUJIzJtk2DFG402sMSEMlonQ==", - "engines": { - "node": ">=14" - } - }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -16903,32 +16566,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/swagger2openapi": { - "version": "7.0.8", - "resolved": "https://registry.npmjs.org/swagger2openapi/-/swagger2openapi-7.0.8.tgz", - "integrity": "sha512-upi/0ZGkYgEcLeGieoz8gT74oWHA0E7JivX7aN9mAf+Tc7BQoRBvnIGHoPDw+f9TXTW4s6kGYCZJtauP6OYp7g==", - "dependencies": { - "call-me-maybe": "^1.0.1", - "node-fetch": "^2.6.1", - "node-fetch-h2": "^2.3.0", - "node-readfiles": "^0.2.0", - "oas-kit-common": "^1.0.8", - "oas-resolver": "^2.5.6", - "oas-schema-walker": "^1.1.5", - "oas-validator": "^5.0.8", - "reftools": "^1.1.9", - "yaml": "^1.10.0", - "yargs": "^17.0.1" - }, - "bin": { - "boast": "boast.js", - "oas-validate": "oas-validate.js", - "swagger2openapi": "swagger2openapi.js" - }, - "funding": { - "url": "https://github.com/Mermade/oas-kit?sponsor=1" - } - }, "node_modules/symbol-observable": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz", @@ -17010,18 +16647,6 @@ "readable-stream": "2 || 3" } }, - "node_modules/timers-ext": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.8.tgz", - "integrity": "sha512-wFH7+SEAcKfJpfLPkrgMPvvwnEtj8W4IurvEyrKsDleXnKLCDw71w8jltvfLa8Rm4qQxxT4jmDBYbJG/z7qoww==", - "dependencies": { - "es5-ext": "^0.10.64", - "next-tick": "^1.1.0" - }, - "engines": { - "node": ">=0.12" - } - }, "node_modules/tiny-warning": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", @@ -17126,11 +16751,6 @@ "node": ">= 14.0.0" } }, - "node_modules/ts-algebra": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/ts-algebra/-/ts-algebra-1.2.2.tgz", - "integrity": "sha512-kloPhf1hq3JbCPOTYoOWDKxebWjNb2o/LKnNfkWhxVVisFFmMJPPdJeGoGmM+iRLyoXAR61e08Pb+vUXINg8aA==" - }, "node_modules/ts-api-utils": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz", @@ -17491,38 +17111,6 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/validate.io-array": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/validate.io-array/-/validate.io-array-1.0.6.tgz", - "integrity": "sha512-DeOy7CnPEziggrOO5CZhVKJw6S3Yi7e9e65R1Nl/RTN1vTQKnzjfvks0/8kQ40FP/dsjRAOd4hxmJ7uLa6vxkg==" - }, - "node_modules/validate.io-function": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/validate.io-function/-/validate.io-function-1.0.2.tgz", - "integrity": "sha512-LlFybRJEriSuBnUhQyG5bwglhh50EpTL2ul23MPIuR1odjO7XaMLFV8vHGwp7AZciFxtYOeiSCT5st+XSPONiQ==" - }, - "node_modules/validate.io-integer": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/validate.io-integer/-/validate.io-integer-1.0.5.tgz", - "integrity": "sha512-22izsYSLojN/P6bppBqhgUDjCkr5RY2jd+N2a3DCAUey8ydvrZ/OkGvFPR7qfOpwR2LC5p4Ngzxz36g5Vgr/hQ==", - "dependencies": { - "validate.io-number": "^1.0.3" - } - }, - "node_modules/validate.io-integer-array": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/validate.io-integer-array/-/validate.io-integer-array-1.0.0.tgz", - "integrity": "sha512-mTrMk/1ytQHtCY0oNO3dztafHYyGU88KL+jRxWuzfOmQb+4qqnWmI+gykvGp8usKZOM0H7keJHEbRaFiYA0VrA==", - "dependencies": { - "validate.io-array": "^1.0.3", - "validate.io-integer": "^1.0.4" - } - }, - "node_modules/validate.io-number": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/validate.io-number/-/validate.io-number-1.0.3.tgz", - "integrity": "sha512-kRAyotcbNaSYoDnXvb4MHg/0a1egJdLwS6oJ38TJY7aw9n93Fl/3blIXdyYvPOp55CNxywooG/3BcrwNrBpcSg==" - }, "node_modules/validator": { "version": "13.15.26", "resolved": "https://registry.npmjs.org/validator/-/validator-13.15.26.tgz", @@ -17566,14 +17154,6 @@ "defaults": "^1.0.3" } }, - "node_modules/web-streams-polyfill": { - "version": "4.0.0-beta.3", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz", - "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==", - "engines": { - "node": ">= 14" - } - }, "node_modules/webidl-conversions": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", @@ -17605,11 +17185,6 @@ "node": ">=0.10.0" } }, - "node_modules/whatwg-fetch": { - "version": "3.6.20", - "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz", - "integrity": "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==" - }, "node_modules/whatwg-mimetype": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", diff --git a/api/src/controllers/auth.controller.ts b/api/src/controllers/auth.controller.ts index e2ecb530f..fa7fcbdba 100644 --- a/api/src/controllers/auth.controller.ts +++ b/api/src/controllers/auth.controller.ts @@ -34,8 +34,96 @@ const saveOAuthToken = async (req: Request, res: Response) => { res.status(HTTP_CODES.OK).json({ message: "Token received successfully." }); }; + +/** + * Handles the request for getting the app configuration. + * + * @param req - The request object. + * @param res - The response object. + */ +export const getAppConfigHandler = async (req: Request, res: Response): Promise => { + try { + const appConfig = await authService.getAppData(); + res.status(200).json(appConfig); + + } catch (error: any) { + console.error('Error in getAppConfig controller:', error); + + if (error?.message?.includes('app.json file not found')) { + res.status(404).json({ + error: 'SSO configuration not found', + message: 'app.json file does not exist' + }); + return; + } + + if (error?.message?.includes('Invalid JSON format')) { + res.status(400).json({ + error: 'Invalid SSO configuration', + message: 'app.json contains invalid JSON' + }); + return; + } + + res.status(500).json({ + error: 'Server error', + message: 'Unable to read SSO configuration' + }); + } +}; + +/** + * Handles the request for checking the SSO authentication status. + * + * @param req - The request object. + * @param res - The response object. + */ +export const getSSOAuthStatus = async (req: Request, res: Response): Promise => { + try { + const { userId } = req.params; + + if (!userId) { + res.status(400).json({ + error: 'Missing user ID', + message: 'User ID parameter is required' + }); + return; + } + + const authStatus = await authService.checkSSOAuthStatus(userId); + + res.status(200).json(authStatus); + + } catch (error: any) { + console.error('Error in getSSOAuthStatus controller:', error); + + if (error?.message?.includes('User not found in authentication records')) { + res.status(404).json({ + error: 'User not found', + message: 'User not found in authentication records' + }); + return; + } + + if (error?.message?.includes('SSO authentication not completed')) { + res.status(202).json({ + authenticated: false, + message: 'SSO authentication not completed' + }); + return; + } + + res.status(500).json({ + error: 'Server error', + message: 'Unable to check SSO authentication status' + }); + } +}; + export const authController = { login, RequestSms, saveOAuthToken, + getAppConfigHandler, + getSSOAuthStatus }; diff --git a/api/src/models/authentication.ts b/api/src/models/authentication.ts index fcbefe733..48dc209f2 100644 --- a/api/src/models/authentication.ts +++ b/api/src/models/authentication.ts @@ -13,6 +13,7 @@ interface AuthenticationDocument { authtoken: string; created_at: string; updated_at: string; + access_token: string; }[]; } diff --git a/api/src/models/types.ts b/api/src/models/types.ts index 5cd0c1ed8..a8409efcf 100644 --- a/api/src/models/types.ts +++ b/api/src/models/types.ts @@ -19,6 +19,7 @@ export interface User { export interface AppTokenPayload { region: string; user_id: string; + is_sso: boolean; } /** diff --git a/api/src/routes/auth.routes.ts b/api/src/routes/auth.routes.ts index 131c26423..cc2f1077a 100644 --- a/api/src/routes/auth.routes.ts +++ b/api/src/routes/auth.routes.ts @@ -50,5 +50,19 @@ router.get( asyncRouter(authController.saveOAuthToken) ); +/** + * @route GET /api/app-config + * @desc Get app configuration from app.json + * @access Public + */ +router.get('/app-config', authController.getAppConfigHandler); + +/** + * @route GET /v2/auth/sso-status/:userId + * @desc Check SSO authentication status for a user + * @param userId - The user ID to check authentication status for + * @access Public + */ +router.get('/sso-status/:userId', authController.getSSOAuthStatus); export default router; diff --git a/api/src/services/auth.service.ts b/api/src/services/auth.service.ts index 90bda5627..6c087c01a 100644 --- a/api/src/services/auth.service.ts +++ b/api/src/services/auth.service.ts @@ -83,6 +83,7 @@ const login = async (req: Request): Promise => { const appTokenPayload: AppTokenPayload = { region: userData?.region, user_id: res?.data?.user.uid, + is_sso: false, }; // Saving auth info in the DB @@ -184,7 +185,7 @@ const getAppConfig = () => { * Receives the final code to generate token, fetches user details, * and saves/updates the user in the database. */ -const saveOAuthToken = async (req: Request): Promise => { +const saveOAuthToken = async (req: Request): Promise => { const { code, region } = req.query; if (!code || !region) { @@ -241,8 +242,10 @@ const saveOAuthToken = async (req: Request): Promise => { const appTokenPayload = { region: region as string, user_id: csUser.uid, + is_sso: true, }; + const appToken = generateToken(appTokenPayload); await AuthenticationModel.read(); const userIndex = AuthenticationModel.chain.get("users").findIndex({ user_id: csUser.uid }).value(); @@ -263,6 +266,13 @@ const saveOAuthToken = async (req: Request): Promise => { }); logger.info(`Token and user data for ${csUser.email} (Region: ${region}) saved successfully.`); + return { + data: { + message: HTTP_TEXTS.SUCCESS_LOGIN, + app_token: appToken, + }, + status: HTTP_CODES.OK, + } } catch (error) { logger.error("An error occurred during token exchange and save:", error); @@ -344,9 +354,90 @@ export const refreshOAuthToken = async (userId: string): Promise => { } }; +/** + * Check app.json file for SSO configuration. + * @returns The app configuration + */ +export const getAppData = async () => { + try { + const appConfigPath = path.join(process.cwd(), '..','app.json'); + + if (!fs.existsSync(appConfigPath)) { + throw new Error('app.json file not found - SSO configuration required'); + } + + const appConfigData = fs.readFileSync(appConfigPath, 'utf8'); + const appConfig: any = JSON.parse(appConfigData); + + return appConfig; + + } catch (error: any) { + if (error?.message?.includes('app.json file not found')) { + throw error; + } + if (error instanceof SyntaxError) { + throw new Error('Invalid JSON format in app.json file'); + } + throw new Error(`Failed to read app configuration: ${error?.message}`); + } +} + +/** + * Checks the status of the SSO authentication. + * @param userId - The user ID + * @returns The authentication status + */ +export const checkSSOAuthStatus = async (userId: string) => { + try { + await AuthenticationModel.read(); + const userRecord = AuthenticationModel.chain.get("users").find({ user_id: userId }).value(); + + if (!userRecord || !userRecord.access_token) { + throw new Error('SSO authentication not completed'); + } + + // Only consider tokens created in the last 10 minutes as "fresh" + const tokenAge = new Date()?.getTime() - new Date(userRecord.updated_at)?.getTime(); + const maxTokenAge = 10 * 60 * 1000; // 10 minutes in milliseconds + + if (tokenAge > maxTokenAge) { + throw new Error('SSO authentication not completed'); + } + + // Token is fresh, proceed with authentication + const appTokenPayload = { + region: userRecord.region, + user_id: userRecord.user_id, + is_sso: true, + }; + + const appToken = generateToken(appTokenPayload); + + return { + authenticated: true, + message: 'SSO authentication successful', + app_token: appToken, + user: { + email: userRecord.email, + uid: userRecord.user_id, + region: userRecord.region, + organization_uid: userRecord.organization_uid + } + }; + + } catch (error: any) { + if (error.message.includes('SSO authentication not completed')) { + throw error; + } + throw new Error(`Failed to check SSO authentication status: ${error.message}`); + } +}; + export const authService = { login, requestSms, saveOAuthToken, refreshOAuthToken, + getAppData, + checkSSOAuthStatus }; \ No newline at end of file diff --git a/api/src/services/contentMapper.service.ts b/api/src/services/contentMapper.service.ts index 9e81fddc8..89d2d9c00 100644 --- a/api/src/services/contentMapper.service.ts +++ b/api/src/services/contentMapper.service.ts @@ -15,7 +15,7 @@ import { import logger from "../utils/logger.js"; import { config } from "../config/index.js"; import https from "../utils/https.utils.js"; -import getAuthtoken from "../utils/auth.utils.js"; +import getAuthtoken, { getAccessToken } from "../utils/auth.utils.js"; import getProjectUtil from "../utils/get-project.utils.js"; import fetchAllPaginatedData from "../utils/pagination.utils.js"; import ProjectModelLowdb from "../models/project-lowdb.js"; @@ -367,26 +367,29 @@ const getExistingContentTypes = async (req: Request) => { const { token_payload } = req.body; - const authtoken = await getAuthtoken( - token_payload?.region, - token_payload?.user_id - ); await ProjectModelLowdb.read(); const project = ProjectModelLowdb.chain .get("projects") .find({ id: projectId }) .value(); - const stackId = project?.destination_stack_id; const baseUrl = `${config.CS_API[ token_payload?.region as keyof typeof config.CS_API ]!}/content_types`; - - const headers = { - api_key: stackId, - authtoken, - }; + let headers: any = { + api_key: projectId?.destination_stack_id, + } + if(token_payload?.is_sso) { + const accessToken = await getAccessToken(token_payload?.region, token_payload?.user_id); + headers.authorization = `Bearer ${accessToken}`; + } else if (token_payload?.is_sso === false) { + const authtoken = await getAuthtoken( + token_payload?.region, + token_payload?.user_id + ); + headers.authtoken = authtoken; + } try { // Step 1: Fetch the updated list of all content types diff --git a/api/src/services/globalField.service.ts b/api/src/services/globalField.service.ts index 950a5b8de..0a28d79a0 100644 --- a/api/src/services/globalField.service.ts +++ b/api/src/services/globalField.service.ts @@ -1,11 +1,11 @@ import { getLogMessage, safePromise } from "../utils/index.js"; -import getAuthtoken from "../utils/auth.utils.js"; import { config } from "../config/index.js"; import https from "../utils/https.utils.js"; import fs from 'fs'; import { HTTP_TEXTS, MIGRATION_DATA_CONFIG} from "../constants/index.js"; import path from "path"; import logger from "../utils/logger.js"; +import AuthenticationModel from "../models/authentication.js"; const { GLOBAL_FIELDS_FILE_NAME, @@ -25,7 +25,26 @@ const createGlobalField = async ({ current_test_stack_id?: string; }) => { const srcFun = "createGlobalField"; - const authtoken = await getAuthtoken(region, user_id); + let headers: any = { + api_key : stackId, + } + let authtoken = ""; + await AuthenticationModel.read(); + const userIndex = AuthenticationModel.chain + .get('users') + .findIndex({ region, user_id: user_id }) + .value(); + + const userData = AuthenticationModel?.data?.users[userIndex]; + if(userData?.access_token) { + authtoken = `Bearer ${userData?.access_token}`; + headers.authorization = authtoken; + } else if(userData?.authtoken) { + authtoken = userData?.authtoken; + headers.authtoken = authtoken; + }else{ + throw new Error("No authentication token found"); + } try { const [err, res] = await safePromise( https({ @@ -33,10 +52,7 @@ const createGlobalField = async ({ url: `${config.CS_API[ region as keyof typeof config.CS_API ]!}/global_fields?include_global_field_schema=true`, - headers: { - api_key : stackId, - authtoken, - }, + headers: headers, }) ); const globalSave = path.join(MIGRATION_DATA_CONFIG.DATA, current_test_stack_id ?? '', GLOBAL_FIELDS_DIR_NAME); diff --git a/api/src/services/marketplace.service.ts b/api/src/services/marketplace.service.ts index 06a010483..d317b8653 100644 --- a/api/src/services/marketplace.service.ts +++ b/api/src/services/marketplace.service.ts @@ -1,9 +1,10 @@ import path from 'path'; import fs from 'fs'; -import getAuthtoken from '../utils/auth.utils.js'; import { MIGRATION_DATA_CONFIG, KEYTOREMOVE } from '../constants/index.js'; import { getAppManifestAndAppConfig } from '../utils/market-app.utils.js'; -import { v4 as uuidv4 } from 'uuid'; +import { v4 as uuidv4 } from "uuid"; +import AuthenticationModel from "../models/authentication.js"; + const { EXTENSIONS_MAPPER_DIR_NAME, @@ -51,21 +52,27 @@ const writeManifestFile = async ({ destinationStackId, appManifest }: any) => { } }; -const createAppManifest = async ({ - destinationStackId, - region, - userId, - orgId, -}: any) => { - const authtoken = await getAuthtoken(region, userId); - const marketPlacePath = path.join( - MIGRATION_DATA_CONFIG.DATA, - destinationStackId, - EXTENSIONS_MAPPER_DIR_NAME - ); - const AppMapper: any = await fs.promises - .readFile(marketPlacePath, 'utf-8') - .catch(async () => {}); + + +const createAppManifest = async ({ destinationStackId, region, userId, orgId }: any) => { + let authtoken = ""; + await AuthenticationModel.read(); + const userIndex = AuthenticationModel.chain + .get('users') + .findIndex({ region, user_id: userId }) + .value(); + + const userData = AuthenticationModel?.data?.users[userIndex]; + if(userData?.access_token) { + + authtoken = `Bearer ${userData?.access_token}`; + } else if(userData?.authtoken) { + authtoken = userData?.authtoken; + }else{ + throw new Error("No authentication token found"); + } + const marketPlacePath = path.join(MIGRATION_DATA_CONFIG.DATA, destinationStackId, EXTENSIONS_MAPPER_DIR_NAME); + const AppMapper: any = await fs.promises.readFile(marketPlacePath, "utf-8").catch(async () => { }); if (AppMapper !== undefined) { const appManifest: any = []; const groupUids: any = groupByAppUid(JSON.parse(AppMapper)); diff --git a/api/src/services/migration.service.ts b/api/src/services/migration.service.ts index dc4348bb7..63efbb3c1 100644 --- a/api/src/services/migration.service.ts +++ b/api/src/services/migration.service.ts @@ -7,7 +7,7 @@ import { config } from '../config/index.js'; import { safePromise, getLogMessage } from '../utils/index.js'; import https from '../utils/https.utils.js'; import { LoginServiceType } from '../models/types.js'; -import getAuthtoken from '../utils/auth.utils.js'; +import getAuthtoken, { getAccessToken } from '../utils/auth.utils.js'; import logger from '../utils/logger.js'; import { HTTP_TEXTS, @@ -55,11 +55,21 @@ const createTestStack = async (req: Request): Promise => { const testStackName = `${name}-Test`; try { + let headers: any = { + organization_uid: orgId, + } + if(token_payload?.is_sso) { + const accessToken = await getAccessToken(token_payload?.region, token_payload?.user_id); + headers.authorization = `Bearer ${accessToken}`; + } else if (token_payload?.is_sso === false) { const authtoken = await getAuthtoken( token_payload?.region, token_payload?.user_id ); - + headers.authtoken = authtoken; + } else { + throw new BadRequestError("No valid authentication token found or mismatch in is_sso flag"); + } await ProjectModelLowdb.read(); const projectData: any = ProjectModelLowdb.chain .get('projects') @@ -77,10 +87,7 @@ const createTestStack = async (req: Request): Promise => { url: `${config.CS_API[ token_payload?.region as keyof typeof config.CS_API ]!}/stacks`, - headers: { - organization_uid: orgId, - authtoken, - }, + headers: headers, data: { stack: { name: newName, @@ -159,10 +166,21 @@ const deleteTestStack = async (req: Request): Promise => { const { token_payload, stack_key } = req.body; try { + let headers: any = { + api_key: stack_key, + } + if(token_payload?.is_sso) { + const accessToken = await getAccessToken(token_payload?.region, token_payload?.user_id); + headers.authorization = `Bearer ${accessToken}`; + } else if (token_payload?.is_sso === false) { const authtoken = await getAuthtoken( - token_payload?.region, - token_payload?.user_id - ); + token_payload?.region, + token_payload?.user_id + ); + headers.authtoken = authtoken; + } else { + throw new BadRequestError("No valid authentication token found or mismatch in is_sso flag"); + } const [err, res] = await safePromise( https({ @@ -170,10 +188,7 @@ const deleteTestStack = async (req: Request): Promise => { url: `${config.CS_API[ token_payload?.region as keyof typeof config.CS_API ]!}/stacks`, - headers: { - api_key: stack_key, - authtoken, - }, + headers: headers, }) ); diff --git a/api/src/services/org.service.ts b/api/src/services/org.service.ts index 72fa72eaf..39e40a557 100644 --- a/api/src/services/org.service.ts +++ b/api/src/services/org.service.ts @@ -3,7 +3,7 @@ import { config } from "../config/index.js"; import { safePromise, getLogMessage } from "../utils/index.js"; import https from "../utils/https.utils.js"; import { LoginServiceType } from "../models/types.js"; -import getAuthtoken from "../utils/auth.utils.js"; +import getAuthtoken, { getAccessToken } from "../utils/auth.utils.js"; import logger from "../utils/logger.js"; import { HTTP_TEXTS, HTTP_CODES } from "../constants/index.js"; import { ExceptionFunction } from "../utils/custom-errors.utils.js"; @@ -22,10 +22,22 @@ const getAllStacks = async (req: Request): Promise => { const search: string = req?.params?.searchText?.toLowerCase(); try { - const authtoken = await getAuthtoken( - token_payload?.region, - token_payload?.user_id - ); + let headers: any = { + organization_uid: orgId, + "Content-Type": "application/json", + }; + if (token_payload?.is_sso) { + const accessToken = await getAccessToken(token_payload?.region, token_payload?.user_id); + headers.authorization = `Bearer ${accessToken}`; + } else if (token_payload?.is_sso === false) { + const authtoken = await getAuthtoken( + token_payload?.region, + token_payload?.user_id + ); + headers.authtoken = authtoken; + } else { + throw new BadRequestError("No valid authentication token found or mismatch in is_sso flag"); + } const [err, res] = await safePromise( https({ @@ -33,10 +45,7 @@ const getAllStacks = async (req: Request): Promise => { url: `${config.CS_API[ token_payload?.region as keyof typeof config.CS_API ]!}/stacks`, - headers: { - organization_uid: orgId, - authtoken, - }, + headers: headers, }) ); if (err) { @@ -109,10 +118,22 @@ const createStack = async (req: Request): Promise => { const { token_payload, name, description, master_locale } = req.body; try { - const authtoken = await getAuthtoken( - token_payload?.region, - token_payload?.user_id - ); + let headers: any = { + organization_uid: orgId, + "Content-Type": "application/json", + }; + if (token_payload?.is_sso) { + const accessToken = await getAccessToken(token_payload?.region, token_payload?.user_id); + headers.authorization = `Bearer ${accessToken}`; + } else if (token_payload?.is_sso === false) { + const authtoken = await getAuthtoken( + token_payload?.region, + token_payload?.user_id + ); + headers.authtoken = authtoken; + } else { + throw new BadRequestError("No valid authentication token found or mismatch in is_sso flag"); + } const [err, res] = await safePromise( https({ @@ -120,10 +141,7 @@ const createStack = async (req: Request): Promise => { url: `${config.CS_API[ token_payload?.region as keyof typeof config.CS_API ]!}/stacks`, - headers: { - organization_uid: orgId, - authtoken, - }, + headers: headers, data: { stack: { name, @@ -182,10 +200,18 @@ const getLocales = async (req: Request): Promise => { const { token_payload } = req.body; try { - const authtoken = await getAuthtoken( - token_payload?.region, - token_payload?.user_id - ); + let headers: any = { + "Content-Type": "application/json", + }; + if (token_payload?.is_sso) { + const accessToken = await getAccessToken(token_payload?.region, token_payload?.user_id); + headers.authorization = `Bearer ${accessToken}`; + } else if (token_payload?.is_sso === false) { + const authtoken = await getAuthtoken(token_payload?.region, token_payload?.user_id); + headers.authtoken = authtoken; + } else { + throw new BadRequestError("No valid authentication token found or mismatch in is_sso flag"); + } const [err, res] = await safePromise( https({ @@ -193,9 +219,7 @@ const getLocales = async (req: Request): Promise => { url: `${config.CS_API[ token_payload?.region as keyof typeof config.CS_API ]!}/locales?include_all=true`, - headers: { - authtoken, - }, + headers: headers, }) ); @@ -242,10 +266,22 @@ const getStackStatus = async (req: Request) => { const { token_payload, stack_api_key } = req.body; const srcFunc = "getStackStatus"; - const authtoken = await getAuthtoken( + let headers: any = { + organization_uid: orgId, + "Content-Type": "application/json", + }; + if (token_payload?.is_sso) { + const accessToken = await getAccessToken(token_payload?.region, token_payload?.user_id); + headers.authorization = `Bearer ${accessToken}`; + } else if (token_payload?.is_sso === false) { + const authtoken = await getAuthtoken( token_payload?.region, token_payload?.user_id - ); + ); + headers.authtoken = authtoken; + } else { + throw new BadRequestError("No valid authentication token found or mismatch in is_sso flag"); + } try { const [stackErr, stackRes] = await safePromise( @@ -254,10 +290,7 @@ const getStackStatus = async (req: Request) => { url: `${config.CS_API[ token_payload?.region as keyof typeof config.CS_API ]!}/stacks`, - headers: { - organization_uid: orgId, - authtoken, - }, + headers: headers, }) ); @@ -282,10 +315,7 @@ const getStackStatus = async (req: Request) => { url: `${config.CS_API[ token_payload?.region as keyof typeof config.CS_API ]!}/content_types?skip=0&limit=1&include_count=true`, - headers: { - api_key: stack_api_key, - authtoken, - }, + headers: headers, }) ); @@ -330,10 +360,16 @@ const getStackLocale = async (req: Request) => { const { token_payload, stack_api_key } = req.body; const srcFunc = "getStackStatus"; - const authtoken = await getAuthtoken( - token_payload?.region, - token_payload?.user_id - ); + let headers: any = { + api_key: stack_api_key, + } + if(token_payload?.is_sso) { + const accessToken = await getAccessToken(token_payload?.region, token_payload?.user_id); + headers.authorization = `Bearer ${accessToken}`; + } else if (token_payload?.is_sso === false) { + const authtoken = await getAuthtoken(token_payload?.region, token_payload?.user_id); + headers.authtoken = authtoken; + } try { const [stackErr, stackRes] = await safePromise( @@ -342,10 +378,7 @@ const getStackLocale = async (req: Request) => { url: `${config.CS_API[ token_payload?.region as keyof typeof config.CS_API ]!}/locales`, - headers: { - api_key: stack_api_key, - authtoken, - }, + headers: headers, }) ); @@ -388,10 +421,15 @@ const getOrgDetails = async (req: Request) => { const { token_payload } = req.body; const srcFunc = "getOrgDetails"; - const authtoken = await getAuthtoken( - token_payload?.region, - token_payload?.user_id - ); + let headers: any = {} + if(token_payload?.is_sso) { + const accessToken = await getAccessToken(token_payload?.region, token_payload?.user_id); + headers.authorization = `Bearer ${accessToken}`; + } else if (token_payload?.is_sso === false) { + const authtoken = await getAuthtoken(token_payload?.region, token_payload?.user_id); + headers.authtoken = authtoken; + } + try { const [stackErr, stackRes] = await safePromise( @@ -400,9 +438,7 @@ const getOrgDetails = async (req: Request) => { url: `${config.CS_API[ token_payload?.region as keyof typeof config.CS_API ]!}/organizations/${orgId}?include_plan=true`, - headers: { - authtoken, - }, + headers: headers, }) ); diff --git a/api/src/services/projects.service.ts b/api/src/services/projects.service.ts index f2e6f7de1..fd602c9f4 100644 --- a/api/src/services/projects.service.ts +++ b/api/src/services/projects.service.ts @@ -15,13 +15,14 @@ import { HTTP_CODES, STEPPER_STEPS, NEW_PROJECT_STATUS, -} from '../constants/index.js'; -import { config } from '../config/index.js'; -import { getLogMessage, isEmpty, safePromise } from '../utils/index.js'; -import getAuthtoken from '../utils/auth.utils.js'; -import https from '../utils/https.utils.js'; -import getProjectUtil from '../utils/get-project.utils.js'; -import logger from '../utils/logger.js'; +} from "../constants/index.js"; +import { config } from "../config/index.js"; +import { getLogMessage, isEmpty, safePromise } from "../utils/index.js"; +import getAuthtoken, { getAccessToken } from "../utils/auth.utils.js"; +import https from "../utils/https.utils.js"; +import getProjectUtil from "../utils/get-project.utils.js"; +import logger from "../utils/logger.js"; +import AuthenticationModel from "../models/authentication.js"; // import { contentMapperService } from "./contentMapper.service.js"; import { v4 as uuidv4 } from 'uuid'; @@ -103,21 +104,23 @@ const getProject = async (req: Request) => { */ const createProject = async (req: Request) => { const orgId = req?.params?.orgId; - if (!orgId) { - throw new BadRequestError('Organization ID is required'); - } - - const { name, description } = req?.body || {}; - if (!name) { - throw new BadRequestError('Project name is required'); - } - - const decodedToken = req?.body?.token_payload; - if (!decodedToken) { - throw new BadRequestError('Token payload is required'); + const { name, description } = req.body; + const decodedToken = req.body.token_payload; + const { user_id = "", region = "" } = decodedToken; + let isSSO = false; + const srcFunc = "createProject"; + await AuthenticationModel.read(); + const userIndex = AuthenticationModel.chain + .get("users") + .findIndex({ + user_id: user_id, + region: region, + }) + .value(); + const userRecord = AuthenticationModel.data.users[userIndex]; + if(userRecord?.access_token){ + isSSO = true; } - const { user_id = '', region = '' } = decodedToken; - const srcFunc = 'createProject'; const projectData = { id: uuidv4(), region, @@ -156,8 +159,9 @@ const createProject = async (req: Request) => { }, mapperKeys: {}, isMigrationStarted: false, - isMigrationCompleted: false, - migration_execution: false, + isMigrationCompleted:false, + migration_execution:false, + isSSO: isSSO, }; try { @@ -761,15 +765,18 @@ const updateDestinationStack = async (req: Request) => { true )) as number; - const project = ProjectModelLowdb.data?.projects?.[projectIndex]; - if (!project) { - throw new NotFoundError(HTTP_TEXTS.PROJECT_NOT_FOUND); + const project = ProjectModelLowdb.data.projects[projectIndex]; + const headers :any = { + organization_uid: orgId, + } + if (project?.isSSO) { + const accessToken = await getAccessToken(token_payload?.region, token_payload?.user_id); + headers.authorization = `Bearer ${accessToken}`; + }else{ + headers.authtoken = await getAuthtoken(token_payload?.region, token_payload?.user_id); } - const authtoken = await getAuthtoken( - token_payload?.region, - token_payload?.user_id - ); + if ( project.status === NEW_PROJECT_STATUS[4] || @@ -802,10 +809,7 @@ const updateDestinationStack = async (req: Request) => { url: `${config.CS_API[ token_payload?.region as keyof typeof config.CS_API ]!}/stacks`, - headers: { - organization_uid: orgId, - authtoken, - }, + headers: headers, }) ); diff --git a/api/src/services/runCli.service.ts b/api/src/services/runCli.service.ts index 956e01834..8568d829e 100644 --- a/api/src/services/runCli.service.ts +++ b/api/src/services/runCli.service.ts @@ -16,7 +16,7 @@ interface TestStack { stackUid: string; isMigrated: boolean; } -import utilitiesHandler from '@contentstack/cli-utilities'; +import { setBasicAuthConfig, setOAuthConfig } from '../utils/config-handler.util.js'; /** * Determines log level based on message content without removing ANSI codes @@ -150,27 +150,29 @@ export const runCli = async ( const regionPresent = CS_REGIONS.find((item) => item === rg) ?? 'NA'.replace(/_/g, '-'); const regionCli = regionPresent.replace(/_/g, '-'); - // Fetch user authentication data await AuthenticationModel.read(); const userData = AuthenticationModel.chain .get('users') .find({ region: regionPresent, user_id }) .value(); - - // Configure CLI with region settings await runCommand( 'npx', ['@contentstack/cli', 'config:set:region', `${regionCli}`], transformePath ); // Pass the log file path here - // Set up authentication configuration for CLI - utilitiesHandler.configHandler.set('authtoken', userData.authtoken); - utilitiesHandler.configHandler.set('email', userData.email); - utilitiesHandler.configHandler.set('authorisationType', 'BASIC'); + if(userData?.access_token){ + setOAuthConfig(userData); + + }else if(userData?.authtoken){ + setBasicAuthConfig(userData); + }else { + throw new Error("No authentication token found"); + } + - if (userData?.authtoken && stack_uid) { + if (userData?.authtoken && stack_uid || userData?.access_token && stack_uid) { // Set up paths for backup and source data const { BACKUP_DATA, diff --git a/api/src/services/taxonomy.service.ts b/api/src/services/taxonomy.service.ts index c2215fde5..0b43f2bab 100644 --- a/api/src/services/taxonomy.service.ts +++ b/api/src/services/taxonomy.service.ts @@ -6,6 +6,7 @@ import fs from 'fs'; import { HTTP_TEXTS, MIGRATION_DATA_CONFIG } from "../constants/index.js"; import path from "path"; import logger from "../utils/logger.js"; +import AuthenticationModel from "../models/authentication.js"; const { TAXONOMIES_DIR_NAME, @@ -142,21 +143,35 @@ const createTaxonomy = async ({stackId,region,userId,current_test_stack_id} : const srcFun = "createTaxonomy"; const taxonomiesPath = path.join(MIGRATION_DATA_CONFIG.DATA, current_test_stack_id, TAXONOMIES_DIR_NAME); await fs.promises.mkdir(taxonomiesPath, { recursive: true }); + let headers: any = { + api_key : stackId, + } + let authtoken = ""; + await AuthenticationModel.read(); + const userIndex = AuthenticationModel.chain + .get('users') + .findIndex({ region, user_id: userId }) + .value(); + + const userData = AuthenticationModel?.data?.users[userIndex]; + if(userData?.access_token) { + + authtoken = `Bearer ${userData?.access_token}`; + headers.authorization = authtoken; + } else if(userData?.authtoken) { + authtoken = userData?.authtoken; + headers.authtoken = authtoken; + }else{ + throw new Error("No authentication token found"); + } try { - const authtoken = await getAuthtoken( - region, - userId - ); const [err, res] = await safePromise( https({ method: "GET", url: `${config.CS_API[ region as keyof typeof config.CS_API ]!}/taxonomies?include_terms_count=true&include_count=true`, - headers: { - api_key : stackId, - authtoken, - }, + headers: headers, }) ); if (err) { diff --git a/api/src/services/user.service.ts b/api/src/services/user.service.ts index 86f1d336c..0c3463103 100644 --- a/api/src/services/user.service.ts +++ b/api/src/services/user.service.ts @@ -34,16 +34,25 @@ const getUserProfile = async (req: Request): Promise => { if (userIndex < 0) throw new BadRequestError(HTTP_TEXTS.NO_CS_USER); + const userRecord = AuthenticationModel.data.users[userIndex]; + let headers: any = { + "Content-Type": "application/json", + }; + if (appTokenPayload?.is_sso) { + headers.authorization = `Bearer ${userRecord.access_token}`; + } else if (appTokenPayload?.is_sso === false) { + headers.authtoken = userRecord.authtoken; + } else { + throw new BadRequestError("No valid authentication token found or mismatch in is_sso flag"); + } + const [err, res] = await safePromise( https({ method: "GET", url: `${config.CS_API[ appTokenPayload?.region as keyof typeof config.CS_API ]!}/user?include_orgs_roles=true`, - headers: { - "Content-Type": "application/json", - authtoken: AuthenticationModel.data.users[userIndex]?.authtoken, - }, + headers: headers, }) ); diff --git a/api/src/utils/auth.utils.ts b/api/src/utils/auth.utils.ts index 30df20752..e3d87d616 100644 --- a/api/src/utils/auth.utils.ts +++ b/api/src/utils/auth.utils.ts @@ -24,3 +24,21 @@ export default async (region: string, userId: string) => { return authToken; }; + + +export const getAccessToken = async (region: string, userId: string) => { + await AuthenticationModel.read(); + const userIndex = AuthenticationModel.chain + .get("users") + .findIndex({ + region: region, + user_id: userId, + }) + .value(); + + const accessToken = AuthenticationModel.data.users[userIndex]?.access_token; + + if (userIndex < 0 || !accessToken) throw new UnauthorizedError(); + + return accessToken; +}; \ No newline at end of file diff --git a/api/src/utils/config-handler.util.ts b/api/src/utils/config-handler.util.ts new file mode 100644 index 000000000..db789ebf0 --- /dev/null +++ b/api/src/utils/config-handler.util.ts @@ -0,0 +1,26 @@ +import { configHandler } from '@contentstack/cli-utilities'; + + +/** + * Sets the OAuth configuration for the CLI + * @param userData - The user data + */ +export const setOAuthConfig = (userData: any) => { + configHandler.set('oauthAccessToken', userData?.access_token); + configHandler.set('oauthRefreshToken', userData?.refresh_token); + configHandler.set('oauthDateTime', userData?.created_at); + configHandler.set('email', userData?.email); + configHandler.set('userUid', userData?.user_id); + configHandler.set('oauthOrgUid', userData?.organization_uid); + configHandler.set('authorisationType', 'OAUTH'); +} + +/** + * Sets the Basic Auth configuration for the CLI + * @param userData - The user data + */ +export const setBasicAuthConfig = (userData: any) => { + configHandler.set('authtoken', userData?.authtoken); + configHandler.set('email', userData?.email); + configHandler.set('authorisationType', 'BASIC'); +} \ No newline at end of file diff --git a/ui/src/pages/Login/index.scss b/ui/src/pages/Login/index.scss index 82b05fb7e..c5f5f5dc8 100644 --- a/ui/src/pages/Login/index.scss +++ b/ui/src/pages/Login/index.scss @@ -187,3 +187,49 @@ line-height: 1 !important; } } +// SSO Button specific styles +.AccountForm__actions__sso_button { + margin-bottom: 24px; +} + +// Divider styles +.flex { + display: flex; +} + +.items-center { + align-items: center; +} + +.flex-1 { + flex: 1; +} + +.border-t { + border-top: 1px solid; +} + +.border-gray-300 { + border-color: #d1d5db; +} + +.px-16 { + padding-left: 16px; + padding-right: 16px; +} + +.text-sm { + font-size: 14px; +} + +.text-gray-500 { + color: #6b7280; +} + +.bg-white { + background-color: white; +} + +.mb-24 { + margin-bottom: 24px; +} \ No newline at end of file diff --git a/ui/src/pages/Login/index.tsx b/ui/src/pages/Login/index.tsx index ff80ede18..b82e4e854 100644 --- a/ui/src/pages/Login/index.tsx +++ b/ui/src/pages/Login/index.tsx @@ -26,7 +26,7 @@ import { clearLocalStorage, failtureNotification, setDataInLocalStorage } from ' // API Service import { getCMSDataFromFile } from '../../cmsData/cmsSelector'; -import { userSession, requestSMSToken } from '../../services/api/login.service'; +import { userSession, requestSMSToken, getAppConfig, checkSSOAuthStatus } from '../../services/api/login.service'; // Interface import { IProps, IStates, defaultStates, User, UserRes, LoginType } from './login.interface'; @@ -238,6 +238,170 @@ const Login: FC = () => { }; }; + const handleSSOLogin = async () => { + setIsLoading(true); + try { + const currentRegion = region; + + await getAppConfig() + .then((res: any) => { + if (res?.status === 404) { + failtureNotification('Kindly setup the SSO first'); + setIsLoading(false); + return; + } + + if (res?.status === 400) { + failtureNotification('Something went wrong please try normal login method'); + setIsLoading(false); + return; + } + + if (res?.status === 500) { + failtureNotification('Something went wrong please try normal login method'); + setIsLoading(false); + return; + } + + const appConfig = res?.data; + + // Check if authUrl exists + if (!appConfig?.authUrl) { + failtureNotification('Something went wrong please try normal login method'); + setIsLoading(false); + return; + } + + // Checks if region matches + if (appConfig?.region?.key && appConfig.region.key !== currentRegion) { + failtureNotification('Kindly choose correct region as the SSO region'); + setIsLoading(false); + return; + } + + const authURL = appConfig.authUrl; + const ssoWindow = window.open(authURL, '_blank', 'noopener,noreferrer'); + + if (appConfig.user?.uid) { + startSSOPolling(appConfig.user.uid, ssoWindow); + } else { + failtureNotification('Missing user information in SSO configuration'); + setIsLoading(false); + } + + }) + .catch((err: any) => { + failtureNotification('Something went wrong please try normal login method'); + setIsLoading(false); + }); + + } catch (error) { + failtureNotification('Something went wrong please try normal login method'); + setIsLoading(false); + } + }; + + + const startSSOPolling = (userId: string, ssoWindow: Window | null) => { + const pollInterval = 2000; + const maxPollTime = 300000; + let pollCount = 0; + const maxPolls = maxPollTime / pollInterval; + const poll = async () => { + pollCount++ + + try { + if (ssoWindow?.closed) { + failtureNotification('SSO login was cancelled'); + setIsLoading(false); + return; + } + + await checkSSOAuthStatus(userId) + .then((authRes: any) => { + + if (authRes?.status === 200 && authRes?.data?.authenticated === true) { + + if (ssoWindow && !ssoWindow.closed) { + ssoWindow.close(); + } + + handleSuccessfulSSOLogin(authRes.data); + return; + } + + if (pollCount < maxPolls) { + setTimeout(poll, pollInterval); + } else { + failtureNotification('SSO authentication timed out. Please try again.'); + setIsLoading(false); + if (ssoWindow && !ssoWindow.closed) { + ssoWindow.close(); + } + } + }) + .catch((error: any) => { + + + if (pollCount < maxPolls) { + setTimeout(poll, pollInterval); + } else { + failtureNotification('Something went wrong please try normal login method'); + setIsLoading(false); + if (ssoWindow && !ssoWindow.closed) { + ssoWindow.close(); + } + } + }); + + } catch (error) { + failtureNotification('Something went wrong please try normal login method'); + setIsLoading(false); + if (ssoWindow && !ssoWindow.closed) { + ssoWindow.close(); + } + } + }; + + setTimeout(poll, pollInterval); + }; + + + const handleSuccessfulSSOLogin = (authData: any) => { + + try { + setIsLoading(false); + + setDataInLocalStorage('app_token', authData.app_token); + + localStorage?.removeItem('organization'); + dispatch(clearOrganisationData()); + + + const authenticationObj = { + authToken: authData.app_token, + isAuthenticated: true + }; + + const userObj = { + ...user, + region: region + }; + + dispatch(setUser(userObj)); + dispatch(setAuthToken(authenticationObj)); + setLoginStates((prev) => ({ ...prev, submitted: true })); + + dispatch(getUserDetails()); + + navigate(`/projects`, { replace: true }); + + } catch (error) { + console.error('Error processing SSO login success:', error); + failtureNotification('Login successful but navigation failed. Please refresh the page.'); + } + }; + // useEffect(()=>{ // const handlePopState = (event: PopStateEvent) => { // event.preventDefault(); @@ -281,7 +445,7 @@ const Login: FC = () => { {twoFactorAuthentication?.title && (

{twoFactorAuthentication?.title}

)} - + ( @@ -461,10 +625,9 @@ const Login: FC = () => { }} - +
- {/* disabled={errors && Object.keys(errors).length ? true : false} */}
+
+ +
diff --git a/ui/src/services/api/login.service.ts b/ui/src/services/api/login.service.ts index acf3300a3..fe9be1a20 100644 --- a/ui/src/services/api/login.service.ts +++ b/ui/src/services/api/login.service.ts @@ -1,7 +1,7 @@ import { AUTH_ROUTES } from '../../utilities/constants'; import { User, SmsToken } from '../../pages/Login/login.interface'; -import { postCall } from './service'; +import { postCall, getCall } from './service'; export const userSession = (data: User) => { try { @@ -26,3 +26,27 @@ export const requestSMSToken = (data: SmsToken) => { } } }; + +export const getAppConfig = () => { + try { + return getCall(`${AUTH_ROUTES}/app-config`); + } catch (error) { + if (error instanceof Error) { + throw new Error(`Error in getAppConfig: ${error.message}`); + } else { + throw new Error('Unknown error in getAppConfig'); + } + } +}; + +export const checkSSOAuthStatus = (userId: string) => { + try { + return getCall(`${AUTH_ROUTES}/sso-status/${userId}`); + } catch (error) { + if (error instanceof Error) { + throw new Error(`Error in checkSSOAuthStatus: ${error.message}`); + } else { + throw new Error('Unknown error in checkSSOAuthStatus'); + } + } +}; \ No newline at end of file diff --git a/upload-api/src/config/index.ts b/upload-api/src/config/index.ts index 9bd6fb1ae..d4b65dd8f 100644 --- a/upload-api/src/config/index.ts +++ b/upload-api/src/config/index.ts @@ -2,7 +2,7 @@ export default { plan: { dropdown: { optionLimit: 100 } }, - cmsType: process.env.CMS_TYPE || 'cmsType', + cmsType: process.env.CMS_TYPE || 'wordpress', isLocalPath: true, awsData: { awsRegion: 'us-east-2', From 8c6755bb82ac486f1b9d5d2356157c62068f1995 Mon Sep 17 00:00:00 2001 From: shobhit upadhyay Date: Mon, 29 Sep 2025 14:28:36 +0530 Subject: [PATCH 5/9] talisman --- .talismanrc | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/.talismanrc b/.talismanrc index 4c4dc6cff..beff44c72 100644 --- a/.talismanrc +++ b/.talismanrc @@ -158,4 +158,25 @@ fileignoreconfig: checksum: f3bd8c6e981ed0acf26432859b2b7e388c0d90018513005cfc674726f14fe245 - filename: ui/src/components/SchemaModal/index.tsx checksum: 607a465c9cd4a504b9a81750a3f9faa0f4e11c09414354d69ec7308c11f0046a + +fileignoreconfig: +- filename: api/sso.utils.js + checksum: 5d589c128c4b38f8aacd70e5d02ddd7fa8e93ff7897ca69a1258378139d1d616 +version: "1.0" + +fileignoreconfig: +- filename: api/package-lock.json + checksum: 4d2fd1905b5933e1d2c4d178e1536422d4aac84caa9640149eab0432a75b712d +- filename: api/src/services/migration.service.ts + checksum: 1fdf5423840e170709c7c677c3a6a7c6ae61f373948c2ef295aa645a859c1af5 +- filename: api/src/services/contentMapper.service.ts + checksum: 03d5dcc31b38fd435f6a4389d6891c7fc1ba27b32dc2b382b91173d84f4565f7 +- filename: api/src/services/globalField.service.ts + checksum: b808815c7372f68fe9a5904d23be50cb0ec066592328ec1721dc3c395cbe3a2c +- filename: api/src/services/taxonomy.service.ts + checksum: 840ab11838ebf08df44ada0a3674dad8cc124bc8bcbc5dfd1d9c585a34e4aeda +- filename: api/src/services/org.service.ts + checksum: 0a50297164d7845d889fc78097164c4794a3f9cd7314c06365c8426a2a6ee52a +- filename: ui/src/pages/Login/index.tsx + checksum: 7f7c008586db60f1cc8df625b88bfdc5c3bb861c21e40a55fc763f0ac4a6a8d2 version: "1.0" \ No newline at end of file From 84771e51323f3bf62a99f80352e9975bf9d8a110 Mon Sep 17 00:00:00 2001 From: shobhit upadhyay Date: Tue, 30 Sep 2025 11:47:09 +0530 Subject: [PATCH 6/9] copilot comments resolve --- .talismanrc | 5 +++++ api/src/services/contentMapper.service.ts | 2 +- ui/src/pages/Login/index.tsx | 2 +- upload-api/src/config/index.ts | 2 +- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/.talismanrc b/.talismanrc index beff44c72..f0ff92405 100644 --- a/.talismanrc +++ b/.talismanrc @@ -179,4 +179,9 @@ fileignoreconfig: checksum: 0a50297164d7845d889fc78097164c4794a3f9cd7314c06365c8426a2a6ee52a - filename: ui/src/pages/Login/index.tsx checksum: 7f7c008586db60f1cc8df625b88bfdc5c3bb861c21e40a55fc763f0ac4a6a8d2 +version: "1.0" + +fileignoreconfig: +- filename: api/src/services/contentMapper.service.ts + checksum: 924b124214a93a7bec4c471304f5b270d5e735d506644180273b7118f3d37dd2 version: "1.0" \ No newline at end of file diff --git a/api/src/services/contentMapper.service.ts b/api/src/services/contentMapper.service.ts index 89d2d9c00..f4b0b32ef 100644 --- a/api/src/services/contentMapper.service.ts +++ b/api/src/services/contentMapper.service.ts @@ -378,7 +378,7 @@ const getExistingContentTypes = async (req: Request) => { token_payload?.region as keyof typeof config.CS_API ]!}/content_types`; let headers: any = { - api_key: projectId?.destination_stack_id, + api_key: project?.destination_stack_id, } if(token_payload?.is_sso) { const accessToken = await getAccessToken(token_payload?.region, token_payload?.user_id); diff --git a/ui/src/pages/Login/index.tsx b/ui/src/pages/Login/index.tsx index b82e4e854..c308fc1b3 100644 --- a/ui/src/pages/Login/index.tsx +++ b/ui/src/pages/Login/index.tsx @@ -308,7 +308,7 @@ const Login: FC = () => { let pollCount = 0; const maxPolls = maxPollTime / pollInterval; const poll = async () => { - pollCount++ + pollCount++; try { if (ssoWindow?.closed) { diff --git a/upload-api/src/config/index.ts b/upload-api/src/config/index.ts index d4b65dd8f..9ea8498b3 100644 --- a/upload-api/src/config/index.ts +++ b/upload-api/src/config/index.ts @@ -12,5 +12,5 @@ export default { bucketName: '', bucketKey: '' }, - localPath: process.env.CONTAINER_PATH || 'localPath' + localPath: process.env.CONTAINER_PATH || 'your-local-legacy-cms-path', }; From 0ef07b2071e3b7078f12745451e961bd19cdbe20 Mon Sep 17 00:00:00 2001 From: shobhit upadhyay Date: Tue, 30 Sep 2025 15:16:09 +0530 Subject: [PATCH 7/9] comments resolve --- .talismanrc | 5 +++ api/src/controllers/auth.controller.ts | 5 +-- api/src/routes/auth.routes.ts | 5 +-- api/src/services/auth.service.ts | 42 ++++++++++++------------ api/src/services/user.service.ts | 10 +++--- api/src/utils/auth.utils.ts | 4 +-- api/sso.utils.js | 44 +++++++++++++++++--------- ui/src/pages/Login/index.tsx | 14 ++++---- 8 files changed, 75 insertions(+), 54 deletions(-) diff --git a/.talismanrc b/.talismanrc index f0ff92405..9fc162a4a 100644 --- a/.talismanrc +++ b/.talismanrc @@ -184,4 +184,9 @@ version: "1.0" fileignoreconfig: - filename: api/src/services/contentMapper.service.ts checksum: 924b124214a93a7bec4c471304f5b270d5e735d506644180273b7118f3d37dd2 +version: "1.0" + +fileignoreconfig: +- filename: ui/src/pages/Login/index.tsx + checksum: 213c6441dc87d82ce6b97679d457ae56c6e40ef13a89bddd4f21afcf566b5576 version: "1.0" \ No newline at end of file diff --git a/api/src/controllers/auth.controller.ts b/api/src/controllers/auth.controller.ts index fa7fcbdba..abf01775d 100644 --- a/api/src/controllers/auth.controller.ts +++ b/api/src/controllers/auth.controller.ts @@ -26,8 +26,9 @@ const RequestSms = async (req: Request, res: Response) => { /** - * Handles the secure, server-to-server POST request from our Launch proxy. - * This confirms to the proxy that the token was received. + * Generates the OAuth token and saves it to the database. + * @param req - The request object. Sends the code and region. + * @param res - The response object. Sends the message "Token received successfully." */ const saveOAuthToken = async (req: Request, res: Response) => { await authService.saveOAuthToken(req); diff --git a/api/src/routes/auth.routes.ts b/api/src/routes/auth.routes.ts index cc2f1077a..322243aac 100644 --- a/api/src/routes/auth.routes.ts +++ b/api/src/routes/auth.routes.ts @@ -41,8 +41,9 @@ router.post( ); /** - * The new secure endpoint that the Launch proxy will call with a POST request - * to deliver the final access token. This is NOT for browser access. + * Generates the OAuth token and saves it to the database. + * @param req - The request object. Sends the code and region. + * @param res - The response object. Sends the message "Token received successfully." * @route POST /v2/auth/save-token */ router.get( diff --git a/api/src/services/auth.service.ts b/api/src/services/auth.service.ts index 6c087c01a..3310e3854 100644 --- a/api/src/services/auth.service.ts +++ b/api/src/services/auth.service.ts @@ -237,22 +237,22 @@ const saveOAuthToken = async (req: Request): Promise => { throw new InternalServerError(userErr); } - const csUser = userRes.data.user; + const csUser = userRes?.data?.user; const appTokenPayload = { region: region as string, - user_id: csUser.uid, + user_id: csUser?.uid, is_sso: true, }; const appToken = generateToken(appTokenPayload); await AuthenticationModel.read(); - const userIndex = AuthenticationModel.chain.get("users").findIndex({ user_id: csUser.uid }).value(); + const userIndex = AuthenticationModel.chain.get("users").findIndex({ user_id: csUser?.uid }).value(); AuthenticationModel.update((data: any) => { const userRecord = { ...appTokenPayload, - email: csUser.email, + email: csUser?.email, access_token: access_token, refresh_token: refresh_token, organization_uid: organization_uid, @@ -295,7 +295,7 @@ export const refreshOAuthToken = async (userId: string): Promise => { throw new Error(`User record not found for user_id: ${userId}`); } - if (!userRecord.refresh_token) { + if (!userRecord?.refresh_token) { throw new Error(`No refresh token available for user: ${userId}`); } @@ -311,7 +311,7 @@ export const refreshOAuthToken = async (userId: string): Promise => { throw new Error('OAuth client_id or client_secret not found in app.json'); } - logger.info(`Refreshing token for user: ${userRecord.email} in region: ${userRecord.region}`); + logger.info(`Refreshing token for user: ${userRecord?.email} in region: ${userRecord?.region}`); const appUrl = CSAUTHHOST[userRecord.region] || CSAUTHHOST['NA']; const tokenEndpoint = `${appUrl}`; @@ -321,7 +321,7 @@ export const refreshOAuthToken = async (userId: string): Promise => { client_id: client_id, client_secret: client_secret, redirect_uri: redirect_uri, - refresh_token: userRecord.refresh_token + refresh_token: userRecord?.refresh_token }); const response = await axios.post(tokenEndpoint, formData, { @@ -331,13 +331,13 @@ export const refreshOAuthToken = async (userId: string): Promise => { timeout: 15000 }); - const { access_token, refresh_token } = response.data; + const { access_token, refresh_token } = response?.data; AuthenticationModel.update((data: any) => { - const userIndex = data.users.findIndex((user: any) => user.user_id === userId); + const userIndex = data?.users?.findIndex((user: any) => user?.user_id === userId); if (userIndex >= 0) { data.users[userIndex] = { - ...data.users[userIndex], + ...data?.users[userIndex], access_token: access_token, refresh_token: refresh_token || userRecord.refresh_token, updated_at: new Date().toISOString() @@ -345,11 +345,11 @@ export const refreshOAuthToken = async (userId: string): Promise => { } }); - logger.info(`Token refreshed successfully for user: ${userRecord.email}`); + logger.info(`Token refreshed successfully for user: ${userRecord?.email}`); return access_token; } catch (error: any) { - logger.error(`Token refresh failed for user ${userId}:`, error.response?.data || error.message); + logger.error(`Token refresh failed for user ${userId}:`, error?.response?.data || error?.message); throw new Error(`Failed to refresh token: ${error.response?.data?.error_description || error.message}`); } }; @@ -392,12 +392,12 @@ export const checkSSOAuthStatus = async (userId: string) => { await AuthenticationModel.read(); const userRecord = AuthenticationModel.chain.get("users").find({ user_id: userId }).value(); - if (!userRecord || !userRecord.access_token) { + if (!userRecord || !userRecord?.access_token) { throw new Error('SSO authentication not completed'); } // Only consider tokens created in the last 10 minutes as "fresh" - const tokenAge = new Date()?.getTime() - new Date(userRecord.updated_at)?.getTime(); + const tokenAge = new Date()?.getTime() - new Date(userRecord?.updated_at)?.getTime(); const maxTokenAge = 10 * 60 * 1000; // 10 minutes in milliseconds if (tokenAge > maxTokenAge) { @@ -406,7 +406,7 @@ export const checkSSOAuthStatus = async (userId: string) => { // Token is fresh, proceed with authentication const appTokenPayload = { - region: userRecord.region, + region: userRecord?.region, user_id: userRecord.user_id, is_sso: true, }; @@ -418,18 +418,18 @@ export const checkSSOAuthStatus = async (userId: string) => { message: 'SSO authentication successful', app_token: appToken, user: { - email: userRecord.email, - uid: userRecord.user_id, - region: userRecord.region, - organization_uid: userRecord.organization_uid + email: userRecord?.email, + uid: userRecord?.user_id, + region: userRecord?.region, + organization_uid: userRecord?.organization_uid } }; } catch (error: any) { - if (error.message.includes('SSO authentication not completed')) { + if (error?.message?.includes('SSO authentication not completed')) { throw error; } - throw new Error(`Failed to check SSO authentication status: ${error.message}`); + throw new Error(`Failed to check SSO authentication status: ${error?.message}`); } }; diff --git a/api/src/services/user.service.ts b/api/src/services/user.service.ts index 0c3463103..53f1333ce 100644 --- a/api/src/services/user.service.ts +++ b/api/src/services/user.service.ts @@ -34,14 +34,14 @@ const getUserProfile = async (req: Request): Promise => { if (userIndex < 0) throw new BadRequestError(HTTP_TEXTS.NO_CS_USER); - const userRecord = AuthenticationModel.data.users[userIndex]; + const userRecord = AuthenticationModel?.data?.users[userIndex]; let headers: any = { "Content-Type": "application/json", }; if (appTokenPayload?.is_sso) { - headers.authorization = `Bearer ${userRecord.access_token}`; + headers.authorization = `Bearer ${userRecord?.access_token}`; } else if (appTokenPayload?.is_sso === false) { - headers.authtoken = userRecord.authtoken; + headers.authtoken = userRecord?.authtoken; } else { throw new BadRequestError("No valid authentication token found or mismatch in is_sso flag"); } @@ -75,7 +75,7 @@ const getUserProfile = async (req: Request): Promise => { if (!res?.data?.user) throw new BadRequestError(HTTP_TEXTS.NO_CS_USER); const orgs = (res?.data?.user?.organizations || []) - ?.filter((org: any) => org?.org_roles?.some((item: any) => item.admin)) + ?.filter((org: any) => org?.org_roles?.some((item: any) => item?.admin)) ?.map(({ uid, name }: any) => ({ org_id: uid, org_name: name })); const ownerOrgs = (res?.data?.user?.organizations || [])?.filter((org:any)=> org?.is_owner) @@ -91,7 +91,7 @@ const getUserProfile = async (req: Request): Promise => { orgs: allOrgs, }, }, - status: res.status, + status: res?.status, }; } catch (error: any) { logger.error( diff --git a/api/src/utils/auth.utils.ts b/api/src/utils/auth.utils.ts index e3d87d616..1d933ba0f 100644 --- a/api/src/utils/auth.utils.ts +++ b/api/src/utils/auth.utils.ts @@ -30,11 +30,11 @@ export const getAccessToken = async (region: string, userId: string) => { await AuthenticationModel.read(); const userIndex = AuthenticationModel.chain .get("users") - .findIndex({ + ?.findIndex({ region: region, user_id: userId, }) - .value(); + ?.value(); const accessToken = AuthenticationModel.data.users[userIndex]?.access_token; diff --git a/api/sso.utils.js b/api/sso.utils.js index 1694958f1..2a1c2b600 100644 --- a/api/sso.utils.js +++ b/api/sso.utils.js @@ -6,6 +6,7 @@ const crypto = require("crypto"); const manifest = require("./manifest.json"); const { default: axios } = require("axios"); +// Region configuration const REGION_CONFIG = { NA: { name: "North America", @@ -55,6 +56,10 @@ const REGION_CONFIG = { }; +/** + * Gets the current region from the CSDX config. + * @returns The current region. + */ function getCurrentRegion() { try { const regionOutput = execSync("csdx config:get:region", { @@ -80,6 +85,12 @@ function getCurrentRegion() { } } +/** + * Sets the OAuth configuration for the CLI. + * @param migration - The migration object. + * @param stackSDKInstance - The stack SDK instance. + * @param managementAPIClient - The management API client. + */ module.exports = async ({ migration, stackSDKInstance, @@ -237,21 +248,22 @@ module.exports = async ({ console.log("🔐 Fetching OAuth configuration..."); const oauthData = await client - .marketplace(selectedOrg.uid) - .app(existingApp?.uid) - .oauth() - .fetch(); + ?.marketplace(selectedOrg?.uid) + ?.app(existingApp?.uid) + ?.oauth() + ?.fetch(); console.log("🔒 Generating PKCE credentials..."); - const code_verifier = crypto.randomBytes(32).toString("hex"); + const code_verifier = crypto?.randomBytes(32).toString("hex"); const code_challenge = crypto - .createHash("sha256") - .update(code_verifier) - .digest("base64") - .replace(/\+/g, "-") - .replace(/\//g, "_") - .replace(/=+$/, ""); - + ?.createHash("sha256") + ?.update(code_verifier) + ?.digest("base64") + ?.replace(/\+/g, "-") + ?.replace(/\//g, "_") + ?.replace(/=+$/, ""); + + // Generates the authorization URL for the app const authUrl = `${regionConfig.app}/#!/apps/${ existingApp?.uid }/authorize?response_type=code&client_id=${ @@ -262,6 +274,8 @@ module.exports = async ({ console.log(`\n🚀 Authorization URL for ${regionConfig.name}:`); console.log(authUrl); + + // Formats the app data for the app.json file const appData = { timestamp: new Date().toISOString(), region: { @@ -295,10 +309,10 @@ module.exports = async ({ } catch (error) { console.error("❌ Setup failed:"); - console.error("Error:", error.message); + console.error("Error:", error?.message); - if (error.errorMessage) { - console.error("Details:", error.errorMessage); + if (error?.errorMessage) { + console.error("Details:", error?.errorMessage); } console.error(`\n🔍 Debug Info:`); diff --git a/ui/src/pages/Login/index.tsx b/ui/src/pages/Login/index.tsx index c308fc1b3..921736b66 100644 --- a/ui/src/pages/Login/index.tsx +++ b/ui/src/pages/Login/index.tsx @@ -273,17 +273,17 @@ const Login: FC = () => { } // Checks if region matches - if (appConfig?.region?.key && appConfig.region.key !== currentRegion) { + if (appConfig?.region?.key && appConfig?.region?.key !== currentRegion) { failtureNotification('Kindly choose correct region as the SSO region'); setIsLoading(false); return; } - const authURL = appConfig.authUrl; + const authURL = appConfig?.authUrl; const ssoWindow = window.open(authURL, '_blank', 'noopener,noreferrer'); - if (appConfig.user?.uid) { - startSSOPolling(appConfig.user.uid, ssoWindow); + if (appConfig?.user?.uid) { + startSSOPolling(appConfig?.user?.uid, ssoWindow); } else { failtureNotification('Missing user information in SSO configuration'); setIsLoading(false); @@ -326,7 +326,7 @@ const Login: FC = () => { ssoWindow.close(); } - handleSuccessfulSSOLogin(authRes.data); + handleSuccessfulSSOLogin(authRes?.data); return; } @@ -372,14 +372,14 @@ const Login: FC = () => { try { setIsLoading(false); - setDataInLocalStorage('app_token', authData.app_token); + setDataInLocalStorage('app_token', authData?.app_token); localStorage?.removeItem('organization'); dispatch(clearOrganisationData()); const authenticationObj = { - authToken: authData.app_token, + authToken: authData?.app_token, isAuthenticated: true }; From 54d20155993d49e5a79262bdf90cbd38900406ce Mon Sep 17 00:00:00 2001 From: shobhitupadhyayy Date: Tue, 20 Jan 2026 12:46:17 +0530 Subject: [PATCH 8/9] feat: implement logout functionality and enhance SSO integration - Added logout endpoint to the authentication service for user session management. - Updated UI components to handle logout actions and provide user feedback during the process. - Enhanced error handling for SSO-related operations and improved user experience during authentication. - Introduced app.json for configuration management and updated related services to utilize this configuration. - Refactored authentication logic to streamline SSO checks and improve overall flow. --- .gitignore | 5 - api/manifest.json | 165 +++ api/package-lock.json | 1347 +++------------------ api/package.json | 2 +- api/src/controllers/auth.controller.ts | 39 +- api/src/routes/auth.routes.ts | 7 + api/src/services/auth.service.ts | 135 ++- api/src/services/user.service.ts | 107 +- api/src/utils/auth.utils.ts | 44 +- api/sso.utils.js | 1 + app.json | 187 +++ ui/src/components/ProfileHeader/index.tsx | 52 +- ui/src/pages/Login/index.tsx | 72 +- ui/src/services/api/login.service.ts | 12 + 14 files changed, 891 insertions(+), 1284 deletions(-) create mode 100644 api/manifest.json create mode 100644 app.json diff --git a/.gitignore b/.gitignore index ff59d7935..04c03ec21 100644 --- a/.gitignore +++ b/.gitignore @@ -16,9 +16,6 @@ # Mono auto generated files mono_crash.* -#App JSON file -app.json - # Build results [Dd]ebug/ [Dd]ebugPublic/ @@ -363,10 +360,8 @@ upload-api/extracted_files* *copy* .qodo .vscode -app.json # Snyk Security Extension - AI Rules (auto-generated) .cursor/rules/snyk_rules.mdc *extracted_files* *MigrationData* *.zip -app.json diff --git a/api/manifest.json b/api/manifest.json new file mode 100644 index 000000000..c985a4079 --- /dev/null +++ b/api/manifest.json @@ -0,0 +1,165 @@ +{ + "uid": "68998661a5c2e100121c1b6a", + "name": "Migration Tool", + "description": "", + "target_type": "organization", + "visibility": "private", + "version": 2, + "icon": "", + "oauth": { + "client_id": "xJek_yZraa_HbU8v", + "client_secret": "LoTjFkVJakE9pGXXcS_nQQAJTEVlen9E", + "redirect_uri": "http://localhost:5001/v2/auth/save-token", + "user_token_config": { + "enabled": true, + "scopes": [ + "app.manifests:read", + "app.manifest:read", + "app.manifest:write", + "app.hosting:read", + "app.hosting:write", + "app.installations:read", + "app.installations.management:read", + "app.installations.management:write", + "app.authorizations:manage", + "app.authorizations.management:write", + "app.requests:write", + "app.requests.management:write", + "scim:manage", + "user.profile:read", + "user:read", + "user:write", + "user.tfa:write", + "user.assignments:read", + "user.assignments:write", + "user.notifications:read", + "user.notifications:write", + "organizations:read", + "organization:read", + "organization.roles:read", + "organization.share:read", + "organization.share:write", + "organization.ownership:write", + "organization.settings:write", + "organization.logs:read", + "organization.usage:read", + "organization.jobs:read", + "organization.jobs:write", + "cm.stacks.management:read", + "cm.stacks.management:write", + "cm.stack.management:read", + "cm.stack.management:write", + "cm.stack.settings:read", + "cm.stack.settings:write", + "cm.stack:share", + "cm.stack:unshare", + "cm.stack.users:read", + "cm.stack.users:write", + "cm.stack.delivery-tokens:read", + "cm.stack.delivery-tokens:write", + "cm.stack.management-tokens:read", + "cm.stack.management-tokens:write", + "cm.content-types.management:read", + "cm.content-types.management:write", + "cm.content-types:import", + "cm.content-types:export", + "cm.content-type:read", + "cm.content-type:write", + "cm.content-type:copy", + "cm.global-fields.management:read", + "cm.global-fields.management:write", + "cm.global-fields:import", + "cm.global-fields:export", + "cm.entries.management:read", + "cm.entries.management:write", + "cm.entries:import", + "cm.entries:export", + "cm.entry:read", + "cm.entry:write", + "cm.entry:publish", + "cm.entry:unpublish", + "cm.entry.workflow:write", + "cm.webhooks.management:read", + "cm.webhooks.management:write", + "cm.webhooks:import", + "cm.webhooks:export", + "cm.webhook:read", + "cm.webhook:write", + "cm.assets.management:read", + "cm.assets.management:write", + "cm.assets.rt:read", + "cm.assets.rt:write", + "cm.assets:download", + "cm.asset:read", + "cm.asset:write", + "cm.asset:publish", + "cm.asset:unpublish", + "cm.workflows.management:read", + "cm.workflows.management:write", + "cm.workflows.publishing-rules:read", + "cm.workflows.publishing-rules:write", + "cm.environments.management:read", + "cm.environments.management:write", + "cm.extensions.management:read", + "cm.extensions.management:write", + "cm.languages.management:read", + "cm.languages.management:write", + "cm.labels.management:read", + "cm.labels.management:write", + "cm.bulk-operations:publish", + "cm.bulk-operations:unpublish", + "cm.bulk-operations:add-to-release", + "cm.bulk-operations:delete", + "cm.bulk-operations:move-to-folder", + "cm.bulk-operations:workflow", + "cm.releases.management:read", + "cm.releases.management:write", + "cm.release:read", + "cm.release:write", + "cm.release:clone", + "cm.release:deploy", + "cm.roles.management:read", + "cm.roles.management:write", + "cm.audit-logs:read", + "personalize:read", + "personalize:manage", + "cm.publish-queue.management:read", + "cm.publish-queue.management:write", + "cm.taxonomies.management:read", + "cm.taxonomies.management:write", + "cm.taxonomy.terms:read", + "cm.taxonomy.terms:write", + "cm.branches.management:read", + "cm.branches.management:write", + "cm.branches:compare-merge", + "cm.branch-aliases.management:read", + "cm.branch-aliases.management:write", + "launch:manage", + "launch.gitproviders:manage", + "automationhub.projects.management:read", + "automationhub.projects.management:write", + "automationhub.automations:read", + "automationhub.automations:write", + "automationhub.executions:read", + "automationhub.audit-logs:read", + "automationhub.variables:read", + "automationhub.variables:write", + "automationhub.accounts:read", + "brand-kits:read", + "brand-kits:manage", + "cm.variant:read", + "cm.variant:write", + "analytics:read", + "auditlogs:read", + "teams:read", + "teams:write" + ], + "allow_pkce": true + }, + "app_token_config": { + "enabled": false, + "scopes": [] + } + }, + "group": "user" + } \ No newline at end of file diff --git a/api/package-lock.json b/api/package-lock.json index 7251795ae..a0a6d7090 100644 --- a/api/package-lock.json +++ b/api/package-lock.json @@ -13,7 +13,7 @@ "@contentstack/cli-utilities": "^1.16.0", "@contentstack/json-rte-serializer": "^3.0.4", "@contentstack/marketplace-sdk": "^1.4.1", - "axios": "^1.12.0", + "axios": "^1.13.2", "chokidar": "^3.6.0", "cors": "^2.8.5", "dayjs": "^1.11.18", @@ -200,7 +200,6 @@ "version": "1.15.0", "resolved": "https://registry.npmjs.org/@contentstack/cli-utilities/-/cli-utilities-1.15.0.tgz", "integrity": "sha512-Q3csEjZk7rdEvbhRyq41jMT9nFduxR7zVpyGAkYdialh4KjMHxJvzVUdmYuA3PA92xoTlFdcY97yXPQJpmptTw==", - "license": "MIT", "dependencies": { "@contentstack/management": "~1.22.0", "@contentstack/marketplace-sdk": "^1.2.8", @@ -237,7 +236,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", - "license": "ISC", "engines": { "node": ">= 10" } @@ -246,7 +244,6 @@ "version": "8.2.6", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz", "integrity": "sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==", - "license": "MIT", "dependencies": { "ansi-escapes": "^4.2.1", "chalk": "^4.1.1", @@ -272,7 +269,6 @@ "version": "7.8.2", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", - "license": "Apache-2.0", "dependencies": { "tslib": "^2.1.0" } @@ -281,7 +277,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "license": "MIT", "bin": { "mkdirp": "bin/cmd.js" }, @@ -292,14 +287,12 @@ "node_modules/@contentstack/cli-audit/node_modules/mute-stream": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "license": "ISC" + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" }, "node_modules/@contentstack/cli-audit/node_modules/wrap-ansi": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -342,7 +335,6 @@ "version": "1.15.0", "resolved": "https://registry.npmjs.org/@contentstack/cli-utilities/-/cli-utilities-1.15.0.tgz", "integrity": "sha512-Q3csEjZk7rdEvbhRyq41jMT9nFduxR7zVpyGAkYdialh4KjMHxJvzVUdmYuA3PA92xoTlFdcY97yXPQJpmptTw==", - "license": "MIT", "dependencies": { "@contentstack/management": "~1.22.0", "@contentstack/marketplace-sdk": "^1.2.8", @@ -379,7 +371,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", - "license": "ISC", "engines": { "node": ">= 10" } @@ -388,7 +379,6 @@ "version": "8.2.6", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz", "integrity": "sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==", - "license": "MIT", "dependencies": { "ansi-escapes": "^4.2.1", "chalk": "^4.1.1", @@ -414,7 +404,6 @@ "version": "7.8.2", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", - "license": "Apache-2.0", "dependencies": { "tslib": "^2.1.0" } @@ -423,7 +412,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "license": "MIT", "bin": { "mkdirp": "bin/cmd.js" }, @@ -434,14 +422,12 @@ "node_modules/@contentstack/cli-auth/node_modules/mute-stream": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "license": "ISC" + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" }, "node_modules/@contentstack/cli-auth/node_modules/wrap-ansi": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -473,7 +459,6 @@ "version": "1.15.0", "resolved": "https://registry.npmjs.org/@contentstack/cli-utilities/-/cli-utilities-1.15.0.tgz", "integrity": "sha512-Q3csEjZk7rdEvbhRyq41jMT9nFduxR7zVpyGAkYdialh4KjMHxJvzVUdmYuA3PA92xoTlFdcY97yXPQJpmptTw==", - "license": "MIT", "dependencies": { "@contentstack/management": "~1.22.0", "@contentstack/marketplace-sdk": "^1.2.8", @@ -510,7 +495,6 @@ "version": "8.2.6", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz", "integrity": "sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==", - "license": "MIT", "dependencies": { "ansi-escapes": "^4.2.1", "chalk": "^4.1.1", @@ -536,7 +520,6 @@ "version": "7.8.2", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", - "license": "Apache-2.0", "dependencies": { "tslib": "^2.1.0" } @@ -545,7 +528,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", - "license": "ISC", "engines": { "node": ">= 10" } @@ -564,14 +546,12 @@ "node_modules/@contentstack/cli-cm-bootstrap/node_modules/mute-stream": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "license": "ISC" + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" }, "node_modules/@contentstack/cli-cm-bootstrap/node_modules/wrap-ansi": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -616,7 +596,6 @@ "version": "1.15.0", "resolved": "https://registry.npmjs.org/@contentstack/cli-utilities/-/cli-utilities-1.15.0.tgz", "integrity": "sha512-Q3csEjZk7rdEvbhRyq41jMT9nFduxR7zVpyGAkYdialh4KjMHxJvzVUdmYuA3PA92xoTlFdcY97yXPQJpmptTw==", - "license": "MIT", "dependencies": { "@contentstack/management": "~1.22.0", "@contentstack/marketplace-sdk": "^1.2.8", @@ -653,7 +632,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", - "license": "ISC", "engines": { "node": ">= 10" } @@ -662,7 +640,6 @@ "version": "8.2.6", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz", "integrity": "sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==", - "license": "MIT", "dependencies": { "ansi-escapes": "^4.2.1", "chalk": "^4.1.1", @@ -688,7 +665,6 @@ "version": "7.8.2", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", - "license": "Apache-2.0", "dependencies": { "tslib": "^2.1.0" } @@ -697,7 +673,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "license": "MIT", "bin": { "mkdirp": "bin/cmd.js" }, @@ -708,14 +683,12 @@ "node_modules/@contentstack/cli-cm-branches/node_modules/mute-stream": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "license": "ISC" + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" }, "node_modules/@contentstack/cli-cm-branches/node_modules/wrap-ansi": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -778,7 +751,6 @@ "version": "1.15.0", "resolved": "https://registry.npmjs.org/@contentstack/cli-utilities/-/cli-utilities-1.15.0.tgz", "integrity": "sha512-Q3csEjZk7rdEvbhRyq41jMT9nFduxR7zVpyGAkYdialh4KjMHxJvzVUdmYuA3PA92xoTlFdcY97yXPQJpmptTw==", - "license": "MIT", "dependencies": { "@contentstack/management": "~1.22.0", "@contentstack/marketplace-sdk": "^1.2.8", @@ -815,7 +787,6 @@ "version": "8.2.6", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz", "integrity": "sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==", - "license": "MIT", "dependencies": { "ansi-escapes": "^4.2.1", "chalk": "^4.1.1", @@ -841,7 +812,6 @@ "version": "7.8.2", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", - "license": "Apache-2.0", "dependencies": { "tslib": "^2.1.0" } @@ -850,7 +820,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", - "license": "ISC", "engines": { "node": ">= 10" } @@ -859,7 +828,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "license": "MIT", "bin": { "mkdirp": "bin/cmd.js" }, @@ -870,14 +838,12 @@ "node_modules/@contentstack/cli-cm-bulk-publish/node_modules/mute-stream": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "license": "ISC" + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" }, "node_modules/@contentstack/cli-cm-bulk-publish/node_modules/wrap-ansi": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -915,7 +881,6 @@ "version": "1.15.0", "resolved": "https://registry.npmjs.org/@contentstack/cli-utilities/-/cli-utilities-1.15.0.tgz", "integrity": "sha512-Q3csEjZk7rdEvbhRyq41jMT9nFduxR7zVpyGAkYdialh4KjMHxJvzVUdmYuA3PA92xoTlFdcY97yXPQJpmptTw==", - "license": "MIT", "dependencies": { "@contentstack/management": "~1.22.0", "@contentstack/marketplace-sdk": "^1.2.8", @@ -952,7 +917,6 @@ "version": "8.2.6", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz", "integrity": "sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==", - "license": "MIT", "dependencies": { "ansi-escapes": "^4.2.1", "chalk": "^4.1.1", @@ -978,7 +942,6 @@ "version": "7.8.2", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", - "license": "Apache-2.0", "dependencies": { "tslib": "^2.1.0" } @@ -987,7 +950,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", - "license": "ISC", "engines": { "node": ">= 10" } @@ -996,7 +958,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "license": "MIT", "bin": { "mkdirp": "bin/cmd.js" }, @@ -1007,14 +968,12 @@ "node_modules/@contentstack/cli-cm-clone/node_modules/mute-stream": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "license": "ISC" + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" }, "node_modules/@contentstack/cli-cm-clone/node_modules/wrap-ansi": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -1070,7 +1029,6 @@ "version": "1.15.0", "resolved": "https://registry.npmjs.org/@contentstack/cli-utilities/-/cli-utilities-1.15.0.tgz", "integrity": "sha512-Q3csEjZk7rdEvbhRyq41jMT9nFduxR7zVpyGAkYdialh4KjMHxJvzVUdmYuA3PA92xoTlFdcY97yXPQJpmptTw==", - "license": "MIT", "dependencies": { "@contentstack/management": "~1.22.0", "@contentstack/marketplace-sdk": "^1.2.8", @@ -1107,7 +1065,6 @@ "version": "8.2.6", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz", "integrity": "sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==", - "license": "MIT", "dependencies": { "ansi-escapes": "^4.2.1", "chalk": "^4.1.1", @@ -1133,7 +1090,6 @@ "version": "7.8.2", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", - "license": "Apache-2.0", "dependencies": { "tslib": "^2.1.0" } @@ -1142,7 +1098,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "license": "MIT", "bin": { "mkdirp": "bin/cmd.js" }, @@ -1154,7 +1109,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", - "license": "ISC", "engines": { "node": ">= 10" } @@ -1162,14 +1116,12 @@ "node_modules/@contentstack/cli-cm-export-to-csv/node_modules/mute-stream": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "license": "ISC" + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" }, "node_modules/@contentstack/cli-cm-export-to-csv/node_modules/wrap-ansi": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -1183,7 +1135,6 @@ "version": "1.15.0", "resolved": "https://registry.npmjs.org/@contentstack/cli-utilities/-/cli-utilities-1.15.0.tgz", "integrity": "sha512-Q3csEjZk7rdEvbhRyq41jMT9nFduxR7zVpyGAkYdialh4KjMHxJvzVUdmYuA3PA92xoTlFdcY97yXPQJpmptTw==", - "license": "MIT", "dependencies": { "@contentstack/management": "~1.22.0", "@contentstack/marketplace-sdk": "^1.2.8", @@ -1220,7 +1171,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", - "license": "ISC", "engines": { "node": ">= 10" } @@ -1229,7 +1179,6 @@ "version": "8.2.6", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz", "integrity": "sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==", - "license": "MIT", "dependencies": { "ansi-escapes": "^4.2.1", "chalk": "^4.1.1", @@ -1255,7 +1204,6 @@ "version": "7.8.2", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", - "license": "Apache-2.0", "dependencies": { "tslib": "^2.1.0" } @@ -1274,14 +1222,12 @@ "node_modules/@contentstack/cli-cm-export/node_modules/mute-stream": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "license": "ISC" + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" }, "node_modules/@contentstack/cli-cm-export/node_modules/wrap-ansi": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -1343,7 +1289,6 @@ "version": "1.15.0", "resolved": "https://registry.npmjs.org/@contentstack/cli-utilities/-/cli-utilities-1.15.0.tgz", "integrity": "sha512-Q3csEjZk7rdEvbhRyq41jMT9nFduxR7zVpyGAkYdialh4KjMHxJvzVUdmYuA3PA92xoTlFdcY97yXPQJpmptTw==", - "license": "MIT", "dependencies": { "@contentstack/management": "~1.22.0", "@contentstack/marketplace-sdk": "^1.2.8", @@ -1380,7 +1325,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", - "license": "ISC", "engines": { "node": ">= 10" } @@ -1389,7 +1333,6 @@ "version": "8.2.6", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz", "integrity": "sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==", - "license": "MIT", "dependencies": { "ansi-escapes": "^4.2.1", "chalk": "^4.1.1", @@ -1415,7 +1358,6 @@ "version": "7.8.2", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", - "license": "Apache-2.0", "dependencies": { "tslib": "^2.1.0" } @@ -1434,14 +1376,12 @@ "node_modules/@contentstack/cli-cm-import-setup/node_modules/mute-stream": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "license": "ISC" + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" }, "node_modules/@contentstack/cli-cm-import-setup/node_modules/wrap-ansi": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -1455,7 +1395,6 @@ "version": "1.15.0", "resolved": "https://registry.npmjs.org/@contentstack/cli-utilities/-/cli-utilities-1.15.0.tgz", "integrity": "sha512-Q3csEjZk7rdEvbhRyq41jMT9nFduxR7zVpyGAkYdialh4KjMHxJvzVUdmYuA3PA92xoTlFdcY97yXPQJpmptTw==", - "license": "MIT", "dependencies": { "@contentstack/management": "~1.22.0", "@contentstack/marketplace-sdk": "^1.2.8", @@ -1492,7 +1431,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", - "license": "ISC", "engines": { "node": ">= 10" } @@ -1501,7 +1439,6 @@ "version": "8.2.6", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz", "integrity": "sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==", - "license": "MIT", "dependencies": { "ansi-escapes": "^4.2.1", "chalk": "^4.1.1", @@ -1527,7 +1464,6 @@ "version": "7.8.2", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", - "license": "Apache-2.0", "dependencies": { "tslib": "^2.1.0" } @@ -1546,14 +1482,12 @@ "node_modules/@contentstack/cli-cm-import/node_modules/mute-stream": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "license": "ISC" + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" }, "node_modules/@contentstack/cli-cm-import/node_modules/wrap-ansi": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -1604,7 +1538,6 @@ "version": "1.15.0", "resolved": "https://registry.npmjs.org/@contentstack/cli-utilities/-/cli-utilities-1.15.0.tgz", "integrity": "sha512-Q3csEjZk7rdEvbhRyq41jMT9nFduxR7zVpyGAkYdialh4KjMHxJvzVUdmYuA3PA92xoTlFdcY97yXPQJpmptTw==", - "license": "MIT", "dependencies": { "@contentstack/management": "~1.22.0", "@contentstack/marketplace-sdk": "^1.2.8", @@ -1645,7 +1578,6 @@ "https://github.com/sponsors/broofa", "https://github.com/sponsors/ctavan" ], - "license": "MIT", "bin": { "uuid": "dist/bin/uuid" } @@ -1684,7 +1616,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", - "license": "ISC", "engines": { "node": ">= 10" } @@ -1801,7 +1732,6 @@ "version": "8.2.6", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz", "integrity": "sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==", - "license": "MIT", "dependencies": { "ansi-escapes": "^4.2.1", "chalk": "^4.1.1", @@ -1827,7 +1757,6 @@ "version": "7.8.2", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", - "license": "Apache-2.0", "dependencies": { "tslib": "^2.1.0" } @@ -1880,7 +1809,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "license": "MIT", "bin": { "mkdirp": "bin/cmd.js" }, @@ -1891,8 +1819,7 @@ "node_modules/@contentstack/cli-cm-migrate-rte/node_modules/mute-stream": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "license": "ISC" + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" }, "node_modules/@contentstack/cli-cm-migrate-rte/node_modules/tr46": { "version": "3.0.0", @@ -1960,7 +1887,6 @@ "version": "6.2.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -2028,7 +1954,6 @@ "version": "1.15.0", "resolved": "https://registry.npmjs.org/@contentstack/cli-utilities/-/cli-utilities-1.15.0.tgz", "integrity": "sha512-Q3csEjZk7rdEvbhRyq41jMT9nFduxR7zVpyGAkYdialh4KjMHxJvzVUdmYuA3PA92xoTlFdcY97yXPQJpmptTw==", - "license": "MIT", "dependencies": { "@contentstack/management": "~1.22.0", "@contentstack/marketplace-sdk": "^1.2.8", @@ -2065,7 +1990,6 @@ "version": "8.2.6", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz", "integrity": "sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==", - "license": "MIT", "dependencies": { "ansi-escapes": "^4.2.1", "chalk": "^4.1.1", @@ -2091,7 +2015,6 @@ "version": "7.8.2", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", - "license": "Apache-2.0", "dependencies": { "tslib": "^2.1.0" } @@ -2100,7 +2023,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", - "license": "ISC", "engines": { "node": ">= 10" } @@ -2119,14 +2041,12 @@ "node_modules/@contentstack/cli-cm-seed/node_modules/mute-stream": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "license": "ISC" + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" }, "node_modules/@contentstack/cli-cm-seed/node_modules/wrap-ansi": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -2154,7 +2074,6 @@ "version": "1.15.0", "resolved": "https://registry.npmjs.org/@contentstack/cli-utilities/-/cli-utilities-1.15.0.tgz", "integrity": "sha512-Q3csEjZk7rdEvbhRyq41jMT9nFduxR7zVpyGAkYdialh4KjMHxJvzVUdmYuA3PA92xoTlFdcY97yXPQJpmptTw==", - "license": "MIT", "dependencies": { "@contentstack/management": "~1.22.0", "@contentstack/marketplace-sdk": "^1.2.8", @@ -2191,7 +2110,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", - "license": "ISC", "engines": { "node": ">= 10" } @@ -2200,7 +2118,6 @@ "version": "8.2.6", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz", "integrity": "sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==", - "license": "MIT", "dependencies": { "ansi-escapes": "^4.2.1", "chalk": "^4.1.1", @@ -2226,7 +2143,6 @@ "version": "7.8.2", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", - "license": "Apache-2.0", "dependencies": { "tslib": "^2.1.0" } @@ -2235,7 +2151,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "license": "MIT", "bin": { "mkdirp": "bin/cmd.js" }, @@ -2246,14 +2161,12 @@ "node_modules/@contentstack/cli-command/node_modules/mute-stream": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "license": "ISC" + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" }, "node_modules/@contentstack/cli-command/node_modules/wrap-ansi": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -2282,7 +2195,6 @@ "version": "1.15.0", "resolved": "https://registry.npmjs.org/@contentstack/cli-utilities/-/cli-utilities-1.15.0.tgz", "integrity": "sha512-Q3csEjZk7rdEvbhRyq41jMT9nFduxR7zVpyGAkYdialh4KjMHxJvzVUdmYuA3PA92xoTlFdcY97yXPQJpmptTw==", - "license": "MIT", "dependencies": { "@contentstack/management": "~1.22.0", "@contentstack/marketplace-sdk": "^1.2.8", @@ -2319,7 +2231,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", - "license": "ISC", "engines": { "node": ">= 10" } @@ -2328,7 +2239,6 @@ "version": "8.2.6", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz", "integrity": "sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==", - "license": "MIT", "dependencies": { "ansi-escapes": "^4.2.1", "chalk": "^4.1.1", @@ -2354,7 +2264,6 @@ "version": "7.8.2", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", - "license": "Apache-2.0", "dependencies": { "tslib": "^2.1.0" } @@ -2363,7 +2272,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "license": "MIT", "bin": { "mkdirp": "bin/cmd.js" }, @@ -2374,14 +2282,12 @@ "node_modules/@contentstack/cli-config/node_modules/mute-stream": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "license": "ISC" + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" }, "node_modules/@contentstack/cli-config/node_modules/wrap-ansi": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -2453,7 +2359,6 @@ "version": "1.15.0", "resolved": "https://registry.npmjs.org/@contentstack/cli-utilities/-/cli-utilities-1.15.0.tgz", "integrity": "sha512-Q3csEjZk7rdEvbhRyq41jMT9nFduxR7zVpyGAkYdialh4KjMHxJvzVUdmYuA3PA92xoTlFdcY97yXPQJpmptTw==", - "license": "MIT", "dependencies": { "@contentstack/management": "~1.22.0", "@contentstack/marketplace-sdk": "^1.2.8", @@ -2490,7 +2395,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", - "license": "ISC", "engines": { "node": ">= 10" } @@ -2499,7 +2403,6 @@ "version": "8.2.6", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz", "integrity": "sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==", - "license": "MIT", "dependencies": { "ansi-escapes": "^4.2.1", "chalk": "^4.1.1", @@ -2525,7 +2428,6 @@ "version": "7.8.2", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", - "license": "Apache-2.0", "dependencies": { "tslib": "^2.1.0" } @@ -2534,7 +2436,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "license": "MIT", "bin": { "mkdirp": "bin/cmd.js" }, @@ -2545,14 +2446,12 @@ "node_modules/@contentstack/cli-migration/node_modules/mute-stream": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "license": "ISC" + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" }, "node_modules/@contentstack/cli-migration/node_modules/wrap-ansi": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -2566,7 +2465,6 @@ "version": "1.16.0", "resolved": "https://registry.npmjs.org/@contentstack/cli-utilities/-/cli-utilities-1.16.0.tgz", "integrity": "sha512-2SlKE9bJH3bd+ESNq1c9FWRCYzIjuWxRtXp+83eX7qDzHA7Lgu2EsRjfq+TcYVtBdCd0BzVATRIU2t/vNUl5Zw==", - "license": "MIT", "dependencies": { "@contentstack/management": "~1.25.1", "@contentstack/marketplace-sdk": "^1.4.0", @@ -2603,7 +2501,6 @@ "version": "1.25.1", "resolved": "https://registry.npmjs.org/@contentstack/management/-/management-1.25.1.tgz", "integrity": "sha512-454V3zGw4nrxnlYxXm82Z+yNjuechiN+TRE7SXWyHFUsexYVpKNyGyKZCvG6b4JymRTVUZpy/KnFixo01GP9Sg==", - "license": "MIT", "dependencies": { "assert": "^2.1.0", "axios": "^1.12.2", @@ -2647,7 +2544,6 @@ "version": "1.15.0", "resolved": "https://registry.npmjs.org/@contentstack/cli-utilities/-/cli-utilities-1.15.0.tgz", "integrity": "sha512-Q3csEjZk7rdEvbhRyq41jMT9nFduxR7zVpyGAkYdialh4KjMHxJvzVUdmYuA3PA92xoTlFdcY97yXPQJpmptTw==", - "license": "MIT", "dependencies": { "@contentstack/management": "~1.22.0", "@contentstack/marketplace-sdk": "^1.2.8", @@ -2684,7 +2580,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", - "license": "ISC", "engines": { "node": ">= 10" } @@ -2693,7 +2588,6 @@ "version": "8.2.6", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz", "integrity": "sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==", - "license": "MIT", "dependencies": { "ansi-escapes": "^4.2.1", "chalk": "^4.1.1", @@ -2719,7 +2613,6 @@ "version": "7.8.2", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", - "license": "Apache-2.0", "dependencies": { "tslib": "^2.1.0" } @@ -2738,14 +2631,12 @@ "node_modules/@contentstack/cli-variants/node_modules/mute-stream": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "license": "ISC" + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" }, "node_modules/@contentstack/cli-variants/node_modules/wrap-ansi": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -2759,7 +2650,6 @@ "version": "1.15.0", "resolved": "https://registry.npmjs.org/@contentstack/cli-utilities/-/cli-utilities-1.15.0.tgz", "integrity": "sha512-Q3csEjZk7rdEvbhRyq41jMT9nFduxR7zVpyGAkYdialh4KjMHxJvzVUdmYuA3PA92xoTlFdcY97yXPQJpmptTw==", - "license": "MIT", "dependencies": { "@contentstack/management": "~1.22.0", "@contentstack/marketplace-sdk": "^1.2.8", @@ -2796,7 +2686,6 @@ "version": "8.2.6", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz", "integrity": "sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==", - "license": "MIT", "dependencies": { "ansi-escapes": "^4.2.1", "chalk": "^4.1.1", @@ -2822,7 +2711,6 @@ "version": "7.8.2", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", - "license": "Apache-2.0", "dependencies": { "tslib": "^2.1.0" } @@ -2831,7 +2719,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", - "license": "ISC", "engines": { "node": ">= 10" } @@ -2840,7 +2727,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "license": "MIT", "bin": { "mkdirp": "bin/cmd.js" }, @@ -2851,14 +2737,12 @@ "node_modules/@contentstack/cli/node_modules/mute-stream": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "license": "ISC" + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" }, "node_modules/@contentstack/cli/node_modules/wrap-ansi": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -3041,503 +2925,103 @@ "kuler": "^2.0.0" } }, - "node_modules/@esbuild/aix-ppc64": { + "node_modules/@esbuild/darwin-arm64": { "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz", - "integrity": "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz", + "integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==", "cpu": [ - "ppc64" + "arm64" ], "dev": true, "optional": true, "os": [ - "aix" + "darwin" ], "engines": { "node": ">=18" } }, - "node_modules/@esbuild/android-arm": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.2.tgz", - "integrity": "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==", - "cpu": [ - "arm" - ], + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", "dev": true, - "optional": true, - "os": [ - "android" - ], + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, "engines": { - "node": ">=18" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, - "node_modules/@esbuild/android-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.2.tgz", - "integrity": "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==", - "cpu": [ - "arm64" - ], + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", "dev": true, - "optional": true, - "os": [ - "android" - ], "engines": { - "node": ">=18" + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, - "node_modules/@esbuild/android-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.2.tgz", - "integrity": "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==", - "cpu": [ - "x64" - ], + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", "dev": true, - "optional": true, - "os": [ - "android" - ], + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, "engines": { - "node": ">=18" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz", - "integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==", - "cpu": [ - "arm64" - ], + "node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.2.tgz", - "integrity": "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==", - "cpu": [ - "x64" - ], + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.2.tgz", - "integrity": "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.2.tgz", - "integrity": "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.2.tgz", - "integrity": "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.2.tgz", - "integrity": "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.2.tgz", - "integrity": "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.2.tgz", - "integrity": "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==", - "cpu": [ - "loong64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.2.tgz", - "integrity": "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==", - "cpu": [ - "mips64el" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.2.tgz", - "integrity": "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.2.tgz", - "integrity": "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.2.tgz", - "integrity": "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.2.tgz", - "integrity": "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.2.tgz", - "integrity": "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.2.tgz", - "integrity": "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.2.tgz", - "integrity": "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.2.tgz", - "integrity": "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openharmony-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.2.tgz", - "integrity": "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.2.tgz", - "integrity": "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.2.tgz", - "integrity": "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.2.tgz", - "integrity": "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.2.tgz", - "integrity": "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", - "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", - "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", - "dev": true, - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/eslintrc/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true }, "node_modules/@eslint/eslintrc/node_modules/minimatch": { "version": "3.1.2", @@ -4286,392 +3770,104 @@ } } }, - "node_modules/@rollup/plugin-json": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-6.1.0.tgz", - "integrity": "sha512-EGI2te5ENk1coGeADSIwZ7G2Q8CJS2sF120T7jLw4xFw9n7wIOXHo+kIYRAoVpJAN+kmqZSoO3Fp4JtoNF4ReA==", - "dependencies": { - "@rollup/pluginutils": "^5.1.0" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, - "node_modules/@rollup/plugin-node-resolve": { - "version": "16.0.3", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-16.0.3.tgz", - "integrity": "sha512-lUYM3UBGuM93CnMPG1YocWu7X802BrNF3jW2zny5gQyLQgRFJhV1Sq0Zi74+dh/6NBx1DxFC4b4GXg9wUCG5Qg==", - "dependencies": { - "@rollup/pluginutils": "^5.0.1", - "@types/resolve": "1.20.2", - "deepmerge": "^4.2.2", - "is-module": "^1.0.0", - "resolve": "^1.22.1" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^2.78.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, - "node_modules/@rollup/plugin-typescript": { - "version": "12.3.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-12.3.0.tgz", - "integrity": "sha512-7DP0/p7y3t67+NabT9f8oTBFE6gGkto4SA6Np2oudYmZE/m1dt8RB0SjL1msMxFpLo631qjRCcBlAbq1ml/Big==", - "dependencies": { - "@rollup/pluginutils": "^5.1.0", - "resolve": "^1.22.1" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^2.14.0||^3.0.0||^4.0.0", - "tslib": "*", - "typescript": ">=3.7.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - }, - "tslib": { - "optional": true - } - } - }, - "node_modules/@rollup/pluginutils": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", - "integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==", - "dependencies": { - "@types/estree": "^1.0.0", - "estree-walker": "^2.0.2", - "picomatch": "^4.0.2" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.55.1.tgz", - "integrity": "sha512-9R0DM/ykwfGIlNu6+2U09ga0WXeZ9MRC2Ter8jnz8415VbuIykVuc6bhdrbORFZANDmTDvq26mJrEVTl8TdnDg==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.55.1.tgz", - "integrity": "sha512-eFZCb1YUqhTysgW3sj/55du5cG57S7UTNtdMjCW7LwVcj3dTTcowCsC8p7uBdzKsZYa8J7IDE8lhMI+HX1vQvg==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.55.1.tgz", - "integrity": "sha512-p3grE2PHcQm2e8PSGZdzIhCKbMCw/xi9XvMPErPhwO17vxtvCN5FEA2mSLgmKlCjHGMQTP6phuQTYWUnKewwGg==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.55.1.tgz", - "integrity": "sha512-rDUjG25C9qoTm+e02Esi+aqTKSBYwVTaoS1wxcN47/Luqef57Vgp96xNANwt5npq9GDxsH7kXxNkJVEsWEOEaQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.55.1.tgz", - "integrity": "sha512-+JiU7Jbp5cdxekIgdte0jfcu5oqw4GCKr6i3PJTlXTCU5H5Fvtkpbs4XJHRmWNXF+hKmn4v7ogI5OQPaupJgOg==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.55.1.tgz", - "integrity": "sha512-V5xC1tOVWtLLmr3YUk2f6EJK4qksksOYiz/TCsFHu/R+woubcLWdC9nZQmwjOAbmExBIVKsm1/wKmEy4z4u4Bw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.55.1.tgz", - "integrity": "sha512-Rn3n+FUk2J5VWx+ywrG/HGPTD9jXNbicRtTM11e/uorplArnXZYsVifnPPqNNP5BsO3roI4n8332ukpY/zN7rQ==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.55.1.tgz", - "integrity": "sha512-grPNWydeKtc1aEdrJDWk4opD7nFtQbMmV7769hiAaYyUKCT1faPRm2av8CX1YJsZ4TLAZcg9gTR1KvEzoLjXkg==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.55.1.tgz", - "integrity": "sha512-a59mwd1k6x8tXKcUxSyISiquLwB5pX+fJW9TkWU46lCqD/GRDe9uDN31jrMmVP3feI3mhAdvcCClhV8V5MhJFQ==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.55.1.tgz", - "integrity": "sha512-puS1MEgWX5GsHSoiAsF0TYrpomdvkaXm0CofIMG5uVkP6IBV+ZO9xhC5YEN49nsgYo1DuuMquF9+7EDBVYu4uA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.55.1.tgz", - "integrity": "sha512-r3Wv40in+lTsULSb6nnoudVbARdOwb2u5fpeoOAZjFLznp6tDU8kd+GTHmJoqZ9lt6/Sys33KdIHUaQihFcu7g==", - "cpu": [ - "loong64" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-musl": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.55.1.tgz", - "integrity": "sha512-MR8c0+UxAlB22Fq4R+aQSPBayvYa3+9DrwG/i1TKQXFYEaoW3B5b/rkSRIypcZDdWjWnpcvxbNaAJDcSbJU3Lw==", - "cpu": [ - "loong64" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.55.1.tgz", - "integrity": "sha512-3KhoECe1BRlSYpMTeVrD4sh2Pw2xgt4jzNSZIIPLFEsnQn9gAnZagW9+VqDqAHgm1Xc77LzJOo2LdigS5qZ+gw==", - "cpu": [ - "ppc64" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-ppc64-musl": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.55.1.tgz", - "integrity": "sha512-ziR1OuZx0vdYZZ30vueNZTg73alF59DicYrPViG0NEgDVN8/Jl87zkAPu4u6VjZST2llgEUjaiNl9JM6HH1Vdw==", - "cpu": [ - "ppc64" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.55.1.tgz", - "integrity": "sha512-uW0Y12ih2XJRERZ4jAfKamTyIHVMPQnTZcQjme2HMVDAHY4amf5u414OqNYC+x+LzRdRcnIG1YodLrrtA8xsxw==", - "cpu": [ - "riscv64" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.55.1.tgz", - "integrity": "sha512-u9yZ0jUkOED1BFrqu3BwMQoixvGHGZ+JhJNkNKY/hyoEgOwlqKb62qu+7UjbPSHYjiVy8kKJHvXKv5coH4wDeg==", - "cpu": [ - "riscv64" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.55.1.tgz", - "integrity": "sha512-/0PenBCmqM4ZUd0190j7J0UsQ/1nsi735iPRakO8iPciE7BQ495Y6msPzaOmvx0/pn+eJVVlZrNrSh4WSYLxNg==", - "cpu": [ - "s390x" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.55.1.tgz", - "integrity": "sha512-a8G4wiQxQG2BAvo+gU6XrReRRqj+pLS2NGXKm8io19goR+K8lw269eTrPkSdDTALwMmJp4th2Uh0D8J9bEV1vg==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.55.1.tgz", - "integrity": "sha512-bD+zjpFrMpP/hqkfEcnjXWHMw5BIghGisOKPj+2NaNDuVT+8Ds4mPf3XcPHuat1tz89WRL+1wbcxKY3WSbiT7w==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-openbsd-x64": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.55.1.tgz", - "integrity": "sha512-eLXw0dOiqE4QmvikfQ6yjgkg/xDM+MdU9YJuP4ySTibXU0oAvnEWXt7UDJmD4UkYialMfOGFPJnIHSe/kdzPxg==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "openbsd" - ] - }, - "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.55.1.tgz", - "integrity": "sha512-xzm44KgEP11te3S2HCSyYf5zIzWmx3n8HDCc7EE59+lTcswEWNpvMLfd9uJvVX8LCg9QWG67Xt75AuHn4vgsXw==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "openharmony" - ] + "node_modules/@rollup/plugin-json": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-6.1.0.tgz", + "integrity": "sha512-EGI2te5ENk1coGeADSIwZ7G2Q8CJS2sF120T7jLw4xFw9n7wIOXHo+kIYRAoVpJAN+kmqZSoO3Fp4JtoNF4ReA==", + "dependencies": { + "@rollup/pluginutils": "^5.1.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.55.1.tgz", - "integrity": "sha512-yR6Bl3tMC/gBok5cz/Qi0xYnVbIxGx5Fcf/ca0eB6/6JwOY+SRUcJfI0OpeTpPls7f194as62thCt/2BjxYN8g==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "win32" - ] + "node_modules/@rollup/plugin-node-resolve": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-16.0.3.tgz", + "integrity": "sha512-lUYM3UBGuM93CnMPG1YocWu7X802BrNF3jW2zny5gQyLQgRFJhV1Sq0Zi74+dh/6NBx1DxFC4b4GXg9wUCG5Qg==", + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "@types/resolve": "1.20.2", + "deepmerge": "^4.2.2", + "is-module": "^1.0.0", + "resolve": "^1.22.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.78.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.55.1.tgz", - "integrity": "sha512-3fZBidchE0eY0oFZBnekYCfg+5wAB0mbpCBuofh5mZuzIU/4jIVkbESmd2dOsFNS78b53CYv3OAtwqkZZmU5nA==", - "cpu": [ - "ia32" - ], - "optional": true, - "os": [ - "win32" - ] + "node_modules/@rollup/plugin-typescript": { + "version": "12.3.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-12.3.0.tgz", + "integrity": "sha512-7DP0/p7y3t67+NabT9f8oTBFE6gGkto4SA6Np2oudYmZE/m1dt8RB0SjL1msMxFpLo631qjRCcBlAbq1ml/Big==", + "dependencies": { + "@rollup/pluginutils": "^5.1.0", + "resolve": "^1.22.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.14.0||^3.0.0||^4.0.0", + "tslib": "*", + "typescript": ">=3.7.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + }, + "tslib": { + "optional": true + } + } }, - "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.55.1.tgz", - "integrity": "sha512-xGGY5pXj69IxKb4yv/POoocPy/qmEGhimy/FoTpTSVju3FYXUQQMFCaZZXJVidsmGxRioZAwpThl/4zX41gRKg==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ] + "node_modules/@rollup/pluginutils": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", + "integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } }, - "node_modules/@rollup/rollup-win32-x64-msvc": { + "node_modules/@rollup/rollup-darwin-arm64": { "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.55.1.tgz", - "integrity": "sha512-SPEpaL6DX4rmcXtnhdrQYgzQ5W2uW3SCJch88lB2zImhJRhIIK44fkUrgIV/Q8yUNfw5oyZ5vkeQsZLhCb06lw==", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.55.1.tgz", + "integrity": "sha512-p3grE2PHcQm2e8PSGZdzIhCKbMCw/xi9XvMPErPhwO17vxtvCN5FEA2mSLgmKlCjHGMQTP6phuQTYWUnKewwGg==", "cpu": [ - "x64" + "arm64" ], "optional": true, "os": [ - "win32" + "darwin" ] }, "node_modules/@rtsao/scc": { @@ -4679,7 +3875,6 @@ "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", "dev": true, - "license": "MIT", "peer": true }, "node_modules/@samverschueren/stream-to-observable": { @@ -4865,7 +4060,6 @@ "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true, - "license": "MIT", "peer": true }, "node_modules/@types/jsonfile": { @@ -5466,7 +4660,6 @@ "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", "dev": true, - "license": "Apache-2.0", "peer": true, "engines": { "node": ">= 0.4" @@ -5505,7 +4698,6 @@ "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz", "integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==", "dev": true, - "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.8", @@ -5538,7 +4730,6 @@ "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", "dev": true, - "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.7", @@ -5560,7 +4751,6 @@ "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz", "integrity": "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==", "dev": true, - "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.8", @@ -5600,7 +4790,6 @@ "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz", "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==", "dev": true, - "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.8", @@ -5620,7 +4809,6 @@ "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", "dev": true, - "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.7", @@ -5678,7 +4866,6 @@ "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz", "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==", "dev": true, - "license": "MIT", "peer": true }, "node_modules/async": { @@ -5746,7 +4933,6 @@ "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", "dev": true, - "license": "Apache-2.0", "peer": true, "engines": { "node": ">= 0.4" @@ -6576,7 +5762,6 @@ "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", "dev": true, - "license": "BSD-2-Clause", "peer": true }, "node_modules/data-urls": { @@ -7424,7 +6609,6 @@ "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", "dev": true, - "license": "MIT", "peer": true, "dependencies": { "debug": "^3.2.7", @@ -7437,7 +6621,6 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, - "license": "MIT", "peer": true, "dependencies": { "ms": "^2.1.1" @@ -7448,7 +6631,6 @@ "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.1.tgz", "integrity": "sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==", "dev": true, - "license": "MIT", "peer": true, "dependencies": { "debug": "^3.2.7" @@ -7467,7 +6649,6 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, - "license": "MIT", "peer": true, "dependencies": { "ms": "^2.1.1" @@ -7478,7 +6659,6 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz", "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", "dev": true, - "license": "MIT", "peer": true, "dependencies": { "@rtsao/scc": "^1.1.0", @@ -7513,7 +6693,6 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, - "license": "MIT", "peer": true, "dependencies": { "balanced-match": "^1.0.0", @@ -7525,7 +6704,6 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, - "license": "MIT", "peer": true, "dependencies": { "ms": "^2.1.1" @@ -7536,7 +6714,6 @@ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, - "license": "Apache-2.0", "peer": true, "dependencies": { "esutils": "^2.0.2" @@ -7550,7 +6727,6 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, - "license": "ISC", "peer": true, "dependencies": { "brace-expansion": "^1.1.7" @@ -7564,7 +6740,6 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, - "license": "ISC", "peer": true, "bin": { "semver": "bin/semver.js" @@ -7575,7 +6750,6 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.10.2.tgz", "integrity": "sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==", "dev": true, - "license": "MIT", "peer": true, "dependencies": { "aria-query": "^5.3.2", @@ -7606,7 +6780,6 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, - "license": "MIT", "peer": true, "dependencies": { "balanced-match": "^1.0.0", @@ -7618,7 +6791,6 @@ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", "dev": true, - "license": "MIT", "peer": true }, "node_modules/eslint-plugin-jsx-a11y/node_modules/minimatch": { @@ -7626,7 +6798,6 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, - "license": "ISC", "peer": true, "dependencies": { "brace-expansion": "^1.1.7" @@ -7640,7 +6811,6 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz", "integrity": "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==", "dev": true, - "license": "MIT", "peer": true, "dependencies": { "array-includes": "^3.1.8", @@ -7674,7 +6844,6 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz", "integrity": "sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==", "dev": true, - "license": "MIT", "peer": true, "engines": { "node": ">=10" @@ -7688,7 +6857,6 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, - "license": "MIT", "peer": true, "dependencies": { "balanced-match": "^1.0.0", @@ -7700,7 +6868,6 @@ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, - "license": "Apache-2.0", "peer": true, "dependencies": { "esutils": "^2.0.2" @@ -7714,7 +6881,6 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, - "license": "ISC", "peer": true, "dependencies": { "brace-expansion": "^1.1.7" @@ -7728,7 +6894,6 @@ "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", "dev": true, - "license": "MIT", "peer": true, "dependencies": { "is-core-module": "^2.13.0", @@ -7747,7 +6912,6 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, - "license": "ISC", "peer": true, "bin": { "semver": "bin/semver.js" @@ -7919,15 +7083,6 @@ "node": ">= 0.6" } }, - "node_modules/event-emitter": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", - "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", - "dependencies": { - "d": "1", - "es5-ext": "~0.10.14" - } - }, "node_modules/execa": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", @@ -8072,50 +7227,6 @@ "url": "https://opencollective.com/express" } }, - "node_modules/express-session": { - "version": "1.18.2", - "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.18.2.tgz", - "integrity": "sha512-SZjssGQC7TzTs9rpPDuUrR23GNZ9+2+IkA/+IJWmvQilTr5OSliEHGF+D9scbIpdC6yGtTI0/VhaHoVes2AN/A==", - "dependencies": { - "cookie": "0.7.2", - "cookie-signature": "1.0.7", - "debug": "2.6.9", - "depd": "~2.0.0", - "on-headers": "~1.1.0", - "parseurl": "~1.3.3", - "safe-buffer": "5.2.1", - "uid-safe": "~2.1.5" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/express-session/node_modules/cookie": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", - "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/express-session/node_modules/cookie-signature": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", - "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==" - }, - "node_modules/express-session/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/express-session/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, "node_modules/express-validator": { "version": "7.3.1", "resolved": "https://registry.npmjs.org/express-validator/-/express-validator-7.3.1.tgz", @@ -8229,7 +7340,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", - "license": "MIT", "dependencies": { "chardet": "^0.7.0", "iconv-lite": "^0.4.24", @@ -8242,14 +7352,12 @@ "node_modules/external-editor/node_modules/chardet": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", - "license": "MIT" + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==" }, "node_modules/external-editor/node_modules/iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3" }, @@ -8261,7 +7369,6 @@ "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "license": "MIT", "dependencies": { "os-tmpdir": "~1.0.2" }, @@ -10522,6 +9629,24 @@ "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==" }, + "node_modules/iterator.prototype": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz", + "integrity": "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==", + "dev": true, + "peer": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "get-proto": "^1.0.0", + "has-symbols": "^1.1.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/jackspeak": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.1.1.tgz", @@ -10645,7 +9770,6 @@ "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, - "license": "MIT", "peer": true, "dependencies": { "minimist": "^1.2.0" @@ -10732,7 +9856,6 @@ "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", "dev": true, - "license": "MIT", "peer": true, "dependencies": { "array-includes": "^3.1.6", @@ -10808,7 +9931,6 @@ "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz", "integrity": "sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==", "dev": true, - "license": "CC0-1.0", "peer": true }, "node_modules/language-tags": { @@ -10816,7 +9938,6 @@ "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz", "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==", "dev": true, - "license": "MIT", "peer": true, "dependencies": { "language-subtag-registry": "^0.3.20" @@ -11619,7 +10740,6 @@ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "dev": true, - "license": "MIT", "peer": true, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -11683,14 +10803,6 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, - "node_modules/mustache": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", - "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==", - "bin": { - "mustache": "bin/mustache" - } - }, "node_modules/mute-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz", @@ -14408,7 +13520,6 @@ "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", "dev": true, - "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.7", @@ -14428,7 +13539,6 @@ "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", "dev": true, - "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.7", @@ -14444,7 +13554,6 @@ "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz", "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==", "dev": true, - "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.8", @@ -14481,14 +13590,6 @@ "node": ">= 0.8" } }, - "node_modules/on-headers": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", - "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -15185,14 +14286,6 @@ } ] }, - "node_modules/random-bytes": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", - "integrity": "sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ==", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -15302,42 +14395,6 @@ "integrity": "sha512-a2kMzcfr+ntT0bObNLY22EUNV6Z6WeZ+DybRmPOUXVWzGcqhRcrK74tpgrYt3FdzTlSh85pqoryAPmrNkwLc0g==", "optional": true }, - "node_modules/recheck-linux-x64": { - "version": "4.4.5", - "resolved": "https://registry.npmjs.org/recheck-linux-x64/-/recheck-linux-x64-4.4.5.tgz", - "integrity": "sha512-s8OVPCpiSGw+tLCxH3eei7Zp2AoL22kXqLmEtWXi0AnYNwfuTjZmeLn2aQjW8qhs8ZPSkxS7uRIRTeZqR5Fv/Q==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/recheck-macos-x64": { - "version": "4.4.5", - "resolved": "https://registry.npmjs.org/recheck-macos-x64/-/recheck-macos-x64-4.4.5.tgz", - "integrity": "sha512-Ouup9JwwoKCDclt3Na8+/W2pVbt8FRpzjkDuyM32qTR2TOid1NI+P1GA6/VQAKEOjvaxgGjxhcP/WqAjN+EULA==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/recheck-windows-x64": { - "version": "4.4.5", - "resolved": "https://registry.npmjs.org/recheck-windows-x64/-/recheck-windows-x64-4.4.5.tgz", - "integrity": "sha512-mkpzLHu9G9Ztjx8HssJh9k/Xm1d1d/4OoT7etHqFk+k1NGzISCRXBD22DqYF9w8+J4QEzTAoDf8icFt0IGhOEQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ] - }, "node_modules/rechoir": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", @@ -16381,7 +15438,6 @@ "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.1.tgz", "integrity": "sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==", "dev": true, - "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.7", @@ -16397,7 +15453,6 @@ "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz", "integrity": "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==", "dev": true, - "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.8", @@ -16426,7 +15481,6 @@ "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz", "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==", "dev": true, - "license": "MIT", "peer": true, "dependencies": { "define-properties": "^1.1.3", @@ -16515,7 +15569,6 @@ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "dev": true, - "license": "MIT", "peer": true, "engines": { "node": ">=4" @@ -16779,7 +15832,6 @@ "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", "dev": true, - "license": "MIT", "peer": true, "dependencies": { "@types/json5": "^0.0.29", @@ -16983,17 +16035,6 @@ "node": ">=14.17" } }, - "node_modules/uid-safe": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz", - "integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==", - "dependencies": { - "random-bytes": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/unbox-primitive": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", diff --git a/api/package.json b/api/package.json index b518c37ec..9be372292 100644 --- a/api/package.json +++ b/api/package.json @@ -28,7 +28,7 @@ "@contentstack/cli-utilities": "^1.16.0", "@contentstack/json-rte-serializer": "^3.0.4", "@contentstack/marketplace-sdk": "^1.4.1", - "axios": "^1.12.0", + "axios": "^1.13.2", "chokidar": "^3.6.0", "cors": "^2.8.5", "dayjs": "^1.11.18", diff --git a/api/src/controllers/auth.controller.ts b/api/src/controllers/auth.controller.ts index abf01775d..b8a532313 100644 --- a/api/src/controllers/auth.controller.ts +++ b/api/src/controllers/auth.controller.ts @@ -79,14 +79,17 @@ export const getAppConfigHandler = async (req: Request, res: Response): Promise< * @param req - The request object. * @param res - The response object. */ -export const getSSOAuthStatus = async (req: Request, res: Response): Promise => { +export const getSSOAuthStatus = async ( + req: Request, + res: Response +): Promise => { try { const { userId } = req.params; if (!userId) { res.status(400).json({ error: 'Missing user ID', - message: 'User ID parameter is required' + message: 'User ID parameter is required', }); return; } @@ -98,33 +101,29 @@ export const getSSOAuthStatus = async (req: Request, res: Response): Promise { + const resp = await authService.logout(req); + res.status(resp?.status).json(resp?.data); +}; + export const authController = { login, RequestSms, saveOAuthToken, getAppConfigHandler, - getSSOAuthStatus + getSSOAuthStatus, + logout }; diff --git a/api/src/routes/auth.routes.ts b/api/src/routes/auth.routes.ts index 322243aac..fec39be37 100644 --- a/api/src/routes/auth.routes.ts +++ b/api/src/routes/auth.routes.ts @@ -66,4 +66,11 @@ router.get('/app-config', authController.getAppConfigHandler); */ router.get('/sso-status/:userId', authController.getSSOAuthStatus); +/** + * @route POST /v2/auth/logout + * @desc Log out a user + * @access Public + */ +router.post('/logout', authController.logout); + export default router; diff --git a/api/src/services/auth.service.ts b/api/src/services/auth.service.ts index 3310e3854..cd9ea7075 100644 --- a/api/src/services/auth.service.ts +++ b/api/src/services/auth.service.ts @@ -15,6 +15,7 @@ import logger from "../utils/logger.js"; import path from "path"; import fs from "fs"; import axios from "axios"; +import { getAppOrganizationUID } from "../utils/auth.utils.js"; // import { createHash, randomBytes } from 'crypto'; /** @@ -128,6 +129,62 @@ const login = async (req: Request): Promise => { } }; +/** + * Logs out a user by removing their authentication data from the database. + * @param req - Express Request object containing user_id in the decoded token + * @returns Success response with logout confirmation + */ +const logout = async (req: Request): Promise => { + const srcFun = "Logout"; + try { + const userEmail = (req as any)?.body?.email; + + if (!userEmail) { + throw new BadRequestError("User not found in request"); + } + await AuthenticationModel.read(); + const userRecord = AuthenticationModel.chain + .get("users") + .find({ email: userEmail }) + .value(); + + if (!userRecord) { + logger.warn( + getLogMessage(srcFun, "User not found in database", { userEmail }, {}) + ); + throw new BadRequestError(HTTP_TEXTS.NO_CS_USER); + } + // Remove the user from the database + AuthenticationModel.update((data: any) => { + data.users = data.users.filter((user: any) => user.email !== userEmail); + }); + + logger.info( + getLogMessage( + srcFun, + "User logged out successfully", + { userEmail }, + {} + ) + ); + + return { + data: { + message: "Logged out successfully", + }, + status: HTTP_CODES.OK, + }; + } catch (error: any) { + logger.error( + getLogMessage(srcFun, "Error while logging out", {}, error) + ); + throw new ExceptionFunction( + error?.message || HTTP_TEXTS.INTERNAL_ERROR, + error?.statusCode || error?.status || HTTP_CODES.SERVER_ERROR + ); + } +}; + /** * Sends a request for SMS login token. (No changes needed here) */ @@ -369,6 +426,10 @@ export const getAppData = async () => { const appConfigData = fs.readFileSync(appConfigPath, 'utf8'); const appConfig: any = JSON.parse(appConfigData); + if(appConfig?.isDefault === true) { + throw new Error('SSO is not configured. Please run the setup script first.'); + } + return appConfig; } catch (error: any) { @@ -390,46 +451,69 @@ export const getAppData = async () => { export const checkSSOAuthStatus = async (userId: string) => { try { await AuthenticationModel.read(); - const userRecord = AuthenticationModel.chain.get("users").find({ user_id: userId }).value(); - + + const userRecord = AuthenticationModel + .chain + .get('users') + .find({ user_id: userId }) + .value(); + if (!userRecord || !userRecord?.access_token) { - throw new Error('SSO authentication not completed'); + return { + authenticated: false, + message: 'SSO authentication not completed' + }; } - // Only consider tokens created in the last 10 minutes as "fresh" - const tokenAge = new Date()?.getTime() - new Date(userRecord?.updated_at)?.getTime(); - const maxTokenAge = 10 * 60 * 1000; // 10 minutes in milliseconds - - if (tokenAge > maxTokenAge) { - throw new Error('SSO authentication not completed'); + if (!userRecord?.organization_uid) { + return { + authenticated: false, + message: 'Organization not linked to user' + }; } - // Token is fresh, proceed with authentication - const appTokenPayload = { - region: userRecord?.region, + const appOrgUID = getAppOrganizationUID(); + + if (userRecord.organization_uid !== appOrgUID) { + return { + authenticated: false, + message: 'Organization mismatch' + }; + } + + const tokenAge = + Date.now() - new Date(userRecord.updated_at).getTime(); + + if (tokenAge > 10 * 60 * 1000) { + return { + authenticated: false, + message: 'SSO authentication expired' + }; + } + + const appToken = generateToken({ + region: userRecord.region, user_id: userRecord.user_id, is_sso: true, - }; - - const appToken = generateToken(appTokenPayload); - + }); + return { authenticated: true, message: 'SSO authentication successful', app_token: appToken, user: { - email: userRecord?.email, - uid: userRecord?.user_id, - region: userRecord?.region, - organization_uid: userRecord?.organization_uid + email: userRecord.email, + uid: userRecord.user_id, + region: userRecord.region, + organization_uid: userRecord.organization_uid } }; } catch (error: any) { - if (error?.message?.includes('SSO authentication not completed')) { - throw error; - } - throw new Error(`Failed to check SSO authentication status: ${error?.message}`); + logger.error('SSO status check failed', error); + throw new Error( + `Failed to check SSO authentication status: ${error?.message}` + ); } }; @@ -439,5 +523,6 @@ export const authService = { saveOAuthToken, refreshOAuthToken, getAppData, - checkSSOAuthStatus + checkSSOAuthStatus, + logout }; \ No newline at end of file diff --git a/api/src/services/user.service.ts b/api/src/services/user.service.ts index 53f1333ce..add26c492 100644 --- a/api/src/services/user.service.ts +++ b/api/src/services/user.service.ts @@ -10,6 +10,7 @@ import { import AuthenticationModel from "../models/authentication.js"; import { safePromise, getLogMessage } from "../utils/index.js"; import logger from "../utils/logger.js"; +import { getAppOrganization } from "../utils/auth.utils.js"; /** * Retrieves the user profile based on the provided request. @@ -29,21 +30,67 @@ const getUserProfile = async (req: Request): Promise => { .findIndex({ user_id: appTokenPayload?.user_id, region: appTokenPayload?.region, + is_sso: appTokenPayload?.is_sso, }) .value(); if (userIndex < 0) throw new BadRequestError(HTTP_TEXTS.NO_CS_USER); + const { uid: org_uid, name: org_name } = getAppOrganization(); + const userRecord = AuthenticationModel.data.users[userIndex]; + if (appTokenPayload.is_sso === true) { + if (!userRecord?.access_token) { + throw new BadRequestError("SSO authentication not completed"); + } - const userRecord = AuthenticationModel?.data?.users[userIndex]; - let headers: any = { - "Content-Type": "application/json", - }; - if (appTokenPayload?.is_sso) { - headers.authorization = `Bearer ${userRecord?.access_token}`; - } else if (appTokenPayload?.is_sso === false) { - headers.authtoken = userRecord?.authtoken; - } else { - throw new BadRequestError("No valid authentication token found or mismatch in is_sso flag"); + const [err, res] = await safePromise( + https({ + method: "GET", + url: `${config.CS_API[ + appTokenPayload?.region as keyof typeof config.CS_API + ]!}/user?include_orgs_roles=true`, + headers: { + authorization: `Bearer ${userRecord?.access_token}`, + "Content-Type": "application/json", + }, + }) + ); + + if (err) { + logger.error( + getLogMessage( + srcFun, + HTTP_TEXTS.CS_ERROR, + appTokenPayload, + err.response.data + ) + ); + return { data: err.response.data, status: err.response.status }; + } + + if ( + !res?.data?.user?.organizations?.some( + (org: any) => org.uid === org_uid + ) + ) { + throw new BadRequestError("Organization access revoked"); + } + + return { + data: { + user: { + email: res?.data?.user?.email, + first_name: res?.data?.user?.first_name, + last_name: res?.data?.user?.last_name, + orgs: [ + { + org_id: org_uid, + org_name: org_name, + }, + ], + }, + }, + status: res?.status, + }; } const [err, res] = await safePromise( @@ -52,7 +99,10 @@ const getUserProfile = async (req: Request): Promise => { url: `${config.CS_API[ appTokenPayload?.region as keyof typeof config.CS_API ]!}/user?include_orgs_roles=true`, - headers: headers, + headers: { + authtoken: userRecord?.authtoken, + "Content-Type": "application/json", + }, }) ); @@ -72,36 +122,35 @@ const getUserProfile = async (req: Request): Promise => { }; } - if (!res?.data?.user) throw new BadRequestError(HTTP_TEXTS.NO_CS_USER); - - const orgs = (res?.data?.user?.organizations || []) - ?.filter((org: any) => org?.org_roles?.some((item: any) => item?.admin)) - ?.map(({ uid, name }: any) => ({ org_id: uid, org_name: name })); + const adminOrgs = res?.data?.user?.organizations + ?.filter((org: any) => + org?.org_roles?.some((r: any) => r?.admin) + ) + ?.map(({ uid, name }: any) => ({ + org_id: uid, + org_name: name, + })) || []; - const ownerOrgs = (res?.data?.user?.organizations || [])?.filter((org:any)=> org?.is_owner) - ?.map(({ uid, name }: any) => ({ org_id: uid, org_name: name })); + const ownerOrgs = res?.data?.user?.organizations + ?.filter((org: any) => org?.is_owner) + ?.map(({ uid, name }: any) => ({ + org_id: uid, + org_name: name, + })) || []; - const allOrgs = [...orgs, ...ownerOrgs] return { data: { user: { email: res?.data?.user?.email, first_name: res?.data?.user?.first_name, last_name: res?.data?.user?.last_name, - orgs: allOrgs, + orgs: [...adminOrgs, ...ownerOrgs], }, }, status: res?.status, }; } catch (error: any) { - logger.error( - getLogMessage( - srcFun, - "Error while getting user profile", - appTokenPayload, - error - ) - ); + logger.error(getLogMessage(srcFun, "Error while getting user profile", appTokenPayload, error)); throw new ExceptionFunction( error?.message || HTTP_TEXTS.INTERNAL_ERROR, error?.statusCode || error?.status || HTTP_CODES.SERVER_ERROR @@ -111,4 +160,4 @@ const getUserProfile = async (req: Request): Promise => { export const userService = { getUserProfile, -}; +}; \ No newline at end of file diff --git a/api/src/utils/auth.utils.ts b/api/src/utils/auth.utils.ts index 1d933ba0f..886fb2a84 100644 --- a/api/src/utils/auth.utils.ts +++ b/api/src/utils/auth.utils.ts @@ -1,5 +1,8 @@ import AuthenticationModel from "../models/authentication.js"; import { UnauthorizedError } from "../utils/custom-errors.utils.js"; +// CommonJS-safe JSON loading +// eslint-disable-next-line @typescript-eslint/no-var-requires +import appConfig from "../../../app.json" /** * Retrieves the authentication token for a given user in a specific region. @@ -12,10 +15,7 @@ export default async (region: string, userId: string) => { await AuthenticationModel.read(); const userIndex = AuthenticationModel.chain .get("users") - .findIndex({ - region: region, - user_id: userId, - }) + .findIndex({ region, user_id: userId }) .value(); const authToken = AuthenticationModel.data.users[userIndex]?.authtoken; @@ -30,10 +30,7 @@ export const getAccessToken = async (region: string, userId: string) => { await AuthenticationModel.read(); const userIndex = AuthenticationModel.chain .get("users") - ?.findIndex({ - region: region, - user_id: userId, - }) + ?.findIndex({ region, user_id: userId }) ?.value(); const accessToken = AuthenticationModel.data.users[userIndex]?.access_token; @@ -41,4 +38,35 @@ export const getAccessToken = async (region: string, userId: string) => { if (userIndex < 0 || !accessToken) throw new UnauthorizedError(); return accessToken; +}; + +export const getAppOrganizationUID = (): string => { + const uid = appConfig?.organization?.uid; + + if (!uid) { + throw new Error("Organization UID not found in app.json"); + } + + return uid; +}; + +export const getAppOrganization = () => { + const org = appConfig?.organization; + + if (!org?.uid || !org?.name) { + throw new Error("Organization details not found in app.json"); + } + + return { + uid: org?.uid, + name: org?.name, + }; +}; + +export const getAppConfig = () => { + if (!appConfig?.oauthData) { + throw new Error("SSO is not configured. Missing oauthData in app.json"); + } + + return appConfig; }; \ No newline at end of file diff --git a/api/sso.utils.js b/api/sso.utils.js index 2a1c2b600..741d56d3c 100644 --- a/api/sso.utils.js +++ b/api/sso.utils.js @@ -302,6 +302,7 @@ module.exports = async ({ code_challenge: code_challenge, }, authUrl: authUrl, + isDefault: false, }; fs.writeFileSync("app.json", JSON.stringify(appData, null, 2)); diff --git a/app.json b/app.json new file mode 100644 index 000000000..d45912af0 --- /dev/null +++ b/app.json @@ -0,0 +1,187 @@ +{ + "timestamp": "2026-01-09T08:35:28.575Z", + "region": { + "key": "NA", + "name": "North America", + "endpoints": { + "name": "North America", + "cma": "https://api.contentstack.io", + "cda": "https://cdn.contentstack.io", + "app": "https://app.contentstack.com", + "developerHub": "https://developerhub-api.contentstack.com", + "personalize": "https://personalize-api.contentstack.com", + "launch": "https://launch-api.contentstack.com" + } + }, + "user": { + "email": "shobhit.upadhyay@contentstack.com", + "uid": "bltf56d4d5438c9db89" + }, + "organization": { + "name": "TSO Playground", + "uid": "blt364e72a5e260a11d" + }, + "app": { + "name": "Migration Tool", + "uid": "689ad8516e9f420012a72fce", + "manifest": "Migration Tool" + }, + "oauthData": { + "client_id": "AAOuqJu_1z5wFLwM", + "client_secret": "11S3mkDtBukROD7x58CvLKV87P9fyIyf", + "redirect_uri": "http://localhost:5001/v2/auth/save-token", + "user_token_config": { + "enabled": true, + "scopes": [ + "app.manifests:read", + "app.manifest:read", + "app.manifest:write", + "app.hosting:read", + "app.hosting:write", + "app.installations:read", + "app.installations.management:read", + "app.installations.management:write", + "app.authorizations:manage", + "app.authorizations.management:write", + "app.requests:write", + "app.requests.management:write", + "user.profile:read", + "user:read", + "user:write", + "user.tfa:write", + "user.assignments:read", + "user.assignments:write", + "user.notifications:read", + "user.notifications:write", + "organizations:read", + "organization:read", + "organization.roles:read", + "organization.share:read", + "organization.share:write", + "organization.logs:read", + "organization.usage:read", + "organization.jobs:read", + "organization.jobs:write", + "cm.stacks.management:read", + "cm.stacks.management:write", + "cm.stack.management:read", + "cm.stack.management:write", + "cm.stack.settings:read", + "cm.stack.settings:write", + "cm.stack:share", + "cm.stack:unshare", + "cm.stack.users:read", + "cm.stack.users:write", + "cm.stack.delivery-tokens:read", + "cm.stack.delivery-tokens:write", + "cm.stack.management-tokens:read", + "cm.stack.management-tokens:write", + "cm.content-types.management:read", + "cm.content-types.management:write", + "cm.content-types:import", + "cm.content-types:export", + "cm.content-type:read", + "cm.content-type:write", + "cm.content-type:copy", + "cm.global-fields.management:read", + "cm.global-fields.management:write", + "cm.global-fields:import", + "cm.global-fields:export", + "cm.entries.management:read", + "cm.entries.management:write", + "cm.entries:import", + "cm.entries:export", + "cm.entry:read", + "cm.entry:write", + "cm.entry:publish", + "cm.entry:unpublish", + "cm.entry.workflow:write", + "cm.webhooks.management:read", + "cm.webhooks.management:write", + "cm.webhooks:import", + "cm.webhooks:export", + "cm.webhook:read", + "cm.webhook:write", + "cm.assets.management:read", + "cm.assets.management:write", + "cm.assets.rt:read", + "cm.assets.rt:write", + "cm.assets:download", + "cm.asset:read", + "cm.asset:write", + "cm.asset:publish", + "cm.asset:unpublish", + "cm.workflows.management:read", + "cm.workflows.management:write", + "cm.workflows.publishing-rules:read", + "cm.workflows.publishing-rules:write", + "cm.environments.management:read", + "cm.environments.management:write", + "cm.extensions.management:read", + "cm.extensions.management:write", + "cm.languages.management:read", + "cm.languages.management:write", + "cm.labels.management:read", + "cm.labels.management:write", + "cm.bulk-operations:publish", + "cm.bulk-operations:unpublish", + "cm.bulk-operations:add-to-release", + "cm.bulk-operations:delete", + "cm.bulk-operations:move-to-folder", + "cm.bulk-operations:workflow", + "cm.releases.management:read", + "cm.releases.management:write", + "cm.release:read", + "cm.release:write", + "cm.release:clone", + "cm.release:deploy", + "cm.roles.management:read", + "cm.roles.management:write", + "cm.audit-logs:read", + "personalize:read", + "personalize:manage", + "cm.publish-queue.management:read", + "cm.publish-queue.management:write", + "cm.taxonomies.management:read", + "cm.taxonomies.management:write", + "cm.taxonomy.terms:read", + "cm.taxonomy.terms:write", + "cm.branches.management:read", + "cm.branches.management:write", + "cm.branches:compare-merge", + "cm.branch-aliases.management:read", + "cm.branch-aliases.management:write", + "launch:manage", + "launch.gitproviders:manage", + "automationhub.projects.management:read", + "automationhub.projects.management:write", + "automationhub.automations:read", + "automationhub.automations:write", + "automationhub.executions:read", + "automationhub.audit-logs:read", + "automationhub.variables:read", + "automationhub.variables:write", + "automationhub.accounts:read", + "brand-kits:read", + "brand-kits:manage", + "cm.variant:read", + "cm.variant:write", + "analytics:read", + "auditlogs:read", + "teams:read", + "teams:write" + ], + "allow_pkce": true + }, + "app_token_config": { + "enabled": false, + "scopes": [] + } + }, + "pkce": { + "code_verifier": "d1f52bd6c05002619cd0d866d5a850b47a96386d03e4005d0a321fa545abf7a6", + "code_challenge": "xHzGXAOcIdfPEKyPbYpiadUHKczSgx8j6dCJnFM8DKE" + }, + "authUrl": "https://app.contentstack.com/#!/apps/689ad8516e9f420012a72fce/authorize?response_type=code&client_id=AAOuqJu_1z5wFLwM&redirect_uri=http%3A%2F%2Flocalhost%3A5001%2Fv2%2Fauth%2Fsave-token&code_challenge=xHzGXAOcIdfPEKyPbYpiadUHKczSgx8j6dCJnFM8DKE&code_challenge_method=S256", + "isDefault": false +} \ No newline at end of file diff --git a/ui/src/components/ProfileHeader/index.tsx b/ui/src/components/ProfileHeader/index.tsx index 8452bd418..cbc61f763 100644 --- a/ui/src/components/ProfileHeader/index.tsx +++ b/ui/src/components/ProfileHeader/index.tsx @@ -7,44 +7,68 @@ import { clearLocalStorage } from '../../utilities/functions'; // Styles import './index.scss'; import { LOG_OUT } from '../../common/assets'; +import { logout } from '../../services/api/login.service'; +import { useState } from 'react'; + const ProfileCard = () => { const user = useSelector((state: RootState) => state?.authentication?.user); const name = `${user?.first_name?.charAt(0)}${user?.last_name?.charAt(0)}`.toUpperCase() ?? ''; const navigate = useNavigate(); - // Function for Logout - const handleLogout = () => { - if (clearLocalStorage()) { - navigate('/', { replace: true }); + const [isLoggingOut, setIsLoggingOut] = useState(false); + + const handleLogout = async () => { + if (isLoggingOut) return; // Prevent multiple clicks + + setIsLoggingOut(true); + + try { + const response = await logout(user?.email as string); + + if (response?.status !== 200) { + console.error('Backend logout failed:', response?.data); + } + } catch (error) { + console.error('Error during logout:', error); + } finally { + if (clearLocalStorage()) { + navigate('/', { replace: true }); + } + setIsLoggingOut(false); } }; + return (
-
-
-
{name}
+
+
{name}
-
+
{user?.first_name} {user?.last_name}
{user?.email}
- -
Region: {user?.region?.replaceAll('_', '-')}
-
+
+ Region: {user?.region?.replaceAll('_', '-')} +
{ if (event.key === 'Enter' || event.key === ' ') { handleLogout(); } }} + style={{ + opacity: isLoggingOut ? 0.6 : 1, + cursor: isLoggingOut ? 'not-allowed' : 'pointer', + pointerEvents: isLoggingOut ? 'none' : 'auto' + }} > - {LOG_OUT} - Log out + {LOG_OUT} + {isLoggingOut ? 'Logging out...' : 'Log out'}
); diff --git a/ui/src/pages/Login/index.tsx b/ui/src/pages/Login/index.tsx index 921736b66..3610cf0ae 100644 --- a/ui/src/pages/Login/index.tsx +++ b/ui/src/pages/Login/index.tsx @@ -252,22 +252,29 @@ const Login: FC = () => { } if (res?.status === 400) { - failtureNotification('Something went wrong please try normal login method'); + failtureNotification('Invalid SSO configuration. Please try again.'); setIsLoading(false); return; } if (res?.status === 500) { - failtureNotification('Something went wrong please try normal login method'); + failtureNotification('Kindly setup the SSO first'); setIsLoading(false); return; } const appConfig = res?.data; + + console.info('appConfig', appConfig); + if (appConfig?.isDefault) { + failtureNotification('SSO is not configured. Please run the setup script first.'); + setIsLoading(false); + return; + } // Check if authUrl exists if (!appConfig?.authUrl) { - failtureNotification('Something went wrong please try normal login method'); + failtureNotification('Invalid Auth URL. Please try again.'); setIsLoading(false); return; } @@ -367,40 +374,47 @@ const Login: FC = () => { }; - const handleSuccessfulSSOLogin = (authData: any) => { - + const handleSuccessfulSSOLogin = async (authData: any) => { try { setIsLoading(false); - - setDataInLocalStorage('app_token', authData?.app_token); - - localStorage?.removeItem('organization'); + + if (!authData?.app_token) { + throw new Error("Missing app token"); + } + + // 1️⃣ Store token FIRST + setDataInLocalStorage('app_token', authData.app_token); + + localStorage.removeItem('organization'); dispatch(clearOrganisationData()); - - - const authenticationObj = { - authToken: authData?.app_token, + + // 2️⃣ Update redux auth + dispatch(setAuthToken({ + authToken: authData.app_token, isAuthenticated: true - }; - - const userObj = { + })); + + dispatch(setUser({ ...user, - region: region - }; - - dispatch(setUser(userObj)); - dispatch(setAuthToken(authenticationObj)); - setLoginStates((prev) => ({ ...prev, submitted: true })); - - dispatch(getUserDetails()); - - navigate(`/projects`, { replace: true }); - + region, + is_sso: true + })); + + // 3️⃣ WAIT for user hydration + await dispatch(getUserDetails()).unwrap(); + + setLoginStates(prev => ({ ...prev, submitted: true })); + + // 4️⃣ Navigate LAST + navigate('/projects', { replace: true }); + } catch (error) { console.error('Error processing SSO login success:', error); - failtureNotification('Login successful but navigation failed. Please refresh the page.'); + failtureNotification( + 'Login successful but setup failed. Please refresh.' + ); } - }; + }; // useEffect(()=>{ // const handlePopState = (event: PopStateEvent) => { diff --git a/ui/src/services/api/login.service.ts b/ui/src/services/api/login.service.ts index fe9be1a20..9363dc0f8 100644 --- a/ui/src/services/api/login.service.ts +++ b/ui/src/services/api/login.service.ts @@ -49,4 +49,16 @@ export const checkSSOAuthStatus = (userId: string) => { throw new Error('Unknown error in checkSSOAuthStatus'); } } +}; + +export const logout = (email: string) => { + try { + return postCall(`${AUTH_ROUTES}/logout`, { email }); + } catch (error) { + if (error instanceof Error) { + throw new Error(`Error in logout: ${error.message}`); + } else { + throw new Error('Unknown error in logout'); + } + } }; \ No newline at end of file From 89cddec3c88c62e692cd40590349d58d41face77 Mon Sep 17 00:00:00 2001 From: shobhitupadhyayy Date: Tue, 20 Jan 2026 14:52:49 +0530 Subject: [PATCH 9/9] chore: update .gitignore files to include app.json and manifest.json - Added app.json to the main .gitignore to prevent tracking of configuration files. - Included manifest.json in the api/.gitignore to exclude it from version control. --- .gitignore | 3 +++ api/.gitignore | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 04c03ec21..324af1bcf 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,9 @@ # Mono auto generated files mono_crash.* +# App JSON file +app.json + # Build results [Dd]ebug/ [Dd]ebugPublic/ diff --git a/api/.gitignore b/api/.gitignore index a3563aa2f..736178335 100644 --- a/api/.gitignore +++ b/api/.gitignore @@ -366,4 +366,5 @@ database/ /cmsMigrationData /migration-data **/copy* -**copy.ts \ No newline at end of file +**copy.ts +manifest.json \ No newline at end of file