From 0e7b0a0ce526aaf0f6ccb4d3dceb096a30f55208 Mon Sep 17 00:00:00 2001 From: lohxt1 Date: Wed, 19 Mar 2025 16:20:52 +0530 Subject: [PATCH] option for oauth2 authroization using default browser --- package-lock.json | 617 +++++++++++++++--- .../Auth/OAuth2/AuthorizationCode/index.js | 23 +- .../bruno-app/src/utils/collections/index.js | 1 + packages/bruno-electron/package.json | 1 + .../src/ipc/network/interpolate-vars.js | 3 +- .../src/ipc/network/prepare-request.js | 3 +- .../bruno-electron/src/utils/oauth2-server.js | 68 ++ packages/bruno-electron/src/utils/oauth2.js | 27 +- packages/bruno-electron/src/utils/pid-port.js | 83 +++ packages/bruno-lang/v2/src/bruToJson.js | 4 +- .../bruno-lang/v2/src/collectionBruToJson.js | 4 +- packages/bruno-lang/v2/src/jsonToBru.js | 14 +- .../bruno-lang/v2/src/jsonToCollectionBru.js | 1 + .../bruno-schema/src/collections/index.js | 5 + 14 files changed, 749 insertions(+), 105 deletions(-) create mode 100644 packages/bruno-electron/src/utils/oauth2-server.js create mode 100644 packages/bruno-electron/src/utils/pid-port.js diff --git a/package-lock.json b/package-lock.json index 1d3d36378..33988eae8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,6 +18,10 @@ "packages/bruno-toml", "packages/bruno-graphql-docs" ], + "dependencies": { + "find-process": "^1.4.10", + "pid-port": "^1.0.2" + }, "devDependencies": { "@faker-js/faker": "^7.6.0", "@jest/globals": "^29.2.0", @@ -6826,6 +6830,12 @@ } } }, + "node_modules/@sec-ant/readable-stream": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz", + "integrity": "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==", + "license": "MIT" + }, "node_modules/@sinclair/typebox": { "version": "0.27.8", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", @@ -6846,6 +6856,18 @@ "url": "https://github.com/sindresorhus/is?sponsor=1" } }, + "node_modules/@sindresorhus/merge-streams": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz", + "integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@sinonjs/commons": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", @@ -8283,6 +8305,15 @@ "node": ">=0.4.0" } }, + "node_modules/address": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/address/-/address-2.0.3.tgz", + "integrity": "sha512-XNAb/a6TCqou+TufU8/u11HCu9x1gYvOoxLwtlXgIqmkrYQADVv6ljyW2zwiPhHz9R1gItAWpuDrdJMmrOBFEA==", + "license": "MIT", + "engines": { + "node": ">= 16.0.0" + } + }, "node_modules/agent-base": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", @@ -11257,7 +11288,6 @@ "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, "license": "MIT", "dependencies": { "path-key": "^3.1.0", @@ -11904,6 +11934,22 @@ "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==", "license": "MIT" }, + "node_modules/detect-port": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-port/-/detect-port-2.1.0.tgz", + "integrity": "sha512-epZuWb/6Q62L+nDHJc/hQAqf8pylsqgk3BpZXVBx1CDnr3nkrVNn73Uu1rXcFzkNcc+hkP3whuOg7JZYaQB65Q==", + "license": "MIT", + "dependencies": { + "address": "^2.0.1" + }, + "bin": { + "detect": "dist/commonjs/bin/detect-port.js", + "detect-port": "dist/commonjs/bin/detect-port.js" + }, + "engines": { + "node": ">= 16.0.0" + } + }, "node_modules/dev-null": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/dev-null/-/dev-null-0.1.1.tgz", @@ -13007,6 +13053,52 @@ "dev": true, "license": "Apache-2.0" }, + "node_modules/express": { + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.3", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.7.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.3.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.12", + "proxy-addr": "~2.0.7", + "qs": "6.13.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.19.0", + "serve-static": "1.16.2", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/express-basic-auth": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/express-basic-auth/-/express-basic-auth-1.2.1.tgz", @@ -13016,6 +13108,30 @@ "basic-auth": "^2.0.1" } }, + "node_modules/express/node_modules/cookie": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express/node_modules/qs": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -13185,6 +13301,33 @@ "pend": "~1.2.0" } }, + "node_modules/figures": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-6.1.0.tgz", + "integrity": "sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==", + "license": "MIT", + "dependencies": { + "is-unicode-supported": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/figures/node_modules/is-unicode-supported": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", + "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/file": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/file/-/file-0.2.2.tgz", @@ -13286,6 +13429,45 @@ "node": ">= 0.8" } }, + "node_modules/find-process": { + "version": "1.4.10", + "resolved": "https://registry.npmjs.org/find-process/-/find-process-1.4.10.tgz", + "integrity": "sha512-ncYFnWEIwL7PzmrK1yZtaccN8GhethD37RzBHG6iOZoFYB4vSmLLXfeWJjeN5nMvCJMjOtBvBBF8OgxEcikiZg==", + "license": "MIT", + "dependencies": { + "chalk": "~4.1.2", + "commander": "^12.1.0", + "loglevel": "^1.9.2" + }, + "bin": { + "find-process": "bin/find-process.js" + } + }, + "node_modules/find-process/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/find-process/node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/find-up": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", @@ -15065,6 +15247,18 @@ "node": ">=8" } }, + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-plain-object": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", @@ -15188,7 +15382,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, "license": "ISC" }, "node_modules/isobject": { @@ -16932,6 +17125,19 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/loglevel": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.9.2.tgz", + "integrity": "sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg==", + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + }, + "funding": { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/loglevel" + } + }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -17412,7 +17618,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true, "license": "MIT" }, "node_modules/merge2": { @@ -18625,6 +18830,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/parse-ms": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-4.0.0.tgz", + "integrity": "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/parse5": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", @@ -18792,7 +19009,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -18838,6 +19054,12 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/path-to-regexp": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", + "license": "MIT" + }, "node_modules/path/node_modules/inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", @@ -18960,6 +19182,155 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pid-port": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pid-port/-/pid-port-1.0.2.tgz", + "integrity": "sha512-Khqp07zX8IJpmIg56bHrLxS3M0iSL4cq6wnMq8YE7r/hSw3Kn4QxYS6QJg8Bs22Z7CSVj7eSsxFuigYVIFWmjg==", + "license": "MIT", + "dependencies": { + "execa": "^8.0.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pid-port/node_modules/execa": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/pid-port/node_modules/get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pid-port/node_modules/human-signals": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=16.17.0" + } + }, + "node_modules/pid-port/node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pid-port/node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pid-port/node_modules/npm-run-path": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", + "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", + "license": "MIT", + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pid-port/node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "license": "MIT", + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pid-port/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pid-port/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/pid-port/node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/pify": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/pify/-/pify-5.0.0.tgz", @@ -20031,6 +20402,21 @@ "dev": true, "license": "MIT" }, + "node_modules/pretty-ms": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.2.0.tgz", + "integrity": "sha512-4yf0QO/sllf/1zbZWYnvWw3NxCQwLXKzIj0G849LSufP15BXKM0rbD2Z3wVnkMfjdn/CB0Dpp444gYAACdsplg==", + "license": "MIT", + "dependencies": { + "parse-ms": "^4.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/pretty-quick": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/pretty-quick/-/pretty-quick-3.3.1.tgz", @@ -22382,7 +22768,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" @@ -22395,7 +22780,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -24228,6 +24612,18 @@ "node": ">=4" } }, + "node_modules/unicorn-magic": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", + "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/unique-filename": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-2.0.1.tgz", @@ -24744,7 +25140,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, "license": "ISC", "dependencies": { "isexe": "^2.0.0" @@ -24994,6 +25389,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/yoctocolors": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.1.1.tgz", + "integrity": "sha512-GQHQqAopRhwU8Kt1DDM8NjibDXHC8eoh1erhGAJPEyveY9qqVeXvVikNKrDz69sHowPMorbPUrH/mx8c50eiBQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/yup": { "version": "0.32.11", "resolved": "https://registry.npmjs.org/yup/-/yup-0.32.11.tgz", @@ -26282,11 +26689,15 @@ "chokidar": "^3.5.3", "content-disposition": "^0.5.4", "decomment": "^0.9.5", + "detect-port": "^2.1.0", "dotenv": "^16.0.3", "electron-is-dev": "^2.0.0", "electron-notarize": "^1.2.2", "electron-store": "^8.1.0", "electron-util": "^0.17.2", + "execa": "^9.5.2", + "express": "^4.21.2", + "find-process": "^1.4.10", "form-data": "^4.0.0", "fs-extra": "^10.1.0", "graphql": "^16.6.0", @@ -26298,6 +26709,7 @@ "lodash": "^4.17.21", "mime-types": "^2.1.35", "nanoid": "3.3.8", + "pid-port": "^1.0.2", "qs": "^6.11.0", "socks-proxy-agent": "^8.0.2", "tough-cookie": "^4.1.3", @@ -27351,6 +27763,32 @@ "proxy-from-env": "^1.1.0" } }, + "packages/bruno-electron/node_modules/execa": { + "version": "9.5.2", + "resolved": "https://registry.npmjs.org/execa/-/execa-9.5.2.tgz", + "integrity": "sha512-EHlpxMCpHWSAh1dgS6bVeoLAXGnJNdR93aabr4QCGbzOM73o5XmRfM/e5FUqsw3aagP8S8XEWUWFAxnRBnAF0Q==", + "license": "MIT", + "dependencies": { + "@sindresorhus/merge-streams": "^4.0.0", + "cross-spawn": "^7.0.3", + "figures": "^6.1.0", + "get-stream": "^9.0.0", + "human-signals": "^8.0.0", + "is-plain-obj": "^4.1.0", + "is-stream": "^4.0.1", + "npm-run-path": "^6.0.0", + "pretty-ms": "^9.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^4.0.0", + "yoctocolors": "^2.0.0" + }, + "engines": { + "node": "^18.19.0 || >=20.5.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, "packages/bruno-electron/node_modules/fs-extra": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", @@ -27365,6 +27803,43 @@ "node": ">=12" } }, + "packages/bruno-electron/node_modules/get-stream": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-9.0.1.tgz", + "integrity": "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==", + "license": "MIT", + "dependencies": { + "@sec-ant/readable-stream": "^0.4.1", + "is-stream": "^4.0.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/bruno-electron/node_modules/human-signals": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-8.0.0.tgz", + "integrity": "sha512-/1/GPCpDUCCYwlERiYjxoczfP0zfvZMU/OWgQPMya9AbAE24vseigFdhAMObpc8Q4lc/kjutPfUddDYyAmejnA==", + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "packages/bruno-electron/node_modules/is-stream": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz", + "integrity": "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "packages/bruno-electron/node_modules/nanoid": { "version": "3.3.8", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", @@ -27383,6 +27858,58 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "packages/bruno-electron/node_modules/npm-run-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-6.0.0.tgz", + "integrity": "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==", + "license": "MIT", + "dependencies": { + "path-key": "^4.0.0", + "unicorn-magic": "^0.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/bruno-electron/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/bruno-electron/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "packages/bruno-electron/node_modules/strip-final-newline": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-4.0.0.tgz", + "integrity": "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "packages/bruno-graphql-docs": { "name": "@usebruno/graphql-docs", "version": "0.1.0", @@ -27587,61 +28114,6 @@ "proxy-from-env": "^1.1.0" } }, - "packages/bruno-tests/node_modules/cookie": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", - "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "packages/bruno-tests/node_modules/express": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", - "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", - "license": "MIT", - "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.3", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.7.1", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.3.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.3", - "methods": "~1.1.2", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.12", - "proxy-addr": "~2.0.7", - "qs": "6.13.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.19.0", - "serve-static": "1.16.2", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, "packages/bruno-tests/node_modules/fast-xml-parser": { "version": "5.0.9", "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.0.9.tgz", @@ -27660,27 +28132,6 @@ "fxparser": "src/cli/cli.js" } }, - "packages/bruno-tests/node_modules/path-to-regexp": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", - "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", - "license": "MIT" - }, - "packages/bruno-tests/node_modules/qs": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", - "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", - "license": "BSD-3-Clause", - "dependencies": { - "side-channel": "^1.0.6" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "packages/bruno-tests/node_modules/strnum": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.0.5.tgz", diff --git a/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/AuthorizationCode/index.js b/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/AuthorizationCode/index.js index bae6e4a0d..fc274f47d 100644 --- a/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/AuthorizationCode/index.js +++ b/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/AuthorizationCode/index.js @@ -39,7 +39,8 @@ const OAuth2AuthorizationCode = ({ save, item = {}, request, handleRun, updateAu tokenQueryKey, refreshUrl, autoRefreshToken, - autoFetchToken + autoFetchToken, + authorizeInDefaultBrowser } = oAuth; const refreshUrlAvailable = refreshUrl?.trim() !== ''; @@ -130,6 +131,7 @@ const OAuth2AuthorizationCode = ({ save, item = {}, request, handleRun, updateAu refreshUrl, autoRefreshToken, autoFetchToken, + authorizeInDefaultBrowser, [key]: value, } }) @@ -157,6 +159,7 @@ const OAuth2AuthorizationCode = ({ save, item = {}, request, handleRun, updateAu tokenHeaderPrefix, tokenQueryKey, autoFetchToken, + authorizeInDefaultBrowser, pkce: !Boolean(oAuth?.['pkce']) } }) @@ -195,6 +198,24 @@ const OAuth2AuthorizationCode = ({ save, item = {}, request, handleRun, updateAu Configuration + {/* Authorize in default browser */} +
+ handleChange('authorizeInDefaultBrowser', e.target.checked)} + className={`cursor-pointer ml-1`} + /> + +
+
+ + + Use the default browser to authorize the user. + +
+
+
{inputsConfig.map((input) => { const { key, label, isSecret } = input; return ( diff --git a/packages/bruno-app/src/utils/collections/index.js b/packages/bruno-app/src/utils/collections/index.js index fb37cc455..75a975fca 100644 --- a/packages/bruno-app/src/utils/collections/index.js +++ b/packages/bruno-app/src/utils/collections/index.js @@ -416,6 +416,7 @@ export const transformCollectionToSaveToExportAsFile = (collection, options = {} tokenQueryKey: get(si.request, 'auth.oauth2.tokenQueryKey', ''), autoFetchToken: get(si.request, 'auth.oauth2.autoFetchToken', true), autoRefreshToken: get(si.request, 'auth.oauth2.autoRefreshToken', true), + authorizeInDefaultBrowser: get(si.request, 'auth.oauth2.authorizeInDefaultBrowser', ''), }; break; case 'client_credentials': diff --git a/packages/bruno-electron/package.json b/packages/bruno-electron/package.json index cc960f2fe..924753d6b 100644 --- a/packages/bruno-electron/package.json +++ b/packages/bruno-electron/package.json @@ -45,6 +45,7 @@ "electron-notarize": "^1.2.2", "electron-store": "^8.1.0", "electron-util": "^0.17.2", + "express": "^4.21.2", "form-data": "^4.0.0", "fs-extra": "^10.1.0", "graphql": "^16.6.0", diff --git a/packages/bruno-electron/src/ipc/network/interpolate-vars.js b/packages/bruno-electron/src/ipc/network/interpolate-vars.js index f4fb13bd5..381bac733 100644 --- a/packages/bruno-electron/src/ipc/network/interpolate-vars.js +++ b/packages/bruno-electron/src/ipc/network/interpolate-vars.js @@ -162,7 +162,6 @@ const interpolateVars = (request, envVariables = {}, runtimeVariables = {}, proc } if (request?.oauth2?.grantType) { - let username, password, scope, clientId, clientSecret; switch (request.oauth2.grantType) { case 'password': request.oauth2.accessTokenUrl = _interpolate(request.oauth2.accessTokenUrl) || ''; @@ -197,6 +196,8 @@ const interpolateVars = (request, envVariables = {}, runtimeVariables = {}, proc request.oauth2.tokenQueryKey = _interpolate(request.oauth2.tokenQueryKey) || ''; request.oauth2.autoFetchToken = _interpolate(request.oauth2.autoFetchToken); request.oauth2.autoRefreshToken = _interpolate(request.oauth2.autoRefreshToken); + request.oauth2.autoRefreshToken = _interpolate(request.oauth2.autoRefreshToken); + request.oauth2.authorizeInDefaultBrowser = _interpolate(request.oauth2.authorizeInDefaultBrowser); break; case 'client_credentials': request.oauth2.accessTokenUrl = _interpolate(request.oauth2.accessTokenUrl) || ''; diff --git a/packages/bruno-electron/src/ipc/network/prepare-request.js b/packages/bruno-electron/src/ipc/network/prepare-request.js index efc08cce6..ef7ed8243 100644 --- a/packages/bruno-electron/src/ipc/network/prepare-request.js +++ b/packages/bruno-electron/src/ipc/network/prepare-request.js @@ -108,7 +108,8 @@ const setAuthHeaders = (axiosRequest, request, collectionRoot) => { tokenHeaderPrefix: get(collectionAuth, 'oauth2.tokenHeaderPrefix'), tokenQueryKey: get(collectionAuth, 'oauth2.tokenQueryKey'), autoFetchToken: get(collectionAuth, 'oauth2.autoFetchToken'), - autoRefreshToken: get(collectionAuth, 'oauth2.autoRefreshToken') + autoRefreshToken: get(collectionAuth, 'oauth2.autoRefreshToken'), + authorizeInDefaultBrowser: get(collectionAuth, 'oauth2.authorizeInDefaultBrowser') }; break; case 'client_credentials': diff --git a/packages/bruno-electron/src/utils/oauth2-server.js b/packages/bruno-electron/src/utils/oauth2-server.js new file mode 100644 index 000000000..d809808cf --- /dev/null +++ b/packages/bruno-electron/src/utils/oauth2-server.js @@ -0,0 +1,68 @@ +const express = require("express"); +const { shell } = require("electron"); + +const BRUNO_OAUTH2_SERVER_PORT = 9876; +let { exec } = require('child_process'); +const portToPid = require("./pid-port"); + +let server; + +const freePort = async () => { + return new Promise(async (resolve, reject) => { + try { + const pid = await portToPid(BRUNO_OAUTH2_SERVER_PORT); + if(pid) { + if(process.platform === "win32") { + exec(`taskkill /PID ${pid} /F`) + } + else { + exec(`kill -9 ${pid}`); + } + } + else { + console.log("port is free"); + } + resolve(); + } + catch(err) { + reject(err); + } + }); +} + +async function getOauth2AuthorizationCodeUsingDefaultBrowser({ authorizeUrl, port = BRUNO_OAUTH2_SERVER_PORT }) { + await server?.close?.(); + await freePort(); + const redirectUri = `http://localhost:${port}/callback`; + const parsedAuthorizeUrl = new URL(authorizeUrl); + parsedAuthorizeUrl?.searchParams.set('redirect_uri', redirectUri); + const finalAuthorizeUrl = parsedAuthorizeUrl.href; + + return new Promise((resolve, reject) => { + const app = express(); + + app.get("/callback", (req, res) => { + const { code } = req.query; + if (!code) { + res.status(400).send("Authorization failed. No code received."); + reject(new Error("No authorization code received")); + return; + } + + res.send("Authorization successful. You can close this tab."); + resolve({ authorizationCode: code }); + server.close(); + }); + + server = app.listen(port, () => { + shell.openExternal(finalAuthorizeUrl); + }); + + // Ensure the server is cleaned up in case of error + server.on("error", (err) => { + reject(err); + }); + }); +} + +module.exports = { getOauth2AuthorizationCodeUsingDefaultBrowser }; diff --git a/packages/bruno-electron/src/utils/oauth2.js b/packages/bruno-electron/src/utils/oauth2.js index bfc1f20e3..bdc5473ad 100644 --- a/packages/bruno-electron/src/utils/oauth2.js +++ b/packages/bruno-electron/src/utils/oauth2.js @@ -3,7 +3,8 @@ const crypto = require('crypto'); const { authorizeUserInWindow } = require('../ipc/network/authorize-user-in-window'); const Oauth2Store = require('../store/oauth2'); const { makeAxiosInstance } = require('../ipc/network/axios-instance'); -const { safeParseJSON, safeStringifyJSON } = require('./common'); +const { safeParseJSON, safeStringifyJSON, uuid } = require('./common'); +const { getOauth2AuthorizationCodeUsingDefaultBrowser } = require('./oauth2-server'); const oauth2Store = new Oauth2Store(); @@ -47,7 +48,6 @@ const getOAuth2TokenUsingAuthorizationCode = async ({ request, collectionUid, fo scope, pkce, credentialsPlacement, - authorizationUrl, credentialsId, autoRefreshToken, autoFetchToken, @@ -107,7 +107,7 @@ const getOAuth2TokenUsingAuthorizationCode = async ({ request, collectionUid, fo } // Fetch new token process - const { authorizationCode, debugInfo } = await getOAuth2AuthorizationCode(requestCopy, codeChallenge, collectionUid); + let { authorizationCode, debugInfo } = await getOAuth2AuthorizationCode(requestCopy, codeChallenge, collectionUid); requestCopy.method = 'POST'; requestCopy.headers['content-type'] = 'application/x-www-form-urlencoded'; @@ -190,7 +190,7 @@ const getOAuth2TokenUsingAuthorizationCode = async ({ request, collectionUid, fo // Add the axios request and response info as a main request in debugInfo const axiosMainRequest = { - requestId: Date.now().toString(), + requestId: uuid(), request: { url: axiosRequestInfo?.url, method: axiosRequestInfo?.method, @@ -225,7 +225,7 @@ const getOAuth2TokenUsingAuthorizationCode = async ({ request, collectionUid, fo const getOAuth2AuthorizationCode = (request, codeChallenge, collectionUid) => { return new Promise(async (resolve, reject) => { const { oauth2 } = request; - const { callbackUrl, clientId, authorizationUrl, scope, state, pkce, accessTokenUrl } = oauth2; + const { callbackUrl, clientId, authorizationUrl, scope, state, pkce, accessTokenUrl, authorizeInDefaultBrowser = true } = oauth2; const authorizationUrlWithQueryParams = new URL(authorizationUrl); authorizationUrlWithQueryParams.searchParams.append('response_type', 'code'); @@ -245,11 +245,18 @@ const getOAuth2AuthorizationCode = (request, codeChallenge, collectionUid) => { } try { const authorizeUrl = authorizationUrlWithQueryParams.toString(); - const { authorizationCode, debugInfo } = await authorizeUserInWindow({ - authorizeUrl, - callbackUrl, - session: oauth2Store.getSessionIdOfCollection({ collectionUid, url: accessTokenUrl }) - }); + let authorizationCode, debugInfo; + if (authorizeInDefaultBrowser) { + ({ authorizationCode, debugInfo } = await getOauth2AuthorizationCodeUsingDefaultBrowser({ + authorizeUrl + })); + } else { + ({ authorizationCode, debugInfo } = await authorizeUserInWindow({ + authorizeUrl, + callbackUrl, + session: oauth2Store.getSessionIdOfCollection({ collectionUid, url: accessTokenUrl }) + })); + } resolve({ authorizationCode, debugInfo }); } catch (err) { reject(err); diff --git a/packages/bruno-electron/src/utils/pid-port.js b/packages/bruno-electron/src/utils/pid-port.js new file mode 100644 index 000000000..175363aa6 --- /dev/null +++ b/packages/bruno-electron/src/utils/pid-port.js @@ -0,0 +1,83 @@ +// https://github.com/sindresorhus/pid-port +// common js util function for the above library + +const { spawnSync } = require('node:child_process'); +const process = require('node:process'); + +const runCommand = (command, args) => { + const result = spawnSync(command, args, { encoding: 'utf-8' }); + if (result.error) { + throw result.error; + } + return result.stdout || ''; // Handle undefined stdout +}; + +const netstat = type => runCommand('netstat', ['-anv', '-p', type]); + +const macos = async () => { + const result = [netstat('tcp'), netstat('udp')]; + const tcp = result[0] || ''; + const headerStart = tcp?.indexOf('\n') + 1; + const header = tcp.slice(headerStart, tcp.indexOf('\n', headerStart)) || ''; + + return { + stdout: result.join('\n'), + addressColumn: 3, + pidColumn: header.includes('rxbytes') ? 10 : 8, + }; +}; + +const linux = async () => { + const stdout = runCommand('ss', ['-tunlp']) || ''; + return { stdout, addressColumn: 4, pidColumn: 6 }; +}; + +const windows = async () => { + const stdout = runCommand('netstat', ['-ano']) || ''; + return { stdout, addressColumn: 1, pidColumn: 4 }; +}; + +const isProtocol = value => /^\s*(tcp|udp)/i.test(value); + +const parsePid = pid => { + if (typeof pid !== 'string') { + return; + } + + const { groups } = /(?:^|",|",pid=)(?\d+)/.exec(pid) || {}; + return groups ? Number.parseInt(groups.pid, 10) : undefined; +}; + +const getPort = (port, { lines, addressColumn, pidColumn }) => { + const regex = new RegExp(`[.:]${port}$`); + const foundPort = lines.find(line => regex.test(line[addressColumn])); + if (!foundPort) { + return null; + } + return parsePid(foundPort[pidColumn]); +}; + +const implementation = process.platform === 'darwin' ? macos : (process.platform === 'linux' ? linux : windows); +const getList = async () => { + const { stdout, addressColumn, pidColumn } = await implementation(); + const lines = (stdout || '').split('\n') + .filter(line => isProtocol(line)) + .map(line => line.match(/\S+/g) || []); + return { lines, addressColumn, pidColumn }; +}; + +const portToPid = async port => { + if (Array.isArray(port)) { + const list = await getList(); + const tuples = await Promise.all(port.map(port_ => [port_, getPort(port_, list)])); + return new Map(tuples); + } + + if (!Number.isInteger(port)) { + throw new TypeError(`Expected an integer, got ${typeof port}`); + } + + return getPort(port, await getList()); +}; + +module.exports = portToPid; diff --git a/packages/bruno-lang/v2/src/bruToJson.js b/packages/bruno-lang/v2/src/bruToJson.js index 8243704d3..3034096ac 100644 --- a/packages/bruno-lang/v2/src/bruToJson.js +++ b/packages/bruno-lang/v2/src/bruToJson.js @@ -527,6 +527,7 @@ const sem = grammar.createSemantics().addAttribute('ast', { const tokenQueryKeyKey = _.find(auth, { name: 'token_query_key' }); const autoFetchTokenKey = _.find(auth, { name: 'auto_fetch_token' }); const autoRefreshTokenKey = _.find(auth, { name: 'auto_refresh_token' }); + const authorizeInDefaultBrowserKey = _.find(auth, { name: 'authorize_in_default_browser' }); return { auth: { oauth2: @@ -566,7 +567,8 @@ const sem = grammar.createSemantics().addAttribute('ast', { tokenHeaderPrefix: tokenHeaderPrefixKey?.value ? tokenHeaderPrefixKey.value : 'Bearer', tokenQueryKey: tokenQueryKeyKey?.value ? tokenQueryKeyKey.value : 'access_token', autoFetchToken: autoFetchTokenKey ? JSON.parse(autoFetchTokenKey?.value) : true, - autoRefreshToken: autoRefreshTokenKey ? JSON.parse(autoRefreshTokenKey?.value) : true + autoRefreshToken: autoRefreshTokenKey ? JSON.parse(autoRefreshTokenKey?.value) : true, + authorizeInDefaultBrowser: authorizeInDefaultBrowserKey ? JSON.parse(authorizeInDefaultBrowserKey?.value) : true } : grantTypeKey?.value && grantTypeKey?.value == 'client_credentials' ? { diff --git a/packages/bruno-lang/v2/src/collectionBruToJson.js b/packages/bruno-lang/v2/src/collectionBruToJson.js index 7376b71e0..f4636109d 100644 --- a/packages/bruno-lang/v2/src/collectionBruToJson.js +++ b/packages/bruno-lang/v2/src/collectionBruToJson.js @@ -287,6 +287,7 @@ const sem = grammar.createSemantics().addAttribute('ast', { const tokenQueryKeyKey = _.find(auth, { name: 'token_query_key' }); const autoFetchTokenKey = _.find(auth, { name: 'auto_fetch_token' }); const autoRefreshTokenKey = _.find(auth, { name: 'auto_refresh_token' }); + const authorizeInDefaultBrowserKey = _.find(auth, { name: 'authorize_in_default_browser' }); return { auth: { oauth2: @@ -326,7 +327,8 @@ const sem = grammar.createSemantics().addAttribute('ast', { tokenHeaderPrefix: tokenHeaderPrefixKey?.value ? tokenHeaderPrefixKey.value : 'Bearer', tokenQueryKey: tokenQueryKeyKey?.value ? tokenQueryKeyKey.value : 'access_token', autoFetchToken: autoFetchTokenKey ? JSON.parse(autoFetchTokenKey?.value) : true, - autoRefreshToken: autoRefreshTokenKey ? JSON.parse(autoRefreshTokenKey?.value) : true + autoRefreshToken: autoRefreshTokenKey ? JSON.parse(autoRefreshTokenKey?.value) : true, + authorizeInDefaultBrowser: authorizeInDefaultBrowserKey ? JSON.parse(authorizeInDefaultBrowserKey?.value) : true } : grantTypeKey?.value && grantTypeKey?.value == 'client_credentials' ? { diff --git a/packages/bruno-lang/v2/src/jsonToBru.js b/packages/bruno-lang/v2/src/jsonToBru.js index 547fe380f..b7512be24 100644 --- a/packages/bruno-lang/v2/src/jsonToBru.js +++ b/packages/bruno-lang/v2/src/jsonToBru.js @@ -196,8 +196,8 @@ ${indentString(`token_placement: ${auth?.oauth2?.tokenPlacement || ''}`)}${ }${ auth?.oauth2?.tokenPlacement !== 'header' ? '\n' + indentString(`token_query_key: ${auth?.oauth2?.tokenQueryKey || ''}`) : '' } -${indentString(`auto_fetch_token: ${auth?.oauth2?.autoFetchToken?.toString?.()}`)} -${indentString(`auto_refresh_token: ${auth?.oauth2?.autoRefreshToken?.toString?.()}`)} +${indentString(`auto_fetch_token: ${(auth?.oauth2?.autoFetchToken|| false).toString()}`)} +${indentString(`auto_refresh_token: ${(auth?.oauth2?.autoRefreshToken|| false).toString()}`)} } `; @@ -221,10 +221,10 @@ ${indentString(`token_placement: ${auth?.oauth2?.tokenPlacement || ''}`)}${ }${ auth?.oauth2?.tokenPlacement !== 'header' ? '\n' + indentString(`token_query_key: ${auth?.oauth2?.tokenQueryKey || ''}`) : '' } -${indentString(`auto_fetch_token: ${auth?.oauth2?.autoFetchToken?.toString?.()}`)} -${indentString(`auto_refresh_token: ${auth?.oauth2?.autoRefreshToken?.toString?.()}`)} +${indentString(`auto_fetch_token: ${(auth?.oauth2?.autoFetchToken|| false).toString()}`)} +${indentString(`auto_refresh_token: ${(auth?.oauth2?.autoRefreshToken|| false).toString()}`)} +${indentString(`authorize_in_default_browser: ${(auth?.oauth2?.authorizeInDefaultBrowser|| true).toString()}`)} } - `; break; case 'client_credentials': @@ -242,8 +242,8 @@ ${indentString(`token_placement: ${auth?.oauth2?.tokenPlacement || ''}`)}${ }${ auth?.oauth2?.tokenPlacement !== 'header' ? '\n' + indentString(`token_query_key: ${auth?.oauth2?.tokenQueryKey || ''}`) : '' } -${indentString(`auto_fetch_token: ${auth?.oauth2?.autoFetchToken.toString?.()}`)} -${indentString(`auto_refresh_token: ${auth?.oauth2?.autoRefreshToken.toString?.()}`)} +${indentString(`auto_fetch_token: ${(auth?.oauth2?.autoFetchToken|| false).toString()}`)} +${indentString(`auto_refresh_token: ${(auth?.oauth2?.autoRefreshToken|| false).toString()}`)} } `; diff --git a/packages/bruno-lang/v2/src/jsonToCollectionBru.js b/packages/bruno-lang/v2/src/jsonToCollectionBru.js index 16775720a..e91a5f7fb 100644 --- a/packages/bruno-lang/v2/src/jsonToCollectionBru.js +++ b/packages/bruno-lang/v2/src/jsonToCollectionBru.js @@ -189,6 +189,7 @@ ${indentString(`token_placement: ${auth?.oauth2?.tokenPlacement || ''}`)}${ } ${indentString(`auto_fetch_token: ${(auth?.oauth2?.autoFetchToken).toString()}`)} ${indentString(`auto_refresh_token: ${(auth?.oauth2?.autoRefreshToken).toString()}`)} +${indentString(`authorize_in_default_browser: ${(auth?.oauth2?.authorizeInDefaultBrowser|| true).toString()}`)} } `; diff --git a/packages/bruno-schema/src/collections/index.js b/packages/bruno-schema/src/collections/index.js index a4883b460..204171264 100644 --- a/packages/bruno-schema/src/collections/index.js +++ b/packages/bruno-schema/src/collections/index.js @@ -252,6 +252,11 @@ const oauth2Schema = Yup.object({ is: (val) => ['authorization_code'].includes(val), then: Yup.boolean().default(true), otherwise: Yup.boolean() + }), + authorizeInDefaultBrowser: Yup.boolean().when('grantType', { + is: (val) => ['authorization_code'].includes(val), + then: Yup.boolean().default(true), + otherwise: Yup.boolean() }) }) .noUnknown(true)