From d104ea5b9bb518dccbf3439aea43c3bc009f8b9f Mon Sep 17 00:00:00 2001 From: shobhit upadhyay Date: Thu, 4 Sep 2025 13:08:51 +0530 Subject: [PATCH 01/11] 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 0f4be77c2..7307e895b 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", @@ -3583,6 +3584,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", @@ -3678,6 +3684,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", @@ -4239,7 +4253,7 @@ "yarn": "^1.22.22" }, "engines": { - "node": ">=18.0.0" + "node": ">=14" } }, "node_modules/@otplib/core": { @@ -4839,6 +4853,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", @@ -4874,8 +4897,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", @@ -5372,6 +5394,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", @@ -6027,6 +6062,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", @@ -6055,6 +6095,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", @@ -6361,11 +6406,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", @@ -6656,6 +6730,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", @@ -7176,11 +7262,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", @@ -7874,6 +8008,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", @@ -7956,6 +8104,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", @@ -8100,6 +8257,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", @@ -8307,6 +8508,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", @@ -8464,6 +8670,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", @@ -8628,6 +8872,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", @@ -9226,6 +9487,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", @@ -9295,6 +9561,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", @@ -10421,6 +10701,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", @@ -10605,6 +10894,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", @@ -11061,6 +11358,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", @@ -11432,6 +11734,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", @@ -11514,6 +11834,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", @@ -11605,6 +11936,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", @@ -11627,6 +11966,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", @@ -11657,6 +12001,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", @@ -11676,6 +12044,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", @@ -14395,6 +14774,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", @@ -14449,6 +14836,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", @@ -15072,6 +15464,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", @@ -15091,6 +15491,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", @@ -15288,6 +15696,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", @@ -15324,6 +15740,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", @@ -16484,6 +16908,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", @@ -16566,6 +17016,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", @@ -16670,6 +17132,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", @@ -16902,6 +17369,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", @@ -17019,6 +17497,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", @@ -17062,6 +17572,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", @@ -17093,6 +17611,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 96a8807fa9ba2739f0991ad5bc0df36f6a29bf4e Mon Sep 17 00:00:00 2001 From: shobhit upadhyay Date: Thu, 4 Sep 2025 15:28:28 +0530 Subject: [PATCH 02/11] 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 2f4272ca6d8f8a7e0132f8f3136cf79dae0bd868 Mon Sep 17 00:00:00 2001 From: shobhit upadhyay Date: Mon, 8 Sep 2025 10:46:12 +0530 Subject: [PATCH 03/11] 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 e7f5597e15225a9ddc7e446c50ebd315b95d3d73 Mon Sep 17 00:00:00 2001 From: shobhit upadhyay Date: Mon, 29 Sep 2025 14:27:03 +0530 Subject: [PATCH 04/11] 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 7307e895b..801e67e22 100644 --- a/api/package-lock.json +++ b/api/package-lock.json @@ -3584,11 +3584,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", @@ -3684,14 +3679,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", @@ -4897,7 +4884,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", @@ -5394,19 +5382,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", @@ -6062,11 +6037,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", @@ -6095,11 +6065,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", @@ -6406,40 +6371,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", @@ -6730,18 +6666,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", @@ -7262,59 +7186,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", @@ -8008,20 +7884,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", @@ -8508,11 +8370,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", @@ -8670,44 +8527,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", @@ -8872,23 +8691,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", @@ -9487,11 +9289,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", @@ -9561,20 +9358,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", @@ -10701,15 +10484,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", @@ -10894,14 +10668,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", @@ -11358,11 +11124,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", @@ -11734,24 +11495,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", @@ -11834,17 +11577,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", @@ -11966,11 +11698,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", @@ -12001,30 +11728,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", @@ -12044,17 +11747,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", @@ -14836,11 +14528,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", @@ -15464,14 +15151,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", @@ -15696,14 +15375,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", @@ -15740,14 +15411,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", @@ -16908,32 +16571,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", @@ -17016,18 +16653,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", @@ -17132,11 +16757,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", @@ -17497,38 +17117,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", @@ -17572,14 +17160,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", @@ -17611,11 +17191,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 dc8f6b005..b1b71b249 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 da41938b2e27618b851ff5388d3730bfae20cf44 Mon Sep 17 00:00:00 2001 From: shobhit upadhyay Date: Mon, 29 Sep 2025 14:28:36 +0530 Subject: [PATCH 05/11] 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 9c7ff250d9e7d6fc1ad17a5c7210a03ece8d6ae4 Mon Sep 17 00:00:00 2001 From: shobhit upadhyay Date: Tue, 30 Sep 2025 11:47:09 +0530 Subject: [PATCH 06/11] 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 b1b71b249..11f1a0972 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 96e52bbe28428f86c3fabd6bd9ec92ba2592b020 Mon Sep 17 00:00:00 2001 From: shobhit upadhyay Date: Tue, 30 Sep 2025 15:16:09 +0530 Subject: [PATCH 07/11] 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 11f1a0972..806d2f06a 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 8fb61c28b258cc69eadaa10fa06af95d3a6dc9e7 Mon Sep 17 00:00:00 2001 From: shobhitupadhyayy Date: Tue, 20 Jan 2026 12:46:17 +0530 Subject: [PATCH 08/11] 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 | 1583 ++++----------------- 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, 1006 insertions(+), 1405 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 801e67e22..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", @@ -127,33 +127,33 @@ } }, "node_modules/@contentstack/cli": { - "version": "1.55.0", - "resolved": "https://registry.npmjs.org/@contentstack/cli/-/cli-1.55.0.tgz", - "integrity": "sha512-nUPT9keZWHIX1cGkm01SqglzGtPH760L4DolUcZ2XjeEl+h/jSvpZSk6EBcoC+fH6glPbXMmtPzOe8Z/ORx3RQ==", - "dependencies": { - "@contentstack/cli-audit": "~1.17.0", - "@contentstack/cli-auth": "~1.7.0", - "@contentstack/cli-cm-bootstrap": "~1.18.0", - "@contentstack/cli-cm-branches": "~1.6.2", - "@contentstack/cli-cm-bulk-publish": "~1.10.5", - "@contentstack/cli-cm-clone": "~1.19.0", - "@contentstack/cli-cm-export": "~1.23.0", - "@contentstack/cli-cm-export-to-csv": "~1.10.2", - "@contentstack/cli-cm-import": "~1.31.0", - "@contentstack/cli-cm-import-setup": "~1.7.2", - "@contentstack/cli-cm-migrate-rte": "~1.6.3", - "@contentstack/cli-cm-seed": "~1.14.0", - "@contentstack/cli-command": "~1.7.1", - "@contentstack/cli-config": "~1.17.0", + "version": "1.53.1", + "resolved": "https://registry.npmjs.org/@contentstack/cli/-/cli-1.53.1.tgz", + "integrity": "sha512-X31Gz3kB/UNPwPAGju1xXD8D85aH12ALNXOcwf6vuUg1r0xH3IpYSGM2tLNm2T9HR94UhZJmg/xPh/iVm0QOUA==", + "dependencies": { + "@contentstack/cli-audit": "~1.16.1", + "@contentstack/cli-auth": "~1.6.2", + "@contentstack/cli-cm-bootstrap": "~1.17.1", + "@contentstack/cli-cm-branches": "~1.6.1", + "@contentstack/cli-cm-bulk-publish": "~1.10.3", + "@contentstack/cli-cm-clone": "~1.18.0", + "@contentstack/cli-cm-export": "~1.22.1", + "@contentstack/cli-cm-export-to-csv": "~1.10.1", + "@contentstack/cli-cm-import": "~1.30.1", + "@contentstack/cli-cm-import-setup": "~1.7.1", + "@contentstack/cli-cm-migrate-rte": "~1.6.2", + "@contentstack/cli-cm-seed": "~1.13.1", + "@contentstack/cli-command": "~1.7.0", + "@contentstack/cli-config": "~1.16.1", "@contentstack/cli-launch": "^1.9.2", - "@contentstack/cli-migration": "~1.10.2", - "@contentstack/cli-utilities": "~1.16.0", - "@contentstack/cli-variants": "~1.3.6", + "@contentstack/cli-migration": "~1.10.1", + "@contentstack/cli-utilities": "~1.15.0", + "@contentstack/cli-variants": "~1.3.5", "@contentstack/management": "~1.22.0", "@oclif/core": "^4.3.0", "@oclif/plugin-help": "^6.2.28", "@oclif/plugin-not-found": "^3.2.53", - "@oclif/plugin-plugins": "^5.4.54", + "@oclif/plugin-plugins": "^5.4.38", "chalk": "^4.1.2", "debug": "^4.4.1", "figlet": "1.8.1", @@ -173,12 +173,12 @@ } }, "node_modules/@contentstack/cli-audit": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/@contentstack/cli-audit/-/cli-audit-1.17.0.tgz", - "integrity": "sha512-JusFlWsabUEwm3eifX7P90kWCKZxipHcyM/k7haiYXCL5NquQQjYlYfPiNQBvk8t3CnYkCVngVNM1uagqXW2eA==", + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/@contentstack/cli-audit/-/cli-audit-1.16.1.tgz", + "integrity": "sha512-CRe92i7op3RlD5JQu+PY+KelITaTAb3lX22M//Cz7GzW356HyDTNtWydO5MOkPCTt6OkLNz0I9zYY2SPNCRAsw==", "dependencies": { - "@contentstack/cli-command": "~1.7.1", - "@contentstack/cli-utilities": "~1.16.0", + "@contentstack/cli-command": "~1.7.0", + "@contentstack/cli-utilities": "~1.15.0", "@oclif/core": "^4.3.0", "@oclif/plugin-help": "^6.2.28", "@oclif/plugin-plugins": "^5.4.54", @@ -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", @@ -310,12 +303,12 @@ } }, "node_modules/@contentstack/cli-auth": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@contentstack/cli-auth/-/cli-auth-1.7.0.tgz", - "integrity": "sha512-33gwkZMvz7LE7Zj3avltxGXuskxeX8x4izJR2Z6oN4dHeQ1HXpjgglo//5Rsh8Crd99YgBcfxbZyKXR2dQ/YWA==", + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/@contentstack/cli-auth/-/cli-auth-1.6.2.tgz", + "integrity": "sha512-iPqEwgXBI7qWYA7beEBZm5LTbYplTw5VfSBzBLXTdkM6NMshpVCG4ybQJgddfKwQSaLmq86TbxHyTOLaWAcmjw==", "dependencies": { - "@contentstack/cli-command": "~1.7.1", - "@contentstack/cli-utilities": "~1.16.0", + "@contentstack/cli-command": "~1.6.1", + "@contentstack/cli-utilities": "~1.15.0", "@oclif/core": "^4.3.0", "@oclif/plugin-help": "^6.2.28", "otplib": "^12.0.1" @@ -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", @@ -452,13 +438,13 @@ } }, "node_modules/@contentstack/cli-cm-bootstrap": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/@contentstack/cli-cm-bootstrap/-/cli-cm-bootstrap-1.18.0.tgz", - "integrity": "sha512-3o8Q9DeKcisEhJhbkD4DIPEsVf9BVkDHYSQYDVxFw8mdW89twecJz5ofdTEedU1/LwaQTvg8YOEwCAgr3cjiZA==", + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/@contentstack/cli-cm-bootstrap/-/cli-cm-bootstrap-1.17.1.tgz", + "integrity": "sha512-afXMAE813fJAO3mA5xJysauMYBdMcpcDbjrl4xfKrspyclIS6eupvUhRBavPZFkuhRLnGRRqAUenkhf6IB8Hkw==", "dependencies": { - "@contentstack/cli-cm-seed": "~1.14.0", - "@contentstack/cli-command": "~1.7.1", - "@contentstack/cli-utilities": "~1.16.0", + "@contentstack/cli-cm-seed": "~1.13.1", + "@contentstack/cli-command": "~1.7.0", + "@contentstack/cli-utilities": "~1.15.0", "@oclif/core": "^4.3.0", "@oclif/plugin-help": "^6.2.28", "inquirer": "8.2.7", @@ -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", @@ -582,12 +562,12 @@ } }, "node_modules/@contentstack/cli-cm-branches": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/@contentstack/cli-cm-branches/-/cli-cm-branches-1.6.2.tgz", - "integrity": "sha512-cI6dbVMBJRJJKFgNNBjFdvx21i8PKwmpiRStB6SncVP1wVQIiMSX4p7Fee487YrLG2dm/3Fl7NfOPGqp/vlpXg==", + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@contentstack/cli-cm-branches/-/cli-cm-branches-1.6.1.tgz", + "integrity": "sha512-GxgtsLNDvinc4scNlNWotd1tmL0AKyHfDxz5t642UAadyYtk/LNgQqBcQD63txZuWbXnXk8y0J0Amooj0xxkwQ==", "dependencies": { - "@contentstack/cli-command": "~1.7.1", - "@contentstack/cli-utilities": "~1.16.0", + "@contentstack/cli-command": "~1.6.1", + "@contentstack/cli-utilities": "~1.15.0", "@oclif/core": "^4.3.0", "@oclif/plugin-help": "^6.2.28", "chalk": "^4.1.2", @@ -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", @@ -726,13 +699,13 @@ } }, "node_modules/@contentstack/cli-cm-bulk-publish": { - "version": "1.10.5", - "resolved": "https://registry.npmjs.org/@contentstack/cli-cm-bulk-publish/-/cli-cm-bulk-publish-1.10.5.tgz", - "integrity": "sha512-UYhLEKZTA0d2mPvNgLdKDIV+4NWiz6lv49wOKOlqQu77Lohf2mbrGMGVhtL8bq3zqBd7FBK3ng7QEDw6RHNG/w==", + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/@contentstack/cli-cm-bulk-publish/-/cli-cm-bulk-publish-1.10.3.tgz", + "integrity": "sha512-W71BCNFhQrb4p+wHKBCc0eYr+AloVh4hd8HkCjCbF3GKK0YIHlbpzFNjl5+68yEpvsCvDEmiY+s3HSrYKl0kKQ==", "dependencies": { - "@contentstack/cli-command": "~1.7.1", - "@contentstack/cli-config": "~1.17.0", - "@contentstack/cli-utilities": "~1.16.0", + "@contentstack/cli-command": "~1.7.0", + "@contentstack/cli-config": "~1.15.3", + "@contentstack/cli-utilities": "~1.15.0", "@oclif/core": "^4.3.0", "@oclif/plugin-help": "^6.2.28", "chalk": "^4.1.2", @@ -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", @@ -888,15 +854,15 @@ } }, "node_modules/@contentstack/cli-cm-clone": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/@contentstack/cli-cm-clone/-/cli-cm-clone-1.19.0.tgz", - "integrity": "sha512-QtW1rFknlTXExTfNzg6VGSswOWYA+jYhLWL8WDOSwaDnWScAAnT8SEtkE0lngglJDxjIHRuic9Kw0ZEcP4EUZg==", + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/@contentstack/cli-cm-clone/-/cli-cm-clone-1.18.0.tgz", + "integrity": "sha512-DlP3fM5anTzIwDOXgRAgXhhlL0DHwmcwpMgECBHoEt/L6rz6XDw7Tu7FYZjDWsUHwIhHICg6k/hKMHFSU+4Oog==", "dependencies": { "@colors/colors": "^1.6.0", - "@contentstack/cli-cm-export": "~1.23.0", - "@contentstack/cli-cm-import": "~1.31.0", - "@contentstack/cli-command": "~1.7.1", - "@contentstack/cli-utilities": "~1.16.0", + "@contentstack/cli-cm-export": "~1.22.0", + "@contentstack/cli-cm-import": "~1.30.0", + "@contentstack/cli-command": "~1.7.0", + "@contentstack/cli-utilities": "~1.15.0", "@oclif/core": "^4.3.0", "@oclif/plugin-help": "^6.2.28", "chalk": "^4.1.2", @@ -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", @@ -1025,13 +984,13 @@ } }, "node_modules/@contentstack/cli-cm-export": { - "version": "1.23.0", - "resolved": "https://registry.npmjs.org/@contentstack/cli-cm-export/-/cli-cm-export-1.23.0.tgz", - "integrity": "sha512-ckR6/+4GJ6aS7wOOx79PtEb9Ql4rrwgpSFzDoAhENqHY1O4qJ3oEUmNNXKJmqD7/gfexvmb47X6Fm91wgNLQDw==", + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/@contentstack/cli-cm-export/-/cli-cm-export-1.22.1.tgz", + "integrity": "sha512-LvFPKvaNTM1tu1FPe53Ch3ahVX7DE0rA5HW9+WtWjoZ7IcQH23cAgz2aaxBZiXz/jK/Bbr3ZIZ4C/ehGHgftDQ==", "dependencies": { - "@contentstack/cli-command": "~1.7.1", - "@contentstack/cli-utilities": "~1.16.0", - "@contentstack/cli-variants": "~1.3.6", + "@contentstack/cli-command": "~1.7.0", + "@contentstack/cli-utilities": "~1.15.0", + "@contentstack/cli-variants": "~1.3.5", "@oclif/core": "^4.3.3", "async": "^3.2.6", "big-json": "^3.2.0", @@ -1049,12 +1008,12 @@ } }, "node_modules/@contentstack/cli-cm-export-to-csv": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/@contentstack/cli-cm-export-to-csv/-/cli-cm-export-to-csv-1.10.2.tgz", - "integrity": "sha512-oe8+TzH0fo+A540uWz0rmu92T+I8fnKxYYe9F6AD+eQi9tPt+4HzvSYYwQqb+fBnHvkVfcxOBQ3x5hZ9Kp3STA==", + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@contentstack/cli-cm-export-to-csv/-/cli-cm-export-to-csv-1.10.1.tgz", + "integrity": "sha512-V6bc0NG8brP7tFHgMjW8zTZqkg7oUoJ4AWqqkUpqdTztqR45lxJYirPy4MyqtigLST9KCLL8TpU/n2luftLo3w==", "dependencies": { - "@contentstack/cli-command": "~1.7.1", - "@contentstack/cli-utilities": "~1.16.0", + "@contentstack/cli-command": "~1.7.0", + "@contentstack/cli-utilities": "~1.15.0", "@oclif/core": "^4.3.0", "@oclif/plugin-help": "^6.2.32", "fast-csv": "^4.3.6", @@ -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", @@ -1292,14 +1238,14 @@ } }, "node_modules/@contentstack/cli-cm-import": { - "version": "1.31.0", - "resolved": "https://registry.npmjs.org/@contentstack/cli-cm-import/-/cli-cm-import-1.31.0.tgz", - "integrity": "sha512-iJW28DwQZRu3GIZdoXsK7FlV3OoAtx3hkNDiGDyN9fbpD3pGENJAzQDQGh8NxPMZktWB3j3BmERDBjPFjoutig==", - "dependencies": { - "@contentstack/cli-audit": "~1.17.0", - "@contentstack/cli-command": "~1.7.1", - "@contentstack/cli-utilities": "~1.16.0", - "@contentstack/cli-variants": "~1.3.6", + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/@contentstack/cli-cm-import/-/cli-cm-import-1.30.1.tgz", + "integrity": "sha512-SnvPGJ4v/hwEfSs9uplVIR+1aFGzfwldIWv0pnCGYMbCFITjhcuSbOONMkuq8d6mrKtxDfiIoK6ZPDHDCqFRAA==", + "dependencies": { + "@contentstack/cli-audit": "~1.16.1", + "@contentstack/cli-command": "~1.7.0", + "@contentstack/cli-utilities": "~1.15.0", + "@contentstack/cli-variants": "~1.3.5", "@contentstack/management": "~1.22.0", "@oclif/core": "^4.3.0", "big-json": "^3.2.0", @@ -1320,12 +1266,12 @@ } }, "node_modules/@contentstack/cli-cm-import-setup": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/@contentstack/cli-cm-import-setup/-/cli-cm-import-setup-1.7.2.tgz", - "integrity": "sha512-rjLue5ZwW0QHtWNGKIPcaI5FdqhXDAn2CMZ7iWZfDsIlX18VhXJkDrcRRL77QxX2ppMvs7PdT/03vEPioNm9qA==", + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@contentstack/cli-cm-import-setup/-/cli-cm-import-setup-1.7.1.tgz", + "integrity": "sha512-L4BeKnwlAKXtWDp6s4KmM6qQlaFhGhs1C5/5+6hD3JEObfh1aCSxoUF+LSQ25Gfh7dtNMUkirXnjPA7W70kPXw==", "dependencies": { - "@contentstack/cli-command": "~1.7.1", - "@contentstack/cli-utilities": "~1.16.0", + "@contentstack/cli-command": "~1.7.0", + "@contentstack/cli-utilities": "~1.15.0", "@oclif/core": "^4.3.0", "big-json": "^3.2.0", "chalk": "^4.1.2", @@ -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", @@ -1564,12 +1498,12 @@ } }, "node_modules/@contentstack/cli-cm-migrate-rte": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/@contentstack/cli-cm-migrate-rte/-/cli-cm-migrate-rte-1.6.3.tgz", - "integrity": "sha512-bsHF+La03FNfrEGqwmi8Rc4K05WJ+LJ6STnpzDgWRvHSoxi+fnxRIINkDLLK8HI/akJ/k+LKrBA8+gAalSyOSA==", + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/@contentstack/cli-cm-migrate-rte/-/cli-cm-migrate-rte-1.6.2.tgz", + "integrity": "sha512-jZTj6o84ZyMUmzSH6BttDg0MPh1bVpc2MHTKYr+4j591LH+ln7SVAffOq2DIYQGamSRb/B1qbBQ1c0oeVntM+w==", "dependencies": { - "@contentstack/cli-command": "~1.7.1", - "@contentstack/cli-utilities": "~1.16.0", + "@contentstack/cli-command": "~1.6.1", + "@contentstack/cli-utilities": "~1.15.0", "@contentstack/json-rte-serializer": "~2.1.0", "@oclif/core": "^4.3.0", "@oclif/plugin-help": "^6.2.28", @@ -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", @@ -1979,13 +1905,13 @@ } }, "node_modules/@contentstack/cli-cm-seed": { - "version": "1.14.0", - "resolved": "https://registry.npmjs.org/@contentstack/cli-cm-seed/-/cli-cm-seed-1.14.0.tgz", - "integrity": "sha512-wA9yAca1UgZbi2fRHYfYVl717FYhafzBAVZ8/4eTTfKycI/Y1hLrkfrFb5xAIm+eP6+ySmlL2Xh73MNOmaTjXQ==", + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/@contentstack/cli-cm-seed/-/cli-cm-seed-1.13.1.tgz", + "integrity": "sha512-pWmochgo1dUBUNP/TnjhLs61kSDpAE9NIxfgckUWmEIMdfaIB0xfasSdYu141m7MXQtR1flXVvgBKLo6qat4cw==", "dependencies": { - "@contentstack/cli-cm-import": "~1.31.0", - "@contentstack/cli-command": "~1.7.1", - "@contentstack/cli-utilities": "~1.16.0", + "@contentstack/cli-cm-import": "1.30.0", + "@contentstack/cli-command": "~1.7.0", + "@contentstack/cli-utilities": "~1.15.0", "@contentstack/management": "~1.22.0", "inquirer": "8.2.7", "mkdirp": "^1.0.4", @@ -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", @@ -2137,11 +2057,11 @@ } }, "node_modules/@contentstack/cli-command": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@contentstack/cli-command/-/cli-command-1.7.1.tgz", - "integrity": "sha512-VS+f+hwStXNShyVs9m/xV5l+KVZZ81k9lhJu+XjO5zXV/ZS3BNzW96xS6oAOUvSURVUPmZvELzjXFIvwbdBnGQ==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@contentstack/cli-command/-/cli-command-1.7.0.tgz", + "integrity": "sha512-hhsGGa6wFcvHwkapu0vXB1yvOaOmJ1LaV2imyjUREVxvHYC5O4JS2H5VeXLq137Q/dOk5q6o9MjVS+9W4Ri4sw==", "dependencies": { - "@contentstack/cli-utilities": "~1.16.0", + "@contentstack/cli-utilities": "~1.15.0", "@oclif/core": "^4.3.0", "@oclif/plugin-help": "^6.2.28", "contentstack": "^3.25.3" @@ -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", @@ -2264,12 +2177,12 @@ } }, "node_modules/@contentstack/cli-config": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/@contentstack/cli-config/-/cli-config-1.17.0.tgz", - "integrity": "sha512-OW0ThVjabSQGSzHUJYLQANfR2ym6QNbyjb+zQV/5IezLITyrA6YZN7Iot1EZeMN3H14hm5GUjYKyx7KBbUKBqg==", + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/@contentstack/cli-config/-/cli-config-1.16.1.tgz", + "integrity": "sha512-vIiR6TYkZOQRFNnarJVyqMYy3l9o7OMQlofR5MSTloRYlzAciwR3bbwjLsEC8WNQ0yBhdj15o/NPNGEa9uHyhA==", "dependencies": { - "@contentstack/cli-command": "~1.7.1", - "@contentstack/cli-utilities": "~1.16.0", + "@contentstack/cli-command": "~1.7.0", + "@contentstack/cli-utilities": "~1.15.0", "@oclif/core": "^4.3.0", "@oclif/plugin-help": "^6.2.28", "lodash": "^4.17.21" @@ -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", @@ -2429,12 +2335,12 @@ } }, "node_modules/@contentstack/cli-migration": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/@contentstack/cli-migration/-/cli-migration-1.10.2.tgz", - "integrity": "sha512-nA/2lNwCrOdFc7LqyFoWP52jCLF5FXmAIBS9uejbkOjGx7eo2y0UTfCOwS6h77wqdpbcqvdnpxNz+94rGp8Wyw==", + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@contentstack/cli-migration/-/cli-migration-1.10.1.tgz", + "integrity": "sha512-TFBBjSM77qPdBQ5ow/DKQGl37/nSzGpK7gy0nf6T108HzUFdgJ1y8h4lRo3zi/zXBdOB6ZKao9kteK4Fy4roTg==", "dependencies": { - "@contentstack/cli-command": "~1.7.1", - "@contentstack/cli-utilities": "~1.16.0", + "@contentstack/cli-command": "~1.7.0", + "@contentstack/cli-utilities": "~1.15.0", "@oclif/core": "^4.3.0", "@oclif/plugin-help": "^6.2.28", "async": "^3.2.6", @@ -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", @@ -2637,39 +2534,16 @@ "dependencies": { "@contentstack/cli-utilities": "~1.15.0", "@oclif/core": "^4.3.0", - "axios": "^1.9.0", - "chalk": "^4.1.2", - "cli-cursor": "^3.1.0", - "cli-progress": "^3.12.0", - "cli-table": "^0.3.11", - "conf": "^10.2.0", - "dotenv": "^16.5.0", - "figures": "^3.2.0", - "inquirer": "8.2.6", - "inquirer-search-checkbox": "^1.0.0", - "inquirer-search-list": "^1.2.6", - "js-yaml": "^4.1.0", - "klona": "^2.0.6", + "@oclif/plugin-help": "^6.2.28", "lodash": "^4.17.21", "mkdirp": "^1.0.4", - "open": "^8.4.2", - "ora": "^5.4.1", - "papaparse": "^5.5.3", - "recheck": "~4.4.5", - "rxjs": "^6.6.7", - "traverse": "^0.6.11", - "tty-table": "^4.2.3", - "unique-string": "^2.0.0", - "uuid": "^9.0.1", - "winston": "^3.17.0", - "xdg-basedir": "^4.0.0" + "winston": "^3.17.0" } }, "node_modules/@contentstack/cli-variants/node_modules/@contentstack/cli-utilities": { "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", @@ -2706,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" } @@ -2715,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", @@ -2741,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" } @@ -2750,7 +2621,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" }, @@ -2761,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", @@ -2782,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", @@ -2819,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", @@ -2845,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" } @@ -2854,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" } @@ -2863,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" }, @@ -2874,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", @@ -2937,10 +2798,9 @@ } }, "node_modules/@contentstack/marketplace-sdk": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@contentstack/marketplace-sdk/-/marketplace-sdk-1.4.2.tgz", - "integrity": "sha512-eFwSWif5RmHJqniYHNzkC1P0WUN90t1BPfEx8zR9pF0GKETELGVtIwf0tFJ9Ag7zPchQZ63qtcbAQ4WJYWN/+w==", - "hasInstallScript": true, + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@contentstack/marketplace-sdk/-/marketplace-sdk-1.4.1.tgz", + "integrity": "sha512-gxklP8+m7Grb4lRudXXNG9BOAiSkTw7Ua8oC9IAAmCfa1BSDMhh7XNphSM5Jj4paH/+1ZQ/StExU7R4MfcIZ1w==", "dependencies": { "axios": "^1.13.2" } @@ -3065,447 +2925,47 @@ "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_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" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "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" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "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" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "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": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, "node_modules/@eslint/eslintrc": { @@ -4252,7 +3712,6 @@ "version": "12.0.1", "resolved": "https://registry.npmjs.org/@otplib/plugin-crypto/-/plugin-crypto-12.0.1.tgz", "integrity": "sha512-qPuhN3QrT7ZZLcLCyKOSNhuijUi9G5guMRVrxq63r9YNOxxQjPm59gVxLM+7xGnHnM6cimY57tuKsjK7y9LM1g==", - "deprecated": "Please upgrade to v13 of otplib. Refer to otplib docs for migration paths", "dependencies": { "@otplib/core": "^12.0.1" } @@ -4261,7 +3720,6 @@ "version": "12.0.1", "resolved": "https://registry.npmjs.org/@otplib/plugin-thirty-two/-/plugin-thirty-two-12.0.1.tgz", "integrity": "sha512-MtT+uqRso909UkbrrYpJ6XFjj9D+x2Py7KjTO9JDPhL0bJUYVu5kFP4TFZW4NFAywrAtFRxOVY261u0qwb93gA==", - "deprecated": "Please upgrade to v13 of otplib. Refer to otplib docs for migration paths", "dependencies": { "@otplib/core": "^12.0.1", "thirty-two": "^1.0.2" @@ -4271,7 +3729,6 @@ "version": "12.0.1", "resolved": "https://registry.npmjs.org/@otplib/preset-default/-/preset-default-12.0.1.tgz", "integrity": "sha512-xf1v9oOJRyXfluBhMdpOkr+bsE+Irt+0D5uHtvg6x1eosfmHCsCC6ej/m7FXiWqdo0+ZUI6xSKDhJwc8yfiOPQ==", - "deprecated": "Please upgrade to v13 of otplib. Refer to otplib docs for migration paths", "dependencies": { "@otplib/core": "^12.0.1", "@otplib/plugin-crypto": "^12.0.1", @@ -4396,309 +3853,21 @@ "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.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.55.2.tgz", - "integrity": "sha512-21J6xzayjy3O6NdnlO6aXi/urvSRjm6nCI6+nF6ra2YofKruGixN9kfT+dt55HVNwfDmpDHJcaS3JuP/boNnlA==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.55.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.55.2.tgz", - "integrity": "sha512-eXBg7ibkNUZ+sTwbFiDKou0BAckeV6kIigK7y5Ko4mB/5A1KLhuzEKovsmfvsL8mQorkoincMFGnQuIT92SKqA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.55.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.55.2.tgz", - "integrity": "sha512-UCbaTklREjrc5U47ypLulAgg4njaqfOVLU18VrCrI+6E5MQjuG0lSWaqLlAJwsD7NpFV249XgB0Bi37Zh5Sz4g==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.55.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.55.2.tgz", - "integrity": "sha512-dP67MA0cCMHFT2g5XyjtpVOtp7y4UyUxN3dhLdt11at5cPKnSm4lY+EhwNvDXIMzAMIo2KU+mc9wxaAQJTn7sQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.55.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.55.2.tgz", - "integrity": "sha512-WDUPLUwfYV9G1yxNRJdXcvISW15mpvod1Wv3ok+Ws93w1HjIVmCIFxsG2DquO+3usMNCpJQ0wqO+3GhFdl6Fow==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.55.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.55.2.tgz", - "integrity": "sha512-Ng95wtHVEulRwn7R0tMrlUuiLVL/HXA8Lt/MYVpy88+s5ikpntzZba1qEulTuPnPIZuOPcW9wNEiqvZxZmgmqQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.55.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.55.2.tgz", - "integrity": "sha512-AEXMESUDWWGqD6LwO/HkqCZgUE1VCJ1OhbvYGsfqX2Y6w5quSXuyoy/Fg3nRqiwro+cJYFxiw5v4kB2ZDLhxrw==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.55.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.55.2.tgz", - "integrity": "sha512-ZV7EljjBDwBBBSv570VWj0hiNTdHt9uGznDtznBB4Caj3ch5rgD4I2K1GQrtbvJ/QiB+663lLgOdcADMNVC29Q==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.55.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.55.2.tgz", - "integrity": "sha512-uvjwc8NtQVPAJtq4Tt7Q49FOodjfbf6NpqXyW/rjXoV+iZ3EJAHLNAnKT5UJBc6ffQVgmXTUL2ifYiLABlGFqA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.55.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.55.2.tgz", - "integrity": "sha512-s3KoWVNnye9mm/2WpOZ3JeUiediUVw6AvY/H7jNA6qgKA2V2aM25lMkVarTDfiicn/DLq3O0a81jncXszoyCFA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.55.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.55.2.tgz", - "integrity": "sha512-gi21faacK+J8aVSyAUptML9VQN26JRxe484IbF+h3hpG+sNVoMXPduhREz2CcYr5my0NE3MjVvQ5bMKX71pfVA==", - "cpu": [ - "loong64" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-musl": { - "version": "4.55.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.55.2.tgz", - "integrity": "sha512-qSlWiXnVaS/ceqXNfnoFZh4IiCA0EwvCivivTGbEu1qv2o+WTHpn1zNmCTAoOG5QaVr2/yhCoLScQtc/7RxshA==", - "cpu": [ - "loong64" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.55.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.55.2.tgz", - "integrity": "sha512-rPyuLFNoF1B0+wolH277E780NUKf+KoEDb3OyoLbAO18BbeKi++YN6gC/zuJoPPDlQRL3fIxHxCxVEWiem2yXw==", - "cpu": [ - "ppc64" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-ppc64-musl": { - "version": "4.55.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.55.2.tgz", - "integrity": "sha512-g+0ZLMook31iWV4PvqKU0i9E78gaZgYpSrYPed/4Bu+nGTgfOPtfs1h11tSSRPXSjC5EzLTjV/1A7L2Vr8pJoQ==", - "cpu": [ - "ppc64" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.55.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.55.2.tgz", - "integrity": "sha512-i+sGeRGsjKZcQRh3BRfpLsM3LX3bi4AoEVqmGDyc50L6KfYsN45wVCSz70iQMwPWr3E5opSiLOwsC9WB4/1pqg==", - "cpu": [ - "riscv64" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.55.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.55.2.tgz", - "integrity": "sha512-C1vLcKc4MfFV6I0aWsC7B2Y9QcsiEcvKkfxprwkPfLaN8hQf0/fKHwSF2lcYzA9g4imqnhic729VB9Fo70HO3Q==", - "cpu": [ - "riscv64" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.55.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.55.2.tgz", - "integrity": "sha512-68gHUK/howpQjh7g7hlD9DvTTt4sNLp1Bb+Yzw2Ki0xvscm2cOdCLZNJNhd2jW8lsTPrHAHuF751BygifW4bkQ==", - "cpu": [ - "s390x" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.55.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.55.2.tgz", - "integrity": "sha512-1e30XAuaBP1MAizaOBApsgeGZge2/Byd6wV4a8oa6jPdHELbRHBiw7wvo4dp7Ie2PE8TZT4pj9RLGZv9N4qwlw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.55.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.55.2.tgz", - "integrity": "sha512-4BJucJBGbuGnH6q7kpPqGJGzZnYrpAzRd60HQSt3OpX/6/YVgSsJnNzR8Ot74io50SeVT4CtCWe/RYIAymFPwA==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-openbsd-x64": { - "version": "4.55.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.55.2.tgz", - "integrity": "sha512-cT2MmXySMo58ENv8p6/O6wI/h/gLnD3D6JoajwXFZH6X9jz4hARqUhWpGuQhOgLNXscfZYRQMJvZDtWNzMAIDw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "openbsd" - ] - }, - "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.55.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.55.2.tgz", - "integrity": "sha512-sZnyUgGkuzIXaK3jNMPmUIyJrxu/PjmATQrocpGA1WbCPX8H5tfGgRSuYtqBYAvLuIGp8SPRb1O4d1Fkb5fXaQ==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "openharmony" - ] - }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.55.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.55.2.tgz", - "integrity": "sha512-sDpFbenhmWjNcEbBcoTV0PWvW5rPJFvu+P7XoTY0YLGRupgLbFY0XPfwIbJOObzO7QgkRDANh65RjhPmgSaAjQ==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.55.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.55.2.tgz", - "integrity": "sha512-GvJ03TqqaweWCigtKQVBErw2bEhu1tyfNQbarwr94wCGnczA9HF8wqEe3U/Lfu6EdeNP0p6R+APeHVwEqVxpUQ==", - "cpu": [ - "ia32" - ], - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.55.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.55.2.tgz", - "integrity": "sha512-KvXsBvp13oZz9JGe5NYS7FNizLe99Ny+W8ETsuCyjXiKdiGrcz2/J/N8qxZ/RSwivqjQguug07NLHqrIHrqfYw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ] + "rollup": { + "optional": true + } + } }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.55.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.55.2.tgz", - "integrity": "sha512-xNO+fksQhsAckRtDSPWaMeT1uIM+JrDRXlerpnWNXhn1TdB3YZ6uKBMBTKP0eX9XtYEP978hHk1f8332i2AW8Q==", + "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": [ - "x64" + "arm64" ], "optional": true, "os": [ - "win32" + "darwin" ] }, "node_modules/@rtsao/scc": { @@ -4706,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": { @@ -4830,9 +3998,9 @@ } }, "node_modules/@types/express-serve-static-core": { - "version": "4.19.8", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.8.tgz", - "integrity": "sha512-02S5fmqeoKzVZCHPZid4b8JH2eM5HzQLZWN2FohQEy/0eXTq8VXZfSN6Pcr3F6N9R/vNrj7cpgbhjie6m/1tCA==", + "version": "4.19.7", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.7.tgz", + "integrity": "sha512-FvPtiIf1LfhzsaIXhv/PHan/2FeQBbtBDtfX2QfvPxdUelMDEckK08SM6nqo1MIZY3RUlfA+HV8+hFUSio78qg==", "dependencies": { "@types/node": "*", "@types/qs": "*", @@ -4892,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": { @@ -4921,9 +4088,9 @@ } }, "node_modules/@types/lodash": { - "version": "4.17.23", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.23.tgz", - "integrity": "sha512-RDvF6wTulMPjrNdCoYRC8gNR880JNGT8uB+REUpC2Ns4pRqQJhGz90wh7rgdXDPpCczF3VGktDuFGVnz8zP7HA==", + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-FOvQ0YPD5NOfPgMzJihoT+Za5pdkDJWcbpuj1DjaKZIr/gxodQjY/uWEFlTNqW2ugXHUiL8lRQgw63dzKHZdeQ==", "dev": true }, "node_modules/@types/mime": { @@ -4948,9 +4115,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.19.30", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.30.tgz", - "integrity": "sha512-WJtwWJu7UdlvzEAUm484QNg5eAoq5QR08KDNx7g45Usrs2NtOPiX8ugDqmKdXkyL03rBqU5dYNYVQetEpBHq2g==", + "version": "20.19.27", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.27.tgz", + "integrity": "sha512-N2clP5pJhB2YnZJ3PIHFk5RkygRX5WO/5f0WC08tp0wd+sv0rsJk3MqWn3CbNmT2J505a5336jaQj4ph1AdMug==", "dependencies": { "undici-types": "~6.21.0" } @@ -5493,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" @@ -5532,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", @@ -5565,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", @@ -5587,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", @@ -5627,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", @@ -5647,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", @@ -5705,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": { @@ -5749,9 +4909,9 @@ } }, "node_modules/axe-core": { - "version": "4.11.1", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.11.1.tgz", - "integrity": "sha512-BASOg+YwO2C+346x3LZOeoovTIoTrRqEsqMa6fmfAV0P+U9mFr9NsyOEpiYvFjbc64NMrSswhV50WdXzdb/Z5A==", + "version": "4.10.3", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.10.3.tgz", + "integrity": "sha512-Xm7bpRXnDSX2YE2YFfBk2FnF0ep6tmG7xPh8iHee8MIcrgq762Nkce856dYtJYLkuIoYZvGfTs/PbZhideTcEg==", "dev": true, "peer": true, "engines": { @@ -5773,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" @@ -6603,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": { @@ -6932,9 +6090,9 @@ } }, "node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, "node_modules/enabled": { "version": "2.0.0", @@ -6984,26 +6142,6 @@ "node": ">=10.0.0" } }, - "node_modules/engine.io/node_modules/ws": { - "version": "8.18.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", - "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, "node_modules/entities": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", @@ -7107,27 +6245,27 @@ } }, "node_modules/es-iterator-helpers": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.2.2.tgz", - "integrity": "sha512-BrUQ0cPTB/IwXj23HtwHjS9n7O4h9FX94b4xc5zlTHxeLgTAdzYUDyy6KdExAl9lbN5rtfe44xpjpmj9grxs5w==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.2.1.tgz", + "integrity": "sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==", "dev": true, "peer": true, "dependencies": { "call-bind": "^1.0.8", - "call-bound": "^1.0.4", + "call-bound": "^1.0.3", "define-properties": "^1.2.1", - "es-abstract": "^1.24.1", + "es-abstract": "^1.23.6", "es-errors": "^1.3.0", - "es-set-tostringtag": "^2.1.0", + "es-set-tostringtag": "^2.0.3", "function-bind": "^1.1.2", - "get-intrinsic": "^1.3.0", + "get-intrinsic": "^1.2.6", "globalthis": "^1.0.4", "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", "has-proto": "^1.2.0", "has-symbols": "^1.1.0", "internal-slot": "^1.1.0", - "iterator.prototype": "^1.1.5", + "iterator.prototype": "^1.1.4", "safe-array-concat": "^1.1.3" }, "engines": { @@ -7471,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", @@ -7484,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" @@ -7495,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" @@ -7514,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" @@ -7525,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", @@ -7560,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", @@ -7572,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" @@ -7583,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" @@ -7597,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" @@ -7611,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" @@ -7622,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", @@ -7653,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", @@ -7665,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": { @@ -7673,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" @@ -7687,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", @@ -7721,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" @@ -7735,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", @@ -7747,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" @@ -7761,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" @@ -7775,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", @@ -7794,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" @@ -7966,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", @@ -8119,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", @@ -8276,27 +7340,24 @@ "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.4.0", - "iconv-lite": "^0.4.17", + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", "tmp": "^0.0.33" }, "engines": { - "node": ">=0.12" + "node": ">=4" } }, "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" }, @@ -8308,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" }, @@ -9316,9 +8376,9 @@ } }, "node_modules/iconv-lite": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", - "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.1.tgz", + "integrity": "sha512-2Tth85cXwGFHfvRgZWszZSvdo+0Xsqmw8k8ZwxScfcBneNUraK+dxRxRm24nszx80Y0TVio8kKLt5sLE7ZCLlw==", "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" }, @@ -9515,6 +8575,11 @@ "node": ">=4" } }, + "node_modules/inquirer-search-checkbox/node_modules/chardet": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", + "integrity": "sha512-j/Toj7f1z98Hh2cYo2BVr85EpIRWqUi7rtRSGxh/cqUjqrnJe9l9UE7IUGd2vQ2p+kSHLkSzObQPZPLUC6TQwg==" + }, "node_modules/inquirer-search-checkbox/node_modules/cli-cursor": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", @@ -9552,6 +8617,19 @@ "node": ">=0.8.0" } }, + "node_modules/inquirer-search-checkbox/node_modules/external-editor": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", + "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==", + "dependencies": { + "chardet": "^0.4.0", + "iconv-lite": "^0.4.17", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=0.12" + } + }, "node_modules/inquirer-search-checkbox/node_modules/figures": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", @@ -9571,6 +8649,17 @@ "node": ">=4" } }, + "node_modules/inquirer-search-checkbox/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==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/inquirer-search-checkbox/node_modules/inquirer": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz", @@ -9675,6 +8764,17 @@ "node": ">=4" } }, + "node_modules/inquirer-search-checkbox/node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, "node_modules/inquirer-search-list": { "version": "1.2.6", "resolved": "https://registry.npmjs.org/inquirer-search-list/-/inquirer-search-list-1.2.6.tgz", @@ -9726,6 +8826,11 @@ "node": ">=4" } }, + "node_modules/inquirer-search-list/node_modules/chardet": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", + "integrity": "sha512-j/Toj7f1z98Hh2cYo2BVr85EpIRWqUi7rtRSGxh/cqUjqrnJe9l9UE7IUGd2vQ2p+kSHLkSzObQPZPLUC6TQwg==" + }, "node_modules/inquirer-search-list/node_modules/cli-cursor": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", @@ -9763,6 +8868,19 @@ "node": ">=0.8.0" } }, + "node_modules/inquirer-search-list/node_modules/external-editor": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", + "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==", + "dependencies": { + "chardet": "^0.4.0", + "iconv-lite": "^0.4.17", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=0.12" + } + }, "node_modules/inquirer-search-list/node_modules/figures": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", @@ -9782,6 +8900,17 @@ "node": ">=4" } }, + "node_modules/inquirer-search-list/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==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/inquirer-search-list/node_modules/inquirer": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz", @@ -9886,6 +9015,17 @@ "node": ">=4" } }, + "node_modules/inquirer-search-list/node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, "node_modules/inquirer/node_modules/cli-width": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", @@ -10630,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" @@ -10717,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", @@ -10793,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": { @@ -10801,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" @@ -11604,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" @@ -11668,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", @@ -14393,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", @@ -14413,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", @@ -14429,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", @@ -14466,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", @@ -15170,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", @@ -15287,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", @@ -15557,9 +14629,9 @@ } }, "node_modules/rollup": { - "version": "4.55.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.55.2.tgz", - "integrity": "sha512-PggGy4dhwx5qaW+CKBilA/98Ql9keyfnb7lh4SR6shQ91QQQi1ORJ1v4UinkdP2i87OBs9AQFooQylcrrRfIcg==", + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.55.1.tgz", + "integrity": "sha512-wDv/Ht1BNHB4upNbK74s9usvl7hObDnvVzknxqY/E/O3X6rW1U1rV1aENEfJ54eFZDTNo7zv1f5N4edCluH7+A==", "dependencies": { "@types/estree": "1.0.8" }, @@ -15571,31 +14643,31 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.55.2", - "@rollup/rollup-android-arm64": "4.55.2", - "@rollup/rollup-darwin-arm64": "4.55.2", - "@rollup/rollup-darwin-x64": "4.55.2", - "@rollup/rollup-freebsd-arm64": "4.55.2", - "@rollup/rollup-freebsd-x64": "4.55.2", - "@rollup/rollup-linux-arm-gnueabihf": "4.55.2", - "@rollup/rollup-linux-arm-musleabihf": "4.55.2", - "@rollup/rollup-linux-arm64-gnu": "4.55.2", - "@rollup/rollup-linux-arm64-musl": "4.55.2", - "@rollup/rollup-linux-loong64-gnu": "4.55.2", - "@rollup/rollup-linux-loong64-musl": "4.55.2", - "@rollup/rollup-linux-ppc64-gnu": "4.55.2", - "@rollup/rollup-linux-ppc64-musl": "4.55.2", - "@rollup/rollup-linux-riscv64-gnu": "4.55.2", - "@rollup/rollup-linux-riscv64-musl": "4.55.2", - "@rollup/rollup-linux-s390x-gnu": "4.55.2", - "@rollup/rollup-linux-x64-gnu": "4.55.2", - "@rollup/rollup-linux-x64-musl": "4.55.2", - "@rollup/rollup-openbsd-x64": "4.55.2", - "@rollup/rollup-openharmony-arm64": "4.55.2", - "@rollup/rollup-win32-arm64-msvc": "4.55.2", - "@rollup/rollup-win32-ia32-msvc": "4.55.2", - "@rollup/rollup-win32-x64-gnu": "4.55.2", - "@rollup/rollup-win32-x64-msvc": "4.55.2", + "@rollup/rollup-android-arm-eabi": "4.55.1", + "@rollup/rollup-android-arm64": "4.55.1", + "@rollup/rollup-darwin-arm64": "4.55.1", + "@rollup/rollup-darwin-x64": "4.55.1", + "@rollup/rollup-freebsd-arm64": "4.55.1", + "@rollup/rollup-freebsd-x64": "4.55.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.55.1", + "@rollup/rollup-linux-arm-musleabihf": "4.55.1", + "@rollup/rollup-linux-arm64-gnu": "4.55.1", + "@rollup/rollup-linux-arm64-musl": "4.55.1", + "@rollup/rollup-linux-loong64-gnu": "4.55.1", + "@rollup/rollup-linux-loong64-musl": "4.55.1", + "@rollup/rollup-linux-ppc64-gnu": "4.55.1", + "@rollup/rollup-linux-ppc64-musl": "4.55.1", + "@rollup/rollup-linux-riscv64-gnu": "4.55.1", + "@rollup/rollup-linux-riscv64-musl": "4.55.1", + "@rollup/rollup-linux-s390x-gnu": "4.55.1", + "@rollup/rollup-linux-x64-gnu": "4.55.1", + "@rollup/rollup-linux-x64-musl": "4.55.1", + "@rollup/rollup-openbsd-x64": "4.55.1", + "@rollup/rollup-openharmony-arm64": "4.55.1", + "@rollup/rollup-win32-arm64-msvc": "4.55.1", + "@rollup/rollup-win32-ia32-msvc": "4.55.1", + "@rollup/rollup-win32-x64-gnu": "4.55.1", + "@rollup/rollup-win32-x64-msvc": "4.55.1", "fsevents": "~2.3.2" } }, @@ -16235,26 +15307,6 @@ "ws": "~8.18.3" } }, - "node_modules/socket.io-adapter/node_modules/ws": { - "version": "8.18.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", - "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, "node_modules/socket.io-parser": { "version": "4.2.5", "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.5.tgz", @@ -16386,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", @@ -16402,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", @@ -16431,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", @@ -16520,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" @@ -16588,7 +15636,6 @@ "version": "6.2.1", "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", - "deprecated": "Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exhorbitant rates) by contacting i@izs.me", "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", @@ -16785,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", @@ -16978,9 +16024,9 @@ } }, "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "version": "5.9.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz", + "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -16989,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", @@ -17292,9 +16327,9 @@ "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==" }, "node_modules/which-typed-array": { - "version": "1.1.20", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.20.tgz", - "integrity": "sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==", + "version": "1.1.19", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", + "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", "dependencies": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", @@ -17420,9 +16455,9 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, "node_modules/ws": { - "version": "8.19.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz", - "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==", + "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", "engines": { "node": ">=10.0.0" }, 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 806d2f06a..b13a7aadb 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 fa2cd13c426dc5fc4064eb69f37d2b7f3ada2893 Mon Sep 17 00:00:00 2001 From: shobhitupadhyayy Date: Tue, 20 Jan 2026 14:52:49 +0530 Subject: [PATCH 09/11] 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 From 79774114046beb49137e830e34e6f50ce51238aa Mon Sep 17 00:00:00 2001 From: shobhitupadhyayy Date: Wed, 28 Jan 2026 12:46:19 +0530 Subject: [PATCH 10/11] feat: enhance SSO integration and refactor API service calls - Added isSSO property to the Project interface for better SSO handling. - Introduced requestWithSsoTokenRefresh utility to streamline SSO token management across services. - Updated various service methods to utilize SSO token refresh logic, improving authentication flow. - Refactored API calls in org.service.ts, migration.service.ts, and user.service.ts to support SSO. - Enhanced pagination utility to accommodate SSO token handling for paginated requests. - Updated configuration handling to prefer updated_at for OAuth token management. --- api/src/models/project-lowdb.ts | 3 +- api/src/services/contentMapper.service.ts | 16 ++- api/src/services/migration.service.ts | 36 +++++- api/src/services/org.service.ts | 132 +++++++++++----------- api/src/services/projects.service.ts | 30 +++-- api/src/services/user.service.ts | 23 ++-- api/src/utils/config-handler.util.ts | 6 +- api/src/utils/pagination.utils.ts | 23 ++-- api/src/utils/sso-request.utils.ts | 52 +++++++++ upload-api/src/config/index.ts | 4 +- 10 files changed, 212 insertions(+), 113 deletions(-) create mode 100644 api/src/utils/sso-request.utils.ts diff --git a/api/src/models/project-lowdb.ts b/api/src/models/project-lowdb.ts index e995da368..e55aa5d2f 100644 --- a/api/src/models/project-lowdb.ts +++ b/api/src/models/project-lowdb.ts @@ -76,9 +76,10 @@ interface Project { isMigrationStarted: boolean; isMigrationCompleted:boolean; migration_execution: boolean; + isSSO: boolean; } -interface ProjectDocument { +interface ProjectDocument { projects: Project[]; } diff --git a/api/src/services/contentMapper.service.ts b/api/src/services/contentMapper.service.ts index f4b0b32ef..73f79eb74 100644 --- a/api/src/services/contentMapper.service.ts +++ b/api/src/services/contentMapper.service.ts @@ -18,6 +18,7 @@ import https from "../utils/https.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 { requestWithSsoTokenRefresh } from "../utils/sso-request.utils.js"; import ProjectModelLowdb from "../models/project-lowdb.js"; import FieldMapperModel from "../models/FieldMapper.js"; import { v4 as uuidv4 } from "uuid"; @@ -398,7 +399,8 @@ const getExistingContentTypes = async (req: Request) => { headers, 100, 'getExistingContentTypes', - 'content_types' + 'content_types', + token_payload ); const processedContentTypes = contentTypes.map((singleCT: any) => ({ @@ -411,13 +413,19 @@ const getExistingContentTypes = async (req: Request) => { let selectedContentType = null; if (contentTypeUID) { - const [err, res] = await safePromise( - https({ + const [err, res] = token_payload?.is_sso + ? await requestWithSsoTokenRefresh(token_payload, { method: 'GET', url: `${baseUrl}/${contentTypeUID}`, headers, }) - ); + : await safePromise( + https({ + method: 'GET', + url: `${baseUrl}/${contentTypeUID}`, + headers, + }) + ); selectedContentType = { diff --git a/api/src/services/migration.service.ts b/api/src/services/migration.service.ts index 63efbb3c1..54ee194ac 100644 --- a/api/src/services/migration.service.ts +++ b/api/src/services/migration.service.ts @@ -38,6 +38,7 @@ import { taxonomyService } from './taxonomy.service.js'; import { globalFieldServie } from './globalField.service.js'; import { getSafePath, sanitizeStackId } from '../utils/sanitize-path.utils.js'; import { aemService } from './aem.service.js'; +import { requestWithSsoTokenRefresh } from '../utils/sso-request.utils.js'; /** * Creates a test stack. @@ -81,8 +82,8 @@ const createTestStack = async (req: Request): Promise => { const testStackCount = projectData?.test_stacks?.length + 1; const newName = testStackName + '-' + testStackCount; - const [err, res] = await safePromise( - https({ + const [err, res] = token_payload?.is_sso + ? await requestWithSsoTokenRefresh(token_payload, { method: 'POST', url: `${config.CS_API[ token_payload?.region as keyof typeof config.CS_API @@ -96,7 +97,22 @@ const createTestStack = async (req: Request): Promise => { }, }, }) - ); + : await safePromise( + https({ + method: 'POST', + url: `${config.CS_API[ + token_payload?.region as keyof typeof config.CS_API + ]!}/stacks`, + headers: headers, + data: { + stack: { + name: newName, + description, + master_locale, + }, + }, + }) + ); if (err) { logger.error( @@ -182,15 +198,23 @@ const deleteTestStack = async (req: Request): Promise => { throw new BadRequestError("No valid authentication token found or mismatch in is_sso flag"); } - const [err, res] = await safePromise( - https({ + const [err, res] = token_payload?.is_sso + ? await requestWithSsoTokenRefresh(token_payload, { method: 'DELETE', url: `${config.CS_API[ token_payload?.region as keyof typeof config.CS_API ]!}/stacks`, headers: headers, }) - ); + : await safePromise( + https({ + method: 'DELETE', + url: `${config.CS_API[ + token_payload?.region as keyof typeof config.CS_API + ]!}/stacks`, + headers: headers, + }) + ); if (err) { logger.error( diff --git a/api/src/services/org.service.ts b/api/src/services/org.service.ts index 39e40a557..0775204a7 100644 --- a/api/src/services/org.service.ts +++ b/api/src/services/org.service.ts @@ -9,6 +9,14 @@ import { HTTP_TEXTS, HTTP_CODES } from "../constants/index.js"; import { ExceptionFunction } from "../utils/custom-errors.utils.js"; import { BadRequestError } from "../utils/custom-errors.utils.js"; import ProjectModelLowdb from "../models/project-lowdb.js"; +import { requestWithSsoTokenRefresh } from "../utils/sso-request.utils.js"; + +const requestWithAuthRetry = (token_payload: any, requestConfig: any) => { + if (token_payload?.is_sso) { + return requestWithSsoTokenRefresh(token_payload, requestConfig); + } + return safePromise(https(requestConfig)); +}; /** * Retrieves all stacks based on the provided request. @@ -39,15 +47,13 @@ const getAllStacks = async (req: Request): Promise => { 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[ - token_payload?.region as keyof typeof config.CS_API - ]!}/stacks`, - headers: headers, - }) - ); + const [err, res] = await requestWithAuthRetry(token_payload, { + method: "GET", + url: `${config.CS_API[ + token_payload?.region as keyof typeof config.CS_API + ]!}/stacks`, + headers: headers, + }); if (err) { logger.error( getLogMessage( @@ -135,22 +141,20 @@ const createStack = async (req: Request): Promise => { throw new BadRequestError("No valid authentication token found or mismatch in is_sso flag"); } - const [err, res] = await safePromise( - https({ - method: "POST", - url: `${config.CS_API[ - token_payload?.region as keyof typeof config.CS_API - ]!}/stacks`, - headers: headers, - data: { - stack: { - name, - description, - master_locale, - }, + const [err, res] = await requestWithAuthRetry(token_payload, { + method: "POST", + url: `${config.CS_API[ + token_payload?.region as keyof typeof config.CS_API + ]!}/stacks`, + headers: headers, + data: { + stack: { + name, + description, + master_locale, }, - }) - ); + }, + }); if (err) { logger.error( @@ -213,15 +217,13 @@ const getLocales = async (req: Request): Promise => { 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[ - token_payload?.region as keyof typeof config.CS_API - ]!}/locales?include_all=true`, - headers: headers, - }) - ); + const [err, res] = await requestWithAuthRetry(token_payload, { + method: "GET", + url: `${config.CS_API[ + token_payload?.region as keyof typeof config.CS_API + ]!}/locales?include_all=true`, + headers: headers, + }); if (err) { logger.error( @@ -284,15 +286,13 @@ const getStackStatus = async (req: Request) => { } try { - const [stackErr, stackRes] = await safePromise( - https({ - method: "GET", - url: `${config.CS_API[ - token_payload?.region as keyof typeof config.CS_API - ]!}/stacks`, - headers: headers, - }) - ); + const [stackErr, stackRes] = await requestWithAuthRetry(token_payload, { + method: "GET", + url: `${config.CS_API[ + token_payload?.region as keyof typeof config.CS_API + ]!}/stacks`, + headers: headers, + }); if (stackErr) return { @@ -309,15 +309,13 @@ const getStackStatus = async (req: Request) => { ) throw new BadRequestError(HTTP_TEXTS.DESTINATION_STACK_NOT_FOUND); - const [err, res] = await safePromise( - https({ - method: "GET", - url: `${config.CS_API[ - token_payload?.region as keyof typeof config.CS_API - ]!}/content_types?skip=0&limit=1&include_count=true`, - headers: headers, - }) - ); + const [err, res] = await requestWithAuthRetry(token_payload, { + method: "GET", + url: `${config.CS_API[ + token_payload?.region as keyof typeof config.CS_API + ]!}/content_types?skip=0&limit=1&include_count=true`, + headers: headers, + }); if (err) return { @@ -372,15 +370,13 @@ const getStackLocale = async (req: Request) => { } try { - const [stackErr, stackRes] = await safePromise( - https({ - method: "GET", - url: `${config.CS_API[ - token_payload?.region as keyof typeof config.CS_API - ]!}/locales`, - headers: headers, - }) - ); + const [stackErr, stackRes] = await requestWithAuthRetry(token_payload, { + method: "GET", + url: `${config.CS_API[ + token_payload?.region as keyof typeof config.CS_API + ]!}/locales`, + headers: headers, + }); if (stackErr) return { @@ -432,15 +428,13 @@ const getOrgDetails = async (req: Request) => { try { - const [stackErr, stackRes] = await safePromise( - https({ - method: "GET", - url: `${config.CS_API[ - token_payload?.region as keyof typeof config.CS_API - ]!}/organizations/${orgId}?include_plan=true`, - headers: headers, - }) - ); + const [stackErr, stackRes] = await requestWithAuthRetry(token_payload, { + method: "GET", + url: `${config.CS_API[ + token_payload?.region as keyof typeof config.CS_API + ]!}/organizations/${orgId}?include_plan=true`, + headers: headers, + }); if (stackErr) return { diff --git a/api/src/services/projects.service.ts b/api/src/services/projects.service.ts index fd602c9f4..2ff1f9ac5 100644 --- a/api/src/services/projects.service.ts +++ b/api/src/services/projects.service.ts @@ -20,6 +20,7 @@ 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 { requestWithSsoTokenRefresh } from "../utils/sso-request.utils.js"; import getProjectUtil from "../utils/get-project.utils.js"; import logger from "../utils/logger.js"; import AuthenticationModel from "../models/authentication.js"; @@ -803,15 +804,26 @@ const updateDestinationStack = async (req: Request) => { // ); // } try { - const [err, res] = await safePromise( - https({ - method: 'GET', - url: `${config.CS_API[ - token_payload?.region as keyof typeof config.CS_API - ]!}/stacks`, - headers: headers, - }) - ); + const [err, res] = project?.isSSO + ? await requestWithSsoTokenRefresh( + { ...token_payload, is_sso: true }, + { + method: 'GET', + url: `${config.CS_API[ + token_payload?.region as keyof typeof config.CS_API + ]!}/stacks`, + headers: headers, + } + ) + : await safePromise( + https({ + method: 'GET', + url: `${config.CS_API[ + token_payload?.region as keyof typeof config.CS_API + ]!}/stacks`, + headers: headers, + }) + ); if (err) { return { diff --git a/api/src/services/user.service.ts b/api/src/services/user.service.ts index add26c492..da481a39e 100644 --- a/api/src/services/user.service.ts +++ b/api/src/services/user.service.ts @@ -11,6 +11,7 @@ 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"; +import { requestWithSsoTokenRefresh } from "../utils/sso-request.utils.js"; /** * Retrieves the user profile based on the provided request. @@ -42,18 +43,16 @@ const getUserProfile = async (req: Request): Promise => { throw new BadRequestError("SSO authentication not completed"); } - 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", - }, - }) - ); + const [err, res] = await requestWithSsoTokenRefresh(appTokenPayload, { + 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( diff --git a/api/src/utils/config-handler.util.ts b/api/src/utils/config-handler.util.ts index db789ebf0..8e93154d0 100644 --- a/api/src/utils/config-handler.util.ts +++ b/api/src/utils/config-handler.util.ts @@ -8,7 +8,11 @@ import { configHandler } from '@contentstack/cli-utilities'; export const setOAuthConfig = (userData: any) => { configHandler.set('oauthAccessToken', userData?.access_token); configHandler.set('oauthRefreshToken', userData?.refresh_token); - configHandler.set('oauthDateTime', userData?.created_at); + // Prefer updated_at so CLI doesn't immediately refresh a fresh token. + configHandler.set( + 'oauthDateTime', + userData?.updated_at || userData?.created_at || new Date() + ); configHandler.set('email', userData?.email); configHandler.set('userUid', userData?.user_id); configHandler.set('oauthOrgUid', userData?.organization_uid); diff --git a/api/src/utils/pagination.utils.ts b/api/src/utils/pagination.utils.ts index df52f33ae..afcade398 100644 --- a/api/src/utils/pagination.utils.ts +++ b/api/src/utils/pagination.utils.ts @@ -1,6 +1,8 @@ /* eslint-disable no-constant-condition */ import { safePromise } from "./index.js"; -import https from './https.utils.js' +import https from "./https.utils.js"; +import { AppTokenPayload } from "../models/types.js"; +import { requestWithSsoTokenRefresh } from "./sso-request.utils.js"; /** * Fetches all paginated data for a given endpoint. * @param baseUrl - The API endpoint base URL. @@ -15,19 +17,22 @@ const fetchAllPaginatedData = async ( headers: Record, limit = 100, srcFunc = '', - responseKey = 'items' + responseKey = 'items', + tokenPayload?: AppTokenPayload ): Promise => { const items: any[] = []; let skip = 0; while (true) { - const [err, res] = await safePromise( - https({ - method: 'GET', - url: `${baseUrl}?limit=${limit}&skip=${skip}`, - headers, - }) - ); + const requestConfig = { + method: 'GET', + url: `${baseUrl}?limit=${limit}&skip=${skip}`, + headers, + }; + + const [err, res] = tokenPayload?.is_sso + ? await requestWithSsoTokenRefresh(tokenPayload, requestConfig) + : await safePromise(https(requestConfig)); if (err) { throw new Error(`Error in ${srcFunc}: ${err.response?.data || err.message}`); diff --git a/api/src/utils/sso-request.utils.ts b/api/src/utils/sso-request.utils.ts new file mode 100644 index 000000000..a1c6b07dc --- /dev/null +++ b/api/src/utils/sso-request.utils.ts @@ -0,0 +1,52 @@ +import { AppTokenPayload } from "../models/types.js"; +import { refreshOAuthToken } from "../services/auth.service.js"; +import { safePromise } from "./index.js"; +import https from "./https.utils.js"; +import logger from "./logger.js"; + +type HttpConfig = { + url: string; + method: string; + headers?: Record; + data?: any; + timeout?: number; +}; + +const shouldRefreshAccessToken = (err: any): boolean => { + const status = err?.response?.status; + const errorCode = err?.response?.data?.error_code ?? err?.response?.data?.code; + + return status === 401 || errorCode === 105; +}; + +export const requestWithSsoTokenRefresh = async ( + tokenPayload: AppTokenPayload, + requestConfig: HttpConfig +): Promise<[any, any]> => { + const [err, res] = await safePromise(https(requestConfig)); + + if (!err || !tokenPayload?.is_sso || !shouldRefreshAccessToken(err)) { + return [err, res]; + } + + try { + const newAccessToken = await refreshOAuthToken(tokenPayload?.user_id); + const refreshedHeaders = { + ...(requestConfig.headers || {}), + authorization: `Bearer ${newAccessToken}`, + }; + + return await safePromise( + https({ + ...requestConfig, + headers: refreshedHeaders, + }) + ); + } catch (refreshError: any) { + logger.error( + "Failed to refresh access token for SSO request", + refreshError?.response?.data || refreshError?.message + ); + return [err, res]; + } +}; diff --git a/upload-api/src/config/index.ts b/upload-api/src/config/index.ts index 9ea8498b3..6333a4716 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 || 'wordpress', + cmsType: process.env.CMS_TYPE || 'aem', isLocalPath: true, awsData: { awsRegion: 'us-east-2', @@ -12,5 +12,5 @@ export default { bucketName: '', bucketKey: '' }, - localPath: process.env.CONTAINER_PATH || 'your-local-legacy-cms-path', + localPath: process.env.CONTAINER_PATH || '/Users/shobhit.upadhyay/Downloads/templates', }; From c3e4bfd7e34acfe06a826bfcfd068ba0e93e13f3 Mon Sep 17 00:00:00 2001 From: shobhitupadhyayy Date: Wed, 28 Jan 2026 12:50:47 +0530 Subject: [PATCH 11/11] fix: update cmsType and localPath defaults in configuration - Changed default value of cmsType to 'cmsType' for clarity. - Updated localPath default to 'localPath' to standardize configuration settings. --- upload-api/src/config/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/upload-api/src/config/index.ts b/upload-api/src/config/index.ts index 6333a4716..5fc95cebc 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 || 'aem', + cmsType: process.env.CMS_TYPE || 'cmsType', isLocalPath: true, awsData: { awsRegion: 'us-east-2', @@ -12,5 +12,5 @@ export default { bucketName: '', bucketKey: '' }, - localPath: process.env.CONTAINER_PATH || '/Users/shobhit.upadhyay/Downloads/templates', +localPath: process.env.CONTAINER_PATH || 'localPath', };