diff --git a/packages/hoppscotch-backend/.env.example b/packages/hoppscotch-backend/.env.example index 234df53fb..48f762ae2 100644 --- a/packages/hoppscotch-backend/.env.example +++ b/packages/hoppscotch-backend/.env.example @@ -13,3 +13,8 @@ ACCESS_TOKEN_VALIDITY="30s" # Default validity is 1 day # Hoppscotch App Domain Config APP_DOMAIN="http://localhost:3000" +# Google Auth Config +GOOGLE_CLIENT_ID="************************************************" +GOOGLE_CLIENT_SECRET="************************************************" +GOOGLE_CALLBACK_URL="************************************************" +GOOGLE_SCOPE= ['email', 'profile'], diff --git a/packages/hoppscotch-backend/.eslintrc.js b/packages/hoppscotch-backend/.eslintrc.js index 259de13c7..f8a28acdd 100644 --- a/packages/hoppscotch-backend/.eslintrc.js +++ b/packages/hoppscotch-backend/.eslintrc.js @@ -21,5 +21,7 @@ module.exports = { '@typescript-eslint/explicit-function-return-type': 'off', '@typescript-eslint/explicit-module-boundary-types': 'off', '@typescript-eslint/no-explicit-any': 'off', + "no-empty-function": "off", + "@typescript-eslint/no-empty-function": "error" }, }; diff --git a/packages/hoppscotch-backend/package.json b/packages/hoppscotch-backend/package.json index db5b1c483..011890024 100644 --- a/packages/hoppscotch-backend/package.json +++ b/packages/hoppscotch-backend/package.json @@ -29,7 +29,6 @@ "@nestjs/passport": "^9.0.0", "@nestjs/platform-express": "^9.2.1", "@prisma/client": "^4.7.1", - "@types/bcrypt": "^5.0.0", "apollo-server-express": "^3.11.1", "apollo-server-plugin-base": "^3.7.1", "argon2": "^0.30.3", @@ -45,7 +44,9 @@ "ioredis": "^5.2.4", "luxon": "^3.2.1", "passport": "^0.6.0", + "passport-google-oauth20": "^2.0.0", "passport-jwt": "^4.0.1", + "passport-local": "^1.0.0", "postmark": "^3.0.15", "prisma": "^4.7.1", "reflect-metadata": "^0.1.13", @@ -57,10 +58,14 @@ "@nestjs/schematics": "^9.0.3", "@nestjs/testing": "^9.2.1", "@relmify/jest-fp-ts": "^2.0.2", + "@types/argon2": "^0.15.0", + "@types/bcrypt": "^5.0.0", "@types/cookie-parser": "^1.4.3", "@types/express": "^4.17.14", "@types/jest": "^27.5.2", + "@types/luxon": "^3.2.0", "@types/node": "^18.11.10", + "@types/passport-google-oauth20": "^2.0.11", "@types/passport-jwt": "^3.0.8", "@types/supertest": "^2.0.12", "@typescript-eslint/eslint-plugin": "^5.45.0", @@ -70,6 +75,7 @@ "eslint-plugin-prettier": "^4.2.1", "jest": "^29.3.1", "jest-mock-extended": "^3.0.1", + "jwt": "link:@types/nestjs/jwt", "prettier": "^2.8.0", "source-map-support": "^0.5.21", "supertest": "^6.3.2", diff --git a/packages/hoppscotch-backend/pnpm-lock.yaml b/packages/hoppscotch-backend/pnpm-lock.yaml index bac499316..3e41538d3 100644 --- a/packages/hoppscotch-backend/pnpm-lock.yaml +++ b/packages/hoppscotch-backend/pnpm-lock.yaml @@ -13,11 +13,14 @@ specifiers: '@nestjs/testing': ^9.2.1 '@prisma/client': ^4.7.1 '@relmify/jest-fp-ts': ^2.0.2 + '@types/argon2': ^0.15.0 '@types/bcrypt': ^5.0.0 '@types/cookie-parser': ^1.4.3 '@types/express': ^4.17.14 '@types/jest': ^27.5.2 + '@types/luxon': ^3.2.0 '@types/node': ^18.11.10 + '@types/passport-google-oauth20': ^2.0.11 '@types/passport-jwt': ^3.0.8 '@types/supertest': ^2.0.12 '@typescript-eslint/eslint-plugin': ^5.45.0 @@ -40,9 +43,12 @@ specifiers: ioredis: ^5.2.4 jest: ^29.3.1 jest-mock-extended: ^3.0.1 + jwt: link:@types/nestjs/jwt luxon: ^3.2.1 passport: ^0.6.0 + passport-google-oauth20: ^2.0.0 passport-jwt: ^4.0.1 + passport-local: ^1.0.0 postmark: ^3.0.15 prettier: ^2.8.0 prisma: ^4.7.1 @@ -66,7 +72,6 @@ dependencies: '@nestjs/passport': 9.0.0_6o47igfla2pj7yzh7agpvpttka '@nestjs/platform-express': 9.2.1_hjcqpoaebdr7gdo5hgc22hthbe '@prisma/client': 4.8.1_prisma@4.8.1 - '@types/bcrypt': 5.0.0 apollo-server-express: 3.11.1_4mq2c443wwzwcb6dpxnwkfvrzm apollo-server-plugin-base: 3.7.1_graphql@15.8.0 argon2: 0.30.3 @@ -82,7 +87,9 @@ dependencies: ioredis: 5.2.4 luxon: 3.2.1 passport: 0.6.0 + passport-google-oauth20: 2.0.0 passport-jwt: 4.0.1 + passport-local: 1.0.0 postmark: 3.0.15 prisma: 4.8.1 reflect-metadata: 0.1.13 @@ -94,10 +101,14 @@ devDependencies: '@nestjs/schematics': 9.0.4_typescript@4.9.4 '@nestjs/testing': 9.2.1_wdbvfsxfdwzlwdfiyh2gynjl4m '@relmify/jest-fp-ts': 2.0.2_fp-ts@2.13.1+io-ts@2.2.20 + '@types/argon2': 0.15.0 + '@types/bcrypt': 5.0.0 '@types/cookie-parser': 1.4.3 '@types/express': 4.17.15 '@types/jest': 27.5.2 + '@types/luxon': 3.2.0 '@types/node': 18.11.18 + '@types/passport-google-oauth20': 2.0.11 '@types/passport-jwt': 3.0.8 '@types/supertest': 2.0.12 '@typescript-eslint/eslint-plugin': 5.48.1_3jon24igvnqaqexgwtxk6nkpse @@ -107,6 +118,7 @@ devDependencies: eslint-plugin-prettier: 4.2.1_iu5s7nk6dw7o3tajefwfiqfmge jest: 29.3.1_zfha7dvnw4nti6zkbsmhmn6xo4 jest-mock-extended: 3.0.1_p6ekqnroyms5nhqbfxosryz7rm + jwt: link:@types/nestjs/jwt prettier: 2.8.2 source-map-support: 0.5.21 supertest: 6.3.3 @@ -705,12 +717,12 @@ packages: tslib: 2.4.1 dev: false - /@graphql-tools/merge/8.3.14_graphql@15.8.0: - resolution: {integrity: sha512-zV0MU1DnxJLIB0wpL4N3u21agEiYFsjm6DI130jqHpwF0pR9HkF+Ni65BNfts4zQelP0GjkHltG+opaozAJ1NA==} + /@graphql-tools/merge/8.3.15_graphql@15.8.0: + resolution: {integrity: sha512-hYYOlsqkUlL6oOo7zzuk6hIv7xQzy+x21sgK84d5FWaiWYkLYh9As8myuDd9SD5xovWWQ9m/iRhIOVDEMSyEKA==} peerDependencies: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 dependencies: - '@graphql-tools/utils': 9.1.3_graphql@15.8.0 + '@graphql-tools/utils': 9.1.4_graphql@15.8.0 graphql: 15.8.0 tslib: 2.4.1 dev: false @@ -725,13 +737,13 @@ packages: tslib: 2.4.1 dev: false - /@graphql-tools/mock/8.7.14_graphql@15.8.0: - resolution: {integrity: sha512-kIYirhGqhhSI6p/5qj95U8Lngm4mml5B3Z/r7ShI4+/EACyOOV+wUlql45+Y21b9NRUxJbsNHpztGxzgCSyviQ==} + /@graphql-tools/mock/8.7.15_graphql@15.8.0: + resolution: {integrity: sha512-0zImG5tuObhowqtijlB6TMAIVtCIBsnGGwNW8gnCOa+xZAqfGdUMsSma17tHC2XuI7xhv7A0O8pika9e3APLUg==} peerDependencies: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 dependencies: - '@graphql-tools/schema': 9.0.12_graphql@15.8.0 - '@graphql-tools/utils': 9.1.3_graphql@15.8.0 + '@graphql-tools/schema': 9.0.13_graphql@15.8.0 + '@graphql-tools/utils': 9.1.4_graphql@15.8.0 fast-json-stable-stringify: 2.1.0 graphql: 15.8.0 tslib: 2.4.1 @@ -761,16 +773,16 @@ packages: value-or-promise: 1.0.11 dev: false - /@graphql-tools/schema/9.0.12_graphql@15.8.0: - resolution: {integrity: sha512-DmezcEltQai0V1y96nwm0Kg11FDS/INEFekD4nnVgzBqawvznWqK6D6bujn+cw6kivoIr3Uq//QmU/hBlBzUlQ==} + /@graphql-tools/schema/9.0.13_graphql@15.8.0: + resolution: {integrity: sha512-guRA3fwAtv+M1Kh930P4ydH9aKJTWscIkhVFcWpj/cnjYYxj88jkEJ15ZNiJX/2breNY+sbVgmlgLKb6aXi/Jg==} peerDependencies: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 dependencies: - '@graphql-tools/merge': 8.3.14_graphql@15.8.0 - '@graphql-tools/utils': 9.1.3_graphql@15.8.0 + '@graphql-tools/merge': 8.3.15_graphql@15.8.0 + '@graphql-tools/utils': 9.1.4_graphql@15.8.0 graphql: 15.8.0 tslib: 2.4.1 - value-or-promise: 1.0.11 + value-or-promise: 1.0.12 dev: false /@graphql-tools/utils/8.9.0_graphql@15.8.0: @@ -791,8 +803,8 @@ packages: tslib: 2.4.1 dev: false - /@graphql-tools/utils/9.1.3_graphql@15.8.0: - resolution: {integrity: sha512-bbJyKhs6awp1/OmP+WKA1GOyu9UbgZGkhIj5srmiMGLHohEOKMjW784Sk0BZil1w2x95UPu0WHw6/d/HVCACCg==} + /@graphql-tools/utils/9.1.4_graphql@15.8.0: + resolution: {integrity: sha512-hgIeLt95h9nQgQuzbbdhuZmh+8WV7RZ/6GbTj6t3IU4Zd2zs9yYJ2jgW/krO587GMOY8zCwrjNOMzD40u3l7Vg==} peerDependencies: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 dependencies: @@ -1151,7 +1163,6 @@ packages: transitivePeerDependencies: - encoding - supports-color - dev: false /@nestjs/apollo/10.1.7_vdmqjlnisg74yu3x345ranirlm: resolution: {integrity: sha512-UQDgUgyJvrj53AcCzws6/854SVibAeyg+RGxMtb9+ENhd8snP6f7RS6mCaFY85UTAc6mo674NIUu9a/JyeYezw==} @@ -1451,7 +1462,6 @@ packages: /@phc/format/1.0.0: resolution: {integrity: sha512-m7X9U6BG2+J+R1lSOdCiITLLrxm+cWlNI3HUFA92oLO77ObGNzaKdh8pMLqdZcshtkKuV84olNNXDfMc4FezBQ==} engines: {node: '>=10'} - dev: false /@prisma/client/4.8.1_prisma@4.8.1: resolution: {integrity: sha512-d4xhZhETmeXK/yZ7K0KcVOzEfI5YKGGEr4F5SBV04/MU4ncN/HcE28sy3e4Yt8UFW0ZuImKFQJE+9rWt9WbGSQ==} @@ -1571,6 +1581,16 @@ packages: '@types/node': 18.11.18 dev: false + /@types/argon2/0.15.0: + resolution: {integrity: sha512-AKQ8LR6bgmNHF7vhIQjD4EEbxITc1+1sTS9OKvkT5SaTfKw9OhFFExriod+H92biWIm23k7UT5VcF5ja9D+FIg==} + deprecated: This is a stub types definition for Argon2 (https://github.com/ranisalt/node-argon2). Argon2 provides its own type definitions, so you don't need @types/argon2 installed! + dependencies: + argon2: 0.30.3 + transitivePeerDependencies: + - encoding + - supports-color + dev: true + /@types/babel__core/7.1.20: resolution: {integrity: sha512-PVb6Bg2QuscZ30FvOU7z4guG6c926D9YRvOxEaelzndpMsvP+YM74Q/dAFASpg2l6+XLalxSGxcq/lrgYWZtyQ==} dependencies: @@ -1604,7 +1624,7 @@ packages: resolution: {integrity: sha512-agtcFKaruL8TmcvqbndlqHPSJgsolhf/qPWchFlgnW1gECTN/nKbFcoFnvKAQRFfKbh+BO6A3SWdJu9t+xF3Lw==} dependencies: '@types/node': 18.11.18 - dev: false + dev: true /@types/body-parser/1.19.2: resolution: {integrity: sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==} @@ -1732,6 +1752,10 @@ packages: resolution: {integrity: sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==} dev: false + /@types/luxon/3.2.0: + resolution: {integrity: sha512-lGmaGFoaXHuOLXFvuju2bfvZRqxAqkHPx9Y9IQdQABrinJJshJwfNCKV+u7rR3kJbiqfTF/NhOkcxxAFrObyaA==} + dev: true + /@types/mime/3.0.1: resolution: {integrity: sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==} @@ -1742,10 +1766,24 @@ packages: /@types/node/18.11.18: resolution: {integrity: sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==} + /@types/oauth/0.9.1: + resolution: {integrity: sha512-a1iY62/a3yhZ7qH7cNUsxoI3U/0Fe9+RnuFrpTKr+0WVOzbKlSLojShCKe20aOD1Sppv+i8Zlq0pLDuTJnwS4A==} + dependencies: + '@types/node': 18.11.18 + dev: true + /@types/parse-json/4.0.0: resolution: {integrity: sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==} dev: true + /@types/passport-google-oauth20/2.0.11: + resolution: {integrity: sha512-9XMT1GfwhZL7UQEiCepLef55RNPHkbrCtsU7rsWPTEOsmu5qVIW8nSemtB4p+P24CuOhA+IKkv8LsPThYghGww==} + dependencies: + '@types/express': 4.17.15 + '@types/passport': 1.0.11 + '@types/passport-oauth2': 1.4.11 + dev: true + /@types/passport-jwt/3.0.8: resolution: {integrity: sha512-VKJZDJUAHFhPHHYvxdqFcc5vlDht8Q2pL1/ePvKAgqRThDaCc84lSYOTQmnx3+JIkDlN+2KfhFhXIzlcVT+Pcw==} dependencies: @@ -1754,6 +1792,14 @@ packages: '@types/passport-strategy': 0.2.35 dev: true + /@types/passport-oauth2/1.4.11: + resolution: {integrity: sha512-KUNwmGhe/3xPbjkzkPwwcPmyFwfyiSgtV1qOrPBLaU4i4q9GSCdAOyCbkFG0gUxAyEmYwqo9OAF/rjPjJ6ImdA==} + dependencies: + '@types/express': 4.17.15 + '@types/oauth': 0.9.1 + '@types/passport': 1.0.11 + dev: true + /@types/passport-strategy/0.2.35: resolution: {integrity: sha512-o5D19Jy2XPFoX2rKApykY15et3Apgax00RRLf0RUotPDUsYrQa7x4howLYr9El2mlUApHmCMv5CZ1IXqKFQ2+g==} dependencies: @@ -2059,7 +2105,6 @@ packages: /abbrev/1.1.1: resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} - dev: false /accepts/1.3.8: resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} @@ -2102,7 +2147,6 @@ packages: debug: 4.3.4 transitivePeerDependencies: - supports-color - dev: false /ajv-formats/2.1.1: resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} @@ -2210,7 +2254,7 @@ packages: '@apollo/utils.usagereporting': 1.0.1_graphql@15.8.0 '@apollographql/apollo-tools': 0.5.4_graphql@15.8.0 '@apollographql/graphql-playground-html': 1.6.29 - '@graphql-tools/mock': 8.7.14_graphql@15.8.0 + '@graphql-tools/mock': 8.7.15_graphql@15.8.0 '@graphql-tools/schema': 8.5.1_graphql@15.8.0 '@josephg/resolvable': 1.0.1 apollo-datasource: 3.3.2 @@ -2313,7 +2357,6 @@ packages: /aproba/2.0.0: resolution: {integrity: sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==} - dev: false /are-we-there-yet/2.0.0: resolution: {integrity: sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==} @@ -2321,7 +2364,6 @@ packages: dependencies: delegates: 1.0.0 readable-stream: 3.6.0 - dev: false /arg/4.1.3: resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} @@ -2338,7 +2380,6 @@ packages: transitivePeerDependencies: - encoding - supports-color - dev: false /argparse/1.0.10: resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} @@ -2463,6 +2504,11 @@ packages: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} dev: true + /base64url/3.0.1: + resolution: {integrity: sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==} + engines: {node: '>=6.0.0'} + dev: false + /bcrypt/5.1.0: resolution: {integrity: sha512-RHBS7HI5N5tEnGTmtR/pppX0mmDSBpQ4aCBsj7CEQfYXDcO74A8sIBYcJMuCsis2E81zDxeENYhv66oZwLiA+Q==} engines: {node: '>= 10.0.0'} @@ -2523,7 +2569,7 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true dependencies: - caniuse-lite: 1.0.30001442 + caniuse-lite: 1.0.30001443 electron-to-chromium: 1.4.284 node-releases: 2.0.8 update-browserslist-db: 1.0.10_browserslist@4.21.4 @@ -2587,8 +2633,8 @@ packages: engines: {node: '>=10'} dev: true - /caniuse-lite/1.0.30001442: - resolution: {integrity: sha512-239m03Pqy0hwxYPYR5JwOIxRJfLTWtle9FV8zosfV5pHg+/51uD4nxcUlM8+mWWGfwKtt8lJNHnD3cWw9VZ6ow==} + /caniuse-lite/1.0.30001443: + resolution: {integrity: sha512-jUo8svymO8+Mkj3qbUbVjR8zv8LUGpGkUM/jKvc9SO2BvjCI980dp9fQbf/dyLs6RascPzgR4nhAKFA4OHeSaA==} dev: true /chalk/2.4.2: @@ -2641,7 +2687,6 @@ packages: /chownr/2.0.0: resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} engines: {node: '>=10'} - dev: false /chrome-trace-event/1.0.3: resolution: {integrity: sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==} @@ -2733,7 +2778,6 @@ packages: /color-support/1.1.3: resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==} hasBin: true - dev: false /combined-stream/1.0.8: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} @@ -2771,7 +2815,6 @@ packages: /console-control-strings/1.1.0: resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==} - dev: false /content-disposition/0.5.4: resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} @@ -2900,7 +2943,6 @@ packages: /delegates/1.0.0: resolution: {integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==} - dev: false /denque/2.1.0: resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==} @@ -2918,7 +2960,6 @@ packages: /detect-libc/2.0.1: resolution: {integrity: sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==} engines: {node: '>=8'} - dev: false /detect-newline/3.1.0: resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} @@ -3499,7 +3540,6 @@ packages: engines: {node: '>= 8'} dependencies: minipass: 3.3.6 - dev: false /fs-monkey/1.0.3: resolution: {integrity: sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q==} @@ -3531,7 +3571,6 @@ packages: string-width: 4.2.3 strip-ansi: 6.0.1 wide-align: 1.1.5 - dev: false /gensync/1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} @@ -3695,7 +3734,6 @@ packages: /has-unicode/2.0.1: resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==} - dev: false /has/1.0.3: resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} @@ -3730,7 +3768,6 @@ packages: debug: 4.3.4 transitivePeerDependencies: - supports-color - dev: false /human-signals/1.1.1: resolution: {integrity: sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==} @@ -4304,7 +4341,7 @@ packages: jest-util: 29.3.1 jest-validate: 29.3.1 resolve: 1.22.1 - resolve.exports: 1.1.0 + resolve.exports: 1.1.1 slash: 3.0.0 dev: true @@ -4787,14 +4824,12 @@ packages: engines: {node: '>=8'} dependencies: yallist: 4.0.0 - dev: false /minipass/4.0.0: resolution: {integrity: sha512-g2Uuh2jEKoht+zvO6vJqXmYpflPqzRBT+Th2h01DKh5z7wbY/AZ2gCQ78cP70YoHPyFdY30YBV5WxgLOEwOykw==} engines: {node: '>=8'} dependencies: yallist: 4.0.0 - dev: false /minizlib/2.1.2: resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} @@ -4802,7 +4837,6 @@ packages: dependencies: minipass: 3.3.6 yallist: 4.0.0 - dev: false /mkdirp/0.5.6: resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} @@ -4814,7 +4848,6 @@ packages: resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} engines: {node: '>=10'} hasBin: true - dev: false /ms/2.0.0: resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} @@ -4862,7 +4895,6 @@ packages: /node-addon-api/5.0.0: resolution: {integrity: sha512-CvkDw2OEnme7ybCykJpVcKH+uAOLV2qLqiyla128dN9TkEWfrYmxG6C2boDe5KcNQqZF3orkqzGgOMvZ/JNekA==} - dev: false /node-emoji/1.11.0: resolution: {integrity: sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==} @@ -4895,7 +4927,6 @@ packages: hasBin: true dependencies: abbrev: 1.1.1 - dev: false /normalize-path/3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} @@ -4915,6 +4946,9 @@ packages: console-control-strings: 1.1.0 gauge: 3.0.2 set-blocking: 2.0.0 + + /oauth/0.9.15: + resolution: {integrity: sha512-a5ERWK1kh38ExDEfoO6qUHJb32rd7aYmPHuyCu3Fta/cnICvYmgd2uhuKXvPD+PXB+gCEYYEaQdIRAjCOwAKNA==} dev: false /object-assign/4.1.1: @@ -5040,6 +5074,13 @@ packages: resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} engines: {node: '>= 0.8'} + /passport-google-oauth20/2.0.0: + resolution: {integrity: sha512-KSk6IJ15RoxuGq7D1UKK/8qKhNfzbLeLrG3gkLZ7p4A6DBCcv7xpyQwuXtWdpyR0+E0mwkpjY1VfPOhxQrKzdQ==} + engines: {node: '>= 0.4.0'} + dependencies: + passport-oauth2: 1.6.1 + dev: false + /passport-jwt/4.0.1: resolution: {integrity: sha512-UCKMDYhNuGOBE9/9Ycuoyh7vP6jpeTp/+sfMJl7nLff/t6dps+iaeE0hhNkKN8/HZHcJ7lCdOyDxHdDoxoSvdQ==} dependencies: @@ -5047,6 +5088,24 @@ packages: passport-strategy: 1.0.0 dev: false + /passport-local/1.0.0: + resolution: {integrity: sha512-9wCE6qKznvf9mQYYbgJ3sVOHmCWoUNMVFoZzNoznmISbhnNNPhN9xfY3sLmScHMetEJeoY7CXwfhCe7argfQow==} + engines: {node: '>= 0.4.0'} + dependencies: + passport-strategy: 1.0.0 + dev: false + + /passport-oauth2/1.6.1: + resolution: {integrity: sha512-ZbV43Hq9d/SBSYQ22GOiglFsjsD1YY/qdiptA+8ej+9C1dL1TVB+mBE5kDH/D4AJo50+2i8f4bx0vg4/yDDZCQ==} + engines: {node: '>= 0.4.0'} + dependencies: + base64url: 3.0.1 + oauth: 0.9.15 + passport-strategy: 1.0.0 + uid2: 0.0.4 + utils-merge: 1.0.1 + dev: false + /passport-strategy/1.0.0: resolution: {integrity: sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA==} engines: {node: '>= 0.4.0'} @@ -5207,8 +5266,8 @@ packages: once: 1.4.0 dev: true - /punycode/2.1.1: - resolution: {integrity: sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==} + /punycode/2.2.0: + resolution: {integrity: sha512-LN6QV1IJ9ZhxWTNdktaPClrNfp8xdSAYS0Zk2ddX7XsXZAxckMHPCBcHRo0cTcEIgYPRiGEkmji3Idkh2yFtYw==} engines: {node: '>=6'} dev: true @@ -5327,8 +5386,8 @@ packages: engines: {node: '>=8'} dev: true - /resolve.exports/1.1.0: - resolution: {integrity: sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==} + /resolve.exports/1.1.1: + resolution: {integrity: sha512-/NtpHNDN7jWhAaQ9BvBUYZ6YTXsRBgfqWFWP7BZBaoMJO/I3G5OFzvTuWNlZC3aPjins1F+TNrLKsGbH4rfsRQ==} engines: {node: '>=10'} dev: true @@ -5454,7 +5513,6 @@ packages: /set-blocking/2.0.0: resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} - dev: false /setprototypeof/1.2.0: resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} @@ -5707,7 +5765,6 @@ packages: minizlib: 2.1.2 mkdirp: 1.0.4 yallist: 4.0.0 - dev: false /terser-webpack-plugin/5.3.6_webpack@5.75.0: resolution: {integrity: sha512-kfLFk+PoLUQIbLmB1+PZDMRSZS99Mp+/MHqDNmMA6tOItzRt+Npe3E+fsMs5mfcM0wCtrrdU387UnV+vnSffXQ==} @@ -5954,6 +6011,10 @@ packages: hasBin: true dev: true + /uid2/0.0.4: + resolution: {integrity: sha512-IevTus0SbGwQzYh3+fRsAMTVVPOoIVufzacXcHPmdlle1jUpq7BRL+mw3dgeLanvGZdwwbWhRV6XrcFNdBmjWA==} + dev: false + /universalify/2.0.0: resolution: {integrity: sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==} engines: {node: '>= 10.0.0'} @@ -5977,7 +6038,7 @@ packages: /uri-js/4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} dependencies: - punycode: 2.1.1 + punycode: 2.2.0 dev: true /util-deprecate/1.0.2: @@ -6009,6 +6070,11 @@ packages: engines: {node: '>=12'} dev: false + /value-or-promise/1.0.12: + resolution: {integrity: sha512-Z6Uz+TYwEqE7ZN50gwn+1LCVo9ZVrpxRPOhOLnncYkY1ZzOYtrX8Fwf/rFktZ8R5mJms6EZf5TqNOMeZmnPq9Q==} + engines: {node: '>=12'} + dev: false + /vary/1.1.2: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} @@ -6109,7 +6175,6 @@ packages: resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==} dependencies: string-width: 4.2.3 - dev: false /windows-release/4.0.0: resolution: {integrity: sha512-OxmV4wzDKB1x7AZaZgXMVsdJ1qER1ed83ZrTYd5Bwq2HfJVg3DJS8nqlAG4sMoJ7mu8cuRmLEYyU13BKwctRAg==} diff --git a/packages/hoppscotch-backend/src/auth/auth.controller.ts b/packages/hoppscotch-backend/src/auth/auth.controller.ts index d4ed1d6cb..f9df68573 100644 --- a/packages/hoppscotch-backend/src/auth/auth.controller.ts +++ b/packages/hoppscotch-backend/src/auth/auth.controller.ts @@ -19,6 +19,7 @@ import { RTJwtAuthGuard } from './guards/rt-jwt-auth.guard'; import { GqlUser } from 'src/decorators/gql-user.decorator'; import { AuthUser } from 'src/types/AuthUser'; import { RTCookie } from 'src/decorators/rt-cookie.decorator'; +import { AuthGuard } from '@nestjs/passport'; @Controller('auth') export class AuthController { @@ -52,4 +53,16 @@ export class AuthController { if (E.isLeft(newTokenPair)) throwHTTPErr(newTokenPair.left); authCookieHandler(res, newTokenPair.right, false); } + + @Get('google') + @UseGuards(AuthGuard('google')) + async googleAuth(@Request() req) {} + + @Get('google/callback') + @UseGuards(AuthGuard('google')) + async googleAuthRedirect(@Request() req, @Res() res) { + const authTokens = await this.authService.generateAuthTokens(req.user.id); + if (E.isLeft(authTokens)) throwHTTPErr(authTokens.left); + authCookieHandler(res, authTokens.right, true); + } } diff --git a/packages/hoppscotch-backend/src/auth/auth.module.ts b/packages/hoppscotch-backend/src/auth/auth.module.ts index 8fa6bb150..7bad87726 100644 --- a/packages/hoppscotch-backend/src/auth/auth.module.ts +++ b/packages/hoppscotch-backend/src/auth/auth.module.ts @@ -8,6 +8,7 @@ import { PassportModule } from '@nestjs/passport'; import { JwtModule } from '@nestjs/jwt/dist'; import { JwtStrategy } from './strategies/jwt.strategy'; import { RTJwtStrategy } from './strategies/rt-jwt.strategy'; +import { GoogleStrategy } from './strategies/google.strategy'; @Module({ imports: [ @@ -19,7 +20,7 @@ import { RTJwtStrategy } from './strategies/rt-jwt.strategy'; secret: process.env.JWT_SECRET, }), ], - providers: [AuthService, JwtStrategy, RTJwtStrategy], + providers: [AuthService, JwtStrategy, RTJwtStrategy, GoogleStrategy], controllers: [AuthController], }) export class AuthModule {} diff --git a/packages/hoppscotch-backend/src/auth/strategies/google.strategy.ts b/packages/hoppscotch-backend/src/auth/strategies/google.strategy.ts new file mode 100644 index 000000000..f47ce8464 --- /dev/null +++ b/packages/hoppscotch-backend/src/auth/strategies/google.strategy.ts @@ -0,0 +1,35 @@ +import { Strategy, VerifyCallback } from 'passport-google-oauth20'; +import { PassportStrategy } from '@nestjs/passport'; +import { Injectable } from '@nestjs/common'; +import { UserService } from 'src/user/user.service'; +import * as O from 'fp-ts/Option'; + +@Injectable() +export class GoogleStrategy extends PassportStrategy(Strategy) { + constructor(private usersService: UserService) { + super({ + clientID: process.env.GOOGLE_CLIENT_ID, + clientSecret: process.env.GOOGLE_CLIENT_SECRET, + callbackURL: process.env.GOOGLE_CALLBACK_URL, + scope: process.env.GOOGLE_SCOPE.split(','), + }); + } + + async validate(accessToken, refreshToken, profile, done: VerifyCallback) { + const user = await this.usersService.findUserByEmail( + profile.emails[0].value, + ); + console.log('user log', user); + + if (O.isNone(user)) { + const createdUser = await this.usersService.createUserSSO( + accessToken, + refreshToken, + profile, + ); + return createdUser; + } + + return user.value; + } +} diff --git a/packages/hoppscotch-backend/src/utils.ts b/packages/hoppscotch-backend/src/utils.ts index d2fa14cdb..2779b1a56 100644 --- a/packages/hoppscotch-backend/src/utils.ts +++ b/packages/hoppscotch-backend/src/utils.ts @@ -157,6 +157,6 @@ export const authCookieHandler = ( sameSite: 'lax', }); if (redirect) { - res.status(HttpStatus.OK).redirect('/'); + res.status(HttpStatus.OK).redirect('http://localhost:3000/'); } else res.status(HttpStatus.OK).send(); };