Compare commits
No commits in common. "65647ccd1f3d6ebac483ff9fb816652dbb2c4a12" and "dbd761bafd1eeb99a9bcb8ee2f090ea693cf282f" have entirely different histories.
65647ccd1f
...
dbd761bafd
|
@ -23,17 +23,10 @@
|
|||
"@nestjs/common": "^10.0.0",
|
||||
"@nestjs/config": "^3.2.2",
|
||||
"@nestjs/core": "^10.0.0",
|
||||
"@nestjs/jwt": "^10.2.0",
|
||||
"@nestjs/passport": "^10.0.3",
|
||||
"@nestjs/platform-express": "^10.0.0",
|
||||
"@nestjs/swagger": "^7.3.1",
|
||||
"@nestjs/typeorm": "^10.0.2",
|
||||
"class-transformer": "^0.5.1",
|
||||
"class-validator": "^0.14.1",
|
||||
"install": "^0.13.0",
|
||||
"passport": "^0.7.0",
|
||||
"passport-jwt": "^4.0.1",
|
||||
"passport-local": "^1.0.0",
|
||||
"pg": "^8.11.5",
|
||||
"reflect-metadata": "^0.2.0",
|
||||
"rxjs": "^7.8.1",
|
||||
|
@ -44,7 +37,6 @@
|
|||
"@nestjs/cli": "^10.0.0",
|
||||
"@nestjs/schematics": "^10.0.0",
|
||||
"@nestjs/testing": "^10.0.0",
|
||||
"@types/argon2": "^0.15.0",
|
||||
"@types/express": "^4.17.17",
|
||||
"@types/jest": "^29.5.2",
|
||||
"@types/node": "^20.3.1",
|
||||
|
|
|
@ -7,46 +7,25 @@ settings:
|
|||
dependencies:
|
||||
'@nestjs/common':
|
||||
specifier: ^10.0.0
|
||||
version: 10.3.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1)
|
||||
version: 10.3.7(reflect-metadata@0.2.2)(rxjs@7.8.1)
|
||||
'@nestjs/config':
|
||||
specifier: ^3.2.2
|
||||
version: 3.2.2(@nestjs/common@10.3.7)(rxjs@7.8.1)
|
||||
'@nestjs/core':
|
||||
specifier: ^10.0.0
|
||||
version: 10.3.7(@nestjs/common@10.3.7)(@nestjs/platform-express@10.3.7)(reflect-metadata@0.2.2)(rxjs@7.8.1)
|
||||
'@nestjs/jwt':
|
||||
specifier: ^10.2.0
|
||||
version: 10.2.0(@nestjs/common@10.3.7)
|
||||
'@nestjs/passport':
|
||||
specifier: ^10.0.3
|
||||
version: 10.0.3(@nestjs/common@10.3.7)(passport@0.7.0)
|
||||
'@nestjs/platform-express':
|
||||
specifier: ^10.0.0
|
||||
version: 10.3.7(@nestjs/common@10.3.7)(@nestjs/core@10.3.7)
|
||||
'@nestjs/swagger':
|
||||
specifier: ^7.3.1
|
||||
version: 7.3.1(@nestjs/common@10.3.7)(@nestjs/core@10.3.7)(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)
|
||||
version: 7.3.1(@nestjs/common@10.3.7)(@nestjs/core@10.3.7)(reflect-metadata@0.2.2)
|
||||
'@nestjs/typeorm':
|
||||
specifier: ^10.0.2
|
||||
version: 10.0.2(@nestjs/common@10.3.7)(@nestjs/core@10.3.7)(reflect-metadata@0.2.2)(rxjs@7.8.1)(typeorm@0.3.20)
|
||||
class-transformer:
|
||||
specifier: ^0.5.1
|
||||
version: 0.5.1
|
||||
class-validator:
|
||||
specifier: ^0.14.1
|
||||
version: 0.14.1
|
||||
install:
|
||||
specifier: ^0.13.0
|
||||
version: 0.13.0
|
||||
passport:
|
||||
specifier: ^0.7.0
|
||||
version: 0.7.0
|
||||
passport-jwt:
|
||||
specifier: ^4.0.1
|
||||
version: 4.0.1
|
||||
passport-local:
|
||||
specifier: ^1.0.0
|
||||
version: 1.0.0
|
||||
pg:
|
||||
specifier: ^8.11.5
|
||||
version: 8.11.5
|
||||
|
@ -73,9 +52,6 @@ devDependencies:
|
|||
'@nestjs/testing':
|
||||
specifier: ^10.0.0
|
||||
version: 10.3.7(@nestjs/common@10.3.7)(@nestjs/core@10.3.7)(@nestjs/platform-express@10.3.7)
|
||||
'@types/argon2':
|
||||
specifier: ^0.15.0
|
||||
version: 0.15.0
|
||||
'@types/express':
|
||||
specifier: ^4.17.17
|
||||
version: 4.17.21
|
||||
|
@ -930,7 +906,7 @@ packages:
|
|||
- webpack-cli
|
||||
dev: true
|
||||
|
||||
/@nestjs/common@10.3.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1):
|
||||
/@nestjs/common@10.3.7(reflect-metadata@0.2.2)(rxjs@7.8.1):
|
||||
resolution: {integrity: sha512-gKFtFzcJznrwsRYjtNZoPAvSOPYdNgxbTYoAyLTpoy393cIKgLmJTHu6ReH8/qIB9AaZLdGaFLkx98W/tFWFUw==}
|
||||
peerDependencies:
|
||||
class-transformer: '*'
|
||||
|
@ -943,8 +919,6 @@ packages:
|
|||
class-validator:
|
||||
optional: true
|
||||
dependencies:
|
||||
class-transformer: 0.5.1
|
||||
class-validator: 0.14.1
|
||||
iterare: 1.2.1
|
||||
reflect-metadata: 0.2.2
|
||||
rxjs: 7.8.1
|
||||
|
@ -957,7 +931,7 @@ packages:
|
|||
'@nestjs/common': ^8.0.0 || ^9.0.0 || ^10.0.0
|
||||
rxjs: ^7.1.0
|
||||
dependencies:
|
||||
'@nestjs/common': 10.3.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1)
|
||||
'@nestjs/common': 10.3.7(reflect-metadata@0.2.2)(rxjs@7.8.1)
|
||||
dotenv: 16.4.5
|
||||
dotenv-expand: 10.0.0
|
||||
lodash: 4.17.21
|
||||
|
@ -983,7 +957,7 @@ packages:
|
|||
'@nestjs/websockets':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@nestjs/common': 10.3.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1)
|
||||
'@nestjs/common': 10.3.7(reflect-metadata@0.2.2)(rxjs@7.8.1)
|
||||
'@nestjs/platform-express': 10.3.7(@nestjs/common@10.3.7)(@nestjs/core@10.3.7)
|
||||
'@nuxtjs/opencollective': 0.3.2
|
||||
fast-safe-stringify: 2.1.1
|
||||
|
@ -996,17 +970,7 @@ packages:
|
|||
transitivePeerDependencies:
|
||||
- encoding
|
||||
|
||||
/@nestjs/jwt@10.2.0(@nestjs/common@10.3.7):
|
||||
resolution: {integrity: sha512-x8cG90SURkEiLOehNaN2aRlotxT0KZESUliOPKKnjWiyJOcWurkF3w345WOX0P4MgFzUjGoZ1Sy0aZnxeihT0g==}
|
||||
peerDependencies:
|
||||
'@nestjs/common': ^8.0.0 || ^9.0.0 || ^10.0.0
|
||||
dependencies:
|
||||
'@nestjs/common': 10.3.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1)
|
||||
'@types/jsonwebtoken': 9.0.5
|
||||
jsonwebtoken: 9.0.2
|
||||
dev: false
|
||||
|
||||
/@nestjs/mapped-types@2.0.5(@nestjs/common@10.3.7)(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2):
|
||||
/@nestjs/mapped-types@2.0.5(@nestjs/common@10.3.7)(reflect-metadata@0.2.2):
|
||||
resolution: {integrity: sha512-bSJv4pd6EY99NX9CjBIyn4TVDoSit82DUZlL4I3bqNfy5Gt+gXTa86i3I/i0iIV9P4hntcGM5GyO+FhZAhxtyg==}
|
||||
peerDependencies:
|
||||
'@nestjs/common': ^8.0.0 || ^9.0.0 || ^10.0.0
|
||||
|
@ -1019,29 +983,17 @@ packages:
|
|||
class-validator:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@nestjs/common': 10.3.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1)
|
||||
class-transformer: 0.5.1
|
||||
class-validator: 0.14.1
|
||||
'@nestjs/common': 10.3.7(reflect-metadata@0.2.2)(rxjs@7.8.1)
|
||||
reflect-metadata: 0.2.2
|
||||
dev: false
|
||||
|
||||
/@nestjs/passport@10.0.3(@nestjs/common@10.3.7)(passport@0.7.0):
|
||||
resolution: {integrity: sha512-znJ9Y4S8ZDVY+j4doWAJ8EuuVO7SkQN3yOBmzxbGaXbvcSwFDAdGJ+OMCg52NdzIO4tQoN4pYKx8W6M0ArfFRQ==}
|
||||
peerDependencies:
|
||||
'@nestjs/common': ^8.0.0 || ^9.0.0 || ^10.0.0
|
||||
passport: ^0.4.0 || ^0.5.0 || ^0.6.0 || ^0.7.0
|
||||
dependencies:
|
||||
'@nestjs/common': 10.3.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1)
|
||||
passport: 0.7.0
|
||||
dev: false
|
||||
|
||||
/@nestjs/platform-express@10.3.7(@nestjs/common@10.3.7)(@nestjs/core@10.3.7):
|
||||
resolution: {integrity: sha512-noNJ+PyIxQJLCKfuXz0tcQtlVAynfLIuKy62g70lEZ86UrIqSrZFqvWs/rFUgkbT6J8H7Rmv11hASOnX+7M2rA==}
|
||||
peerDependencies:
|
||||
'@nestjs/common': ^10.0.0
|
||||
'@nestjs/core': ^10.0.0
|
||||
dependencies:
|
||||
'@nestjs/common': 10.3.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1)
|
||||
'@nestjs/common': 10.3.7(reflect-metadata@0.2.2)(rxjs@7.8.1)
|
||||
'@nestjs/core': 10.3.7(@nestjs/common@10.3.7)(@nestjs/platform-express@10.3.7)(reflect-metadata@0.2.2)(rxjs@7.8.1)
|
||||
body-parser: 1.20.2
|
||||
cors: 2.8.5
|
||||
|
@ -1081,7 +1033,7 @@ packages:
|
|||
- chokidar
|
||||
dev: true
|
||||
|
||||
/@nestjs/swagger@7.3.1(@nestjs/common@10.3.7)(@nestjs/core@10.3.7)(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2):
|
||||
/@nestjs/swagger@7.3.1(@nestjs/common@10.3.7)(@nestjs/core@10.3.7)(reflect-metadata@0.2.2):
|
||||
resolution: {integrity: sha512-LUC4mr+5oAleEC/a2j8pNRh1S5xhKXJ1Gal5ZdRjt9XebQgbngXCdW7JTA9WOEcwGtFZN9EnKYdquzH971LZfw==}
|
||||
peerDependencies:
|
||||
'@fastify/static': ^6.0.0 || ^7.0.0
|
||||
|
@ -1099,11 +1051,9 @@ packages:
|
|||
optional: true
|
||||
dependencies:
|
||||
'@microsoft/tsdoc': 0.14.2
|
||||
'@nestjs/common': 10.3.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1)
|
||||
'@nestjs/common': 10.3.7(reflect-metadata@0.2.2)(rxjs@7.8.1)
|
||||
'@nestjs/core': 10.3.7(@nestjs/common@10.3.7)(@nestjs/platform-express@10.3.7)(reflect-metadata@0.2.2)(rxjs@7.8.1)
|
||||
'@nestjs/mapped-types': 2.0.5(@nestjs/common@10.3.7)(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)
|
||||
class-transformer: 0.5.1
|
||||
class-validator: 0.14.1
|
||||
'@nestjs/mapped-types': 2.0.5(@nestjs/common@10.3.7)(reflect-metadata@0.2.2)
|
||||
js-yaml: 4.1.0
|
||||
lodash: 4.17.21
|
||||
path-to-regexp: 3.2.0
|
||||
|
@ -1124,7 +1074,7 @@ packages:
|
|||
'@nestjs/platform-express':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@nestjs/common': 10.3.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1)
|
||||
'@nestjs/common': 10.3.7(reflect-metadata@0.2.2)(rxjs@7.8.1)
|
||||
'@nestjs/core': 10.3.7(@nestjs/common@10.3.7)(@nestjs/platform-express@10.3.7)(reflect-metadata@0.2.2)(rxjs@7.8.1)
|
||||
'@nestjs/platform-express': 10.3.7(@nestjs/common@10.3.7)(@nestjs/core@10.3.7)
|
||||
tslib: 2.6.2
|
||||
|
@ -1139,7 +1089,7 @@ packages:
|
|||
rxjs: ^7.2.0
|
||||
typeorm: ^0.3.0
|
||||
dependencies:
|
||||
'@nestjs/common': 10.3.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1)
|
||||
'@nestjs/common': 10.3.7(reflect-metadata@0.2.2)(rxjs@7.8.1)
|
||||
'@nestjs/core': 10.3.7(@nestjs/common@10.3.7)(@nestjs/platform-express@10.3.7)(reflect-metadata@0.2.2)(rxjs@7.8.1)
|
||||
reflect-metadata: 0.2.2
|
||||
rxjs: 7.8.1
|
||||
|
@ -1179,11 +1129,6 @@ packages:
|
|||
transitivePeerDependencies:
|
||||
- encoding
|
||||
|
||||
/@phc/format@1.0.0:
|
||||
resolution: {integrity: sha512-m7X9U6BG2+J+R1lSOdCiITLLrxm+cWlNI3HUFA92oLO77ObGNzaKdh8pMLqdZcshtkKuV84olNNXDfMc4FezBQ==}
|
||||
engines: {node: '>=10'}
|
||||
dev: true
|
||||
|
||||
/@pkgjs/parseargs@0.11.0:
|
||||
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
|
||||
engines: {node: '>=14'}
|
||||
|
@ -1227,13 +1172,6 @@ packages:
|
|||
/@tsconfig/node16@1.0.4:
|
||||
resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==}
|
||||
|
||||
/@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.40.1
|
||||
dev: true
|
||||
|
||||
/@types/babel__core@7.20.5:
|
||||
resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==}
|
||||
dependencies:
|
||||
|
@ -1353,12 +1291,6 @@ packages:
|
|||
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
|
||||
dev: true
|
||||
|
||||
/@types/jsonwebtoken@9.0.5:
|
||||
resolution: {integrity: sha512-VRLSGzik+Unrup6BsouBeHsf4d1hOEgYWTm/7Nmw1sXoN1+tRly/Gy/po3yeahnP4jfnQWWAhQAqcNfH7ngOkA==}
|
||||
dependencies:
|
||||
'@types/node': 20.12.4
|
||||
dev: false
|
||||
|
||||
/@types/methods@1.1.4:
|
||||
resolution: {integrity: sha512-ymXWVrDiCxTBE3+RIrrP533E70eA+9qu7zdWoHuOmGujkYtzf4HQF96b8nwHLqhuf4ykX61IGRIB38CC6/sImQ==}
|
||||
dev: true
|
||||
|
@ -1418,9 +1350,6 @@ packages:
|
|||
'@types/superagent': 8.1.6
|
||||
dev: true
|
||||
|
||||
/@types/validator@13.11.9:
|
||||
resolution: {integrity: sha512-FCTsikRozryfayPuiI46QzH3fnrOoctTjvOYZkho9BTFLCOZ2rgZJHMOVgCOfttjPJcgOx52EpkY0CMfy87MIw==}
|
||||
|
||||
/@types/yargs-parser@21.0.3:
|
||||
resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==}
|
||||
dev: true
|
||||
|
@ -1815,16 +1744,6 @@ packages:
|
|||
/arg@4.1.3:
|
||||
resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==}
|
||||
|
||||
/argon2@0.40.1:
|
||||
resolution: {integrity: sha512-DjtHDwd7pm12qeWyfihHoM8Bn5vGcgH6sKwgPqwNYroRmxlrzadHEvMyuvQxN/V8YSyRRKD5x6ito09q1e9OyA==}
|
||||
engines: {node: '>=16.17.0'}
|
||||
requiresBuild: true
|
||||
dependencies:
|
||||
'@phc/format': 1.0.0
|
||||
node-addon-api: 7.1.0
|
||||
node-gyp-build: 4.8.1
|
||||
dev: true
|
||||
|
||||
/argparse@1.0.10:
|
||||
resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==}
|
||||
dependencies:
|
||||
|
@ -2007,10 +1926,6 @@ packages:
|
|||
node-int64: 0.4.0
|
||||
dev: true
|
||||
|
||||
/buffer-equal-constant-time@1.0.1:
|
||||
resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==}
|
||||
dev: false
|
||||
|
||||
/buffer-from@1.1.2:
|
||||
resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
|
||||
|
||||
|
@ -2126,16 +2041,6 @@ packages:
|
|||
resolution: {integrity: sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==}
|
||||
dev: true
|
||||
|
||||
/class-transformer@0.5.1:
|
||||
resolution: {integrity: sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==}
|
||||
|
||||
/class-validator@0.14.1:
|
||||
resolution: {integrity: sha512-2VEG9JICxIqTpoK1eMzZqaV+u/EiwEJkMGzTrZf6sU/fwsnOITVgYJ8yojSy6CaXtO9V0Cc6ZQZ8h8m4UBuLwQ==}
|
||||
dependencies:
|
||||
'@types/validator': 13.11.9
|
||||
libphonenumber-js: 1.10.61
|
||||
validator: 13.11.0
|
||||
|
||||
/cli-cursor@3.1.0:
|
||||
resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==}
|
||||
engines: {node: '>=8'}
|
||||
|
@ -2475,12 +2380,6 @@ packages:
|
|||
/eastasianwidth@0.2.0:
|
||||
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
|
||||
|
||||
/ecdsa-sig-formatter@1.0.11:
|
||||
resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==}
|
||||
dependencies:
|
||||
safe-buffer: 5.2.1
|
||||
dev: false
|
||||
|
||||
/ee-first@1.1.1:
|
||||
resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
|
||||
|
||||
|
@ -3895,37 +3794,6 @@ packages:
|
|||
graceful-fs: 4.2.11
|
||||
dev: true
|
||||
|
||||
/jsonwebtoken@9.0.2:
|
||||
resolution: {integrity: sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==}
|
||||
engines: {node: '>=12', npm: '>=6'}
|
||||
dependencies:
|
||||
jws: 3.2.2
|
||||
lodash.includes: 4.3.0
|
||||
lodash.isboolean: 3.0.3
|
||||
lodash.isinteger: 4.0.4
|
||||
lodash.isnumber: 3.0.3
|
||||
lodash.isplainobject: 4.0.6
|
||||
lodash.isstring: 4.0.1
|
||||
lodash.once: 4.1.1
|
||||
ms: 2.1.3
|
||||
semver: 7.6.0
|
||||
dev: false
|
||||
|
||||
/jwa@1.4.1:
|
||||
resolution: {integrity: sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==}
|
||||
dependencies:
|
||||
buffer-equal-constant-time: 1.0.1
|
||||
ecdsa-sig-formatter: 1.0.11
|
||||
safe-buffer: 5.2.1
|
||||
dev: false
|
||||
|
||||
/jws@3.2.2:
|
||||
resolution: {integrity: sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==}
|
||||
dependencies:
|
||||
jwa: 1.4.1
|
||||
safe-buffer: 5.2.1
|
||||
dev: false
|
||||
|
||||
/keyv@4.5.4:
|
||||
resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
|
||||
dependencies:
|
||||
|
@ -3950,9 +3818,6 @@ packages:
|
|||
type-check: 0.4.0
|
||||
dev: true
|
||||
|
||||
/libphonenumber-js@1.10.61:
|
||||
resolution: {integrity: sha512-TsQsyzDttDvvzWNkbp/i0fVbzTGJIG0mUu/uNalIaRQEYeJxVQ/FPg+EJgSqfSXezREjM0V3RZ8cLVsKYhhw0Q==}
|
||||
|
||||
/lines-and-columns@1.2.4:
|
||||
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
|
||||
dev: true
|
||||
|
@ -3976,30 +3841,6 @@ packages:
|
|||
p-locate: 5.0.0
|
||||
dev: true
|
||||
|
||||
/lodash.includes@4.3.0:
|
||||
resolution: {integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==}
|
||||
dev: false
|
||||
|
||||
/lodash.isboolean@3.0.3:
|
||||
resolution: {integrity: sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==}
|
||||
dev: false
|
||||
|
||||
/lodash.isinteger@4.0.4:
|
||||
resolution: {integrity: sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==}
|
||||
dev: false
|
||||
|
||||
/lodash.isnumber@3.0.3:
|
||||
resolution: {integrity: sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==}
|
||||
dev: false
|
||||
|
||||
/lodash.isplainobject@4.0.6:
|
||||
resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==}
|
||||
dev: false
|
||||
|
||||
/lodash.isstring@4.0.1:
|
||||
resolution: {integrity: sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==}
|
||||
dev: false
|
||||
|
||||
/lodash.memoize@4.1.2:
|
||||
resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==}
|
||||
dev: true
|
||||
|
@ -4008,10 +3849,6 @@ packages:
|
|||
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
|
||||
dev: true
|
||||
|
||||
/lodash.once@4.1.1:
|
||||
resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==}
|
||||
dev: false
|
||||
|
||||
/lodash@4.17.21:
|
||||
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
|
||||
|
||||
|
@ -4038,6 +3875,7 @@ packages:
|
|||
engines: {node: '>=10'}
|
||||
dependencies:
|
||||
yallist: 4.0.0
|
||||
dev: true
|
||||
|
||||
/magic-string@0.30.5:
|
||||
resolution: {integrity: sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==}
|
||||
|
@ -4227,11 +4065,6 @@ packages:
|
|||
resolution: {integrity: sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==}
|
||||
dev: true
|
||||
|
||||
/node-addon-api@7.1.0:
|
||||
resolution: {integrity: sha512-mNcltoe1R8o7STTegSOHdnJNN7s5EUvhoS7ShnTHDyOSd+8H+UdWODq6qSv67PjC8Zc5JRT8+oLAMCr0SIXw7g==}
|
||||
engines: {node: ^16 || ^18 || >= 20}
|
||||
dev: true
|
||||
|
||||
/node-emoji@1.11.0:
|
||||
resolution: {integrity: sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==}
|
||||
dependencies:
|
||||
|
@ -4249,11 +4082,6 @@ packages:
|
|||
dependencies:
|
||||
whatwg-url: 5.0.0
|
||||
|
||||
/node-gyp-build@4.8.1:
|
||||
resolution: {integrity: sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw==}
|
||||
hasBin: true
|
||||
dev: true
|
||||
|
||||
/node-int64@0.4.0:
|
||||
resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==}
|
||||
dev: true
|
||||
|
@ -4400,34 +4228,6 @@ packages:
|
|||
resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==}
|
||||
engines: {node: '>= 0.8'}
|
||||
|
||||
/passport-jwt@4.0.1:
|
||||
resolution: {integrity: sha512-UCKMDYhNuGOBE9/9Ycuoyh7vP6jpeTp/+sfMJl7nLff/t6dps+iaeE0hhNkKN8/HZHcJ7lCdOyDxHdDoxoSvdQ==}
|
||||
dependencies:
|
||||
jsonwebtoken: 9.0.2
|
||||
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-strategy@1.0.0:
|
||||
resolution: {integrity: sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA==}
|
||||
engines: {node: '>= 0.4.0'}
|
||||
dev: false
|
||||
|
||||
/passport@0.7.0:
|
||||
resolution: {integrity: sha512-cPLl+qZpSc+ireUvt+IzqbED1cHHkDoVYMo30jbJIdOOjQ1MQYZBPiNvmi8UM6lJuOpTPXJGZQk0DtC4y61MYQ==}
|
||||
engines: {node: '>= 0.4.0'}
|
||||
dependencies:
|
||||
passport-strategy: 1.0.0
|
||||
pause: 0.0.1
|
||||
utils-merge: 1.0.1
|
||||
dev: false
|
||||
|
||||
/path-exists@4.0.0:
|
||||
resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
|
||||
engines: {node: '>=8'}
|
||||
|
@ -4464,10 +4264,6 @@ packages:
|
|||
engines: {node: '>=8'}
|
||||
dev: true
|
||||
|
||||
/pause@0.0.1:
|
||||
resolution: {integrity: sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==}
|
||||
dev: false
|
||||
|
||||
/pg-cloudflare@1.1.1:
|
||||
resolution: {integrity: sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==}
|
||||
requiresBuild: true
|
||||
|
@ -4837,6 +4633,7 @@ packages:
|
|||
hasBin: true
|
||||
dependencies:
|
||||
lru-cache: 6.0.0
|
||||
dev: true
|
||||
|
||||
/send@0.18.0:
|
||||
resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==}
|
||||
|
@ -5562,10 +5359,6 @@ packages:
|
|||
convert-source-map: 2.0.0
|
||||
dev: true
|
||||
|
||||
/validator@13.11.0:
|
||||
resolution: {integrity: sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ==}
|
||||
engines: {node: '>= 0.10'}
|
||||
|
||||
/vary@1.1.2:
|
||||
resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
|
||||
engines: {node: '>= 0.8'}
|
||||
|
@ -5747,6 +5540,7 @@ packages:
|
|||
|
||||
/yallist@4.0.0:
|
||||
resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
|
||||
dev: true
|
||||
|
||||
/yargs-parser@20.2.9:
|
||||
resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==}
|
||||
|
|
|
@ -1,13 +1,8 @@
|
|||
import { MiddlewareConsumer, Module, RequestMethod } from '@nestjs/common';
|
||||
import { Module } from '@nestjs/common';
|
||||
import { AppController } from './app.controller';
|
||||
import { AppService } from './app.service';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
import { DatabaseModule } from './modules/database-module/database.module';
|
||||
import { CspMiddleware } from './middleware/csp-middleware/csp.middleware';
|
||||
import { SecurityHeadersMiddleware } from './middleware/security-middleware/security.middleware';
|
||||
import { HttpsRedirectMiddleware } from './middleware/https-middlware/https-redirect.middleware';
|
||||
import { AuthModule } from './modules/auth-module/auth.module';
|
||||
import { AccessTokenGuard } from './modules/auth-module/common/guards';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
|
@ -15,16 +10,8 @@ import { AccessTokenGuard } from './modules/auth-module/common/guards';
|
|||
isGlobal: true,
|
||||
}),
|
||||
DatabaseModule,
|
||||
AuthModule,
|
||||
],
|
||||
controllers: [AppController],
|
||||
providers: [AppService, { provide: 'APP_GUARD', useClass: AccessTokenGuard }],
|
||||
providers: [AppService],
|
||||
})
|
||||
export class AppModule {
|
||||
configure(consumer: MiddlewareConsumer) {
|
||||
consumer
|
||||
// TODO: Redirect via Reverse Proxy all HTTP requests to HTTPS
|
||||
.apply(CspMiddleware, SecurityHeadersMiddleware, HttpsRedirectMiddleware)
|
||||
.forRoutes({ path: '*', method: RequestMethod.ALL });
|
||||
}
|
||||
}
|
||||
export class AppModule {}
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
import {
|
||||
Entity,
|
||||
PrimaryGeneratedColumn,
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
UpdateDateColumn,
|
||||
} from 'typeorm';
|
||||
|
||||
@Entity()
|
||||
export class UserCredentials {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id: number;
|
||||
|
||||
@Column({ unique: true })
|
||||
email: string;
|
||||
|
||||
@Column()
|
||||
hash: string;
|
||||
|
||||
@Column({ nullable: true })
|
||||
hashedRt?: string;
|
||||
|
||||
@CreateDateColumn()
|
||||
createdAt: Date;
|
||||
|
||||
@UpdateDateColumn()
|
||||
updatedAt: Date;
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
import { NestFactory } from '@nestjs/core';
|
||||
import { AppModule } from './app.module';
|
||||
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
|
||||
import { ValidationPipe } from '@nestjs/common';
|
||||
|
||||
async function setupSwagger(app) {
|
||||
const config = new DocumentBuilder().build();
|
||||
|
@ -9,19 +8,9 @@ async function setupSwagger(app) {
|
|||
SwaggerModule.setup('api', app, document);
|
||||
}
|
||||
|
||||
async function setupPrefix(app) {
|
||||
app.setGlobalPrefix('api');
|
||||
}
|
||||
|
||||
async function setupClassValidator(app) {
|
||||
app.useGlobalPipes(new ValidationPipe());
|
||||
}
|
||||
|
||||
async function bootstrap() {
|
||||
const app = await NestFactory.create(AppModule);
|
||||
await setupSwagger(app);
|
||||
await setupPrefix(app);
|
||||
await setupClassValidator(app);
|
||||
await app.listen(3000);
|
||||
}
|
||||
bootstrap();
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
import { Injectable, NestMiddleware } from '@nestjs/common';
|
||||
import { Request, Response, NextFunction } from 'express';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
|
||||
@Injectable()
|
||||
export class CspMiddleware implements NestMiddleware {
|
||||
constructor(private readonly configService: ConfigService) {}
|
||||
|
||||
public use(req: Request, res: Response, next: NextFunction): void {
|
||||
const cspDirectives = this.configService.get<string>('CSP_DIRECTIVES');
|
||||
if (cspDirectives) {
|
||||
res.setHeader('Content-Security-Policy', cspDirectives);
|
||||
}
|
||||
next();
|
||||
}
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
import { Injectable, NestMiddleware } from '@nestjs/common';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { NextFunction, Request, Response } from 'express';
|
||||
|
||||
@Injectable()
|
||||
export class HttpsRedirectMiddleware implements NestMiddleware {
|
||||
constructor(private readonly configService: ConfigService) {}
|
||||
|
||||
public use(req: Request, res: Response, next: NextFunction) {
|
||||
if (this.configService.get<string>('NODE_ENV') === 'production') {
|
||||
if (req.protocol === 'http') {
|
||||
const httpsUrl = `https://${req.headers.host}${req.url}`;
|
||||
res.redirect(httpsUrl);
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
import { Injectable, NestMiddleware } from '@nestjs/common';
|
||||
import { Request, Response, NextFunction } from 'express';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
|
||||
@Injectable()
|
||||
export class SecurityHeadersMiddleware implements NestMiddleware {
|
||||
constructor(private readonly configService: ConfigService) {}
|
||||
|
||||
public use(req: Request, res: Response, next: NextFunction): void {
|
||||
if (this.configService.get<string>('NODE_ENV') === 'production') {
|
||||
res.setHeader(
|
||||
'Strict-Transport-Security',
|
||||
'max-age=63072000; includeSubDomains; preload'
|
||||
);
|
||||
}
|
||||
res.setHeader('X-Content-Type-Options', 'nosniff');
|
||||
res.setHeader('X-Frame-Options', 'SAMEORIGIN');
|
||||
next();
|
||||
}
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
import { Module } from '@nestjs/common';
|
||||
import { AuthService } from './services/auth.service';
|
||||
import { AuthController } from './controller/auth.controller';
|
||||
import { JwtModule } from '@nestjs/jwt';
|
||||
import { AccessTokenStrategy, RefreshTokenStrategy } from './strategies';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { UserCredentials } from 'src/entities/user-credentials.entity';
|
||||
import { UserRepository } from './repositories/user.repository';
|
||||
import { EncryptionService } from './services/encryption.service';
|
||||
import { TokenManagementService } from './services/token-management.service';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
JwtModule.register({}),
|
||||
TypeOrmModule.forFeature([UserCredentials]),
|
||||
],
|
||||
providers: [
|
||||
AuthService,
|
||||
TokenManagementService,
|
||||
EncryptionService,
|
||||
UserRepository,
|
||||
AccessTokenStrategy,
|
||||
RefreshTokenStrategy,
|
||||
],
|
||||
controllers: [AuthController],
|
||||
})
|
||||
export class AuthModule {}
|
|
@ -1,10 +0,0 @@
|
|||
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
|
||||
import { JwtPayload } from 'src/modules/auth-module/models/types';
|
||||
|
||||
export const GetCurrentUserId = createParamDecorator(
|
||||
(_: undefined, context: ExecutionContext): number => {
|
||||
const request = context.switchToHttp().getRequest();
|
||||
const user = request.user as JwtPayload;
|
||||
return user.sub;
|
||||
}
|
||||
);
|
|
@ -1,13 +0,0 @@
|
|||
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
|
||||
import { JwtPayloadWithRefreshToken } from 'src/modules/auth-module/models/types';
|
||||
|
||||
export const GetCurrentUser = createParamDecorator(
|
||||
(
|
||||
data: keyof JwtPayloadWithRefreshToken | undefined,
|
||||
context: ExecutionContext
|
||||
) => {
|
||||
const request = context.switchToHttp().getRequest();
|
||||
if (!data) return request.user;
|
||||
return request.user[data];
|
||||
}
|
||||
);
|
|
@ -1,3 +0,0 @@
|
|||
export * from './get-user-id.decorator';
|
||||
export * from './get-user.decorator';
|
||||
export * from './public.decorator';
|
|
@ -1,3 +0,0 @@
|
|||
import { SetMetadata } from '@nestjs/common';
|
||||
|
||||
export const Public = () => SetMetadata('isPublic', true);
|
|
@ -1,28 +0,0 @@
|
|||
import { Injectable, ExecutionContext } from '@nestjs/common';
|
||||
import { AuthGuard } from '@nestjs/passport';
|
||||
import { Reflector } from '@nestjs/core';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
@Injectable()
|
||||
export class AccessTokenGuard extends AuthGuard('jwt-access-token') {
|
||||
constructor(private readonly reflector: Reflector) {
|
||||
super();
|
||||
}
|
||||
|
||||
public canActivate(
|
||||
context: ExecutionContext
|
||||
): boolean | Promise<boolean> | Observable<boolean> {
|
||||
// Check if the current route is marked as public
|
||||
const isPublic = this.reflector.getAllAndOverride<boolean>('isPublic', [
|
||||
context.getHandler(),
|
||||
context.getClass(),
|
||||
]);
|
||||
|
||||
// Allow access if the route is public, otherwise defer to the standard JWT authentication mechanism
|
||||
if (isPublic) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.canActivate(context);
|
||||
}
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
export * from './access-token.guard';
|
||||
export * from './refresh-token.guard';
|
|
@ -1,7 +0,0 @@
|
|||
import { AuthGuard } from '@nestjs/passport';
|
||||
|
||||
export class RefreshTokenGuard extends AuthGuard('jwt-refresh-token') {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
import {
|
||||
Controller,
|
||||
Post,
|
||||
Body,
|
||||
HttpCode,
|
||||
HttpStatus,
|
||||
UseGuards,
|
||||
} from '@nestjs/common';
|
||||
import { AuthService } from '../services/auth.service';
|
||||
import { UserCredentialsDto } from '../models/dto';
|
||||
import { Tokens } from '../models/types';
|
||||
import { RefreshTokenGuard } from '../common/guards';
|
||||
import { GetCurrentUser, GetCurrentUserId, Public } from '../common/decorators';
|
||||
|
||||
@Controller('auth')
|
||||
export class AuthController {
|
||||
constructor(private readonly authService: AuthService) {}
|
||||
|
||||
@Public()
|
||||
@Post('signup')
|
||||
@HttpCode(HttpStatus.CREATED)
|
||||
public async signup(
|
||||
@Body() userCredentials: UserCredentialsDto
|
||||
): Promise<Tokens> {
|
||||
return this.authService.signup(userCredentials);
|
||||
}
|
||||
|
||||
@Public()
|
||||
@Post('signin')
|
||||
@HttpCode(HttpStatus.OK)
|
||||
public async signin(
|
||||
@Body() userCredentials: UserCredentialsDto
|
||||
): Promise<Tokens> {
|
||||
return this.authService.signin(userCredentials);
|
||||
}
|
||||
|
||||
@Post('logout')
|
||||
@HttpCode(HttpStatus.OK)
|
||||
public async logout(@GetCurrentUserId() userId: number): Promise<boolean> {
|
||||
return this.authService.logout(userId);
|
||||
}
|
||||
|
||||
@Public()
|
||||
@UseGuards(RefreshTokenGuard)
|
||||
@Post('refresh')
|
||||
@HttpCode(HttpStatus.OK)
|
||||
public async refresh(
|
||||
@GetCurrentUserId() userId: number,
|
||||
@GetCurrentUser('refresh_token') refresh_token: string
|
||||
): Promise<Tokens> {
|
||||
return this.authService.refresh(userId, refresh_token);
|
||||
}
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
export * from './user-credentials.dto';
|
|
@ -1,12 +0,0 @@
|
|||
import { IsEmail, IsNotEmpty, IsString, MinLength } from 'class-validator';
|
||||
|
||||
export class UserCredentialsDto {
|
||||
@IsNotEmpty()
|
||||
@IsEmail()
|
||||
public email: string;
|
||||
|
||||
@IsNotEmpty()
|
||||
@IsString()
|
||||
@MinLength(8)
|
||||
public password: string;
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
export * from './tokens.type';
|
||||
export * from './jwt-payload.type';
|
||||
export * from './jwt-payload-with-refresh-token.type';
|
|
@ -1,3 +0,0 @@
|
|||
import { JwtPayload } from './jwt-payload.type';
|
||||
|
||||
export type JwtPayloadWithRefreshToken = JwtPayload & { refresh_token: string };
|
|
@ -1,4 +0,0 @@
|
|||
export type JwtPayload = {
|
||||
email: string;
|
||||
sub: number;
|
||||
};
|
|
@ -1,4 +0,0 @@
|
|||
export type Tokens = {
|
||||
access_token: string;
|
||||
refresh_token: string;
|
||||
};
|
|
@ -1,40 +0,0 @@
|
|||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { UserCredentials } from 'src/entities/user-credentials.entity';
|
||||
import { Repository } from 'typeorm';
|
||||
|
||||
@Injectable()
|
||||
export class UserRepository {
|
||||
constructor(
|
||||
@InjectRepository(UserCredentials)
|
||||
private readonly repository: Repository<UserCredentials>
|
||||
) {}
|
||||
|
||||
public async createUser(
|
||||
email: string,
|
||||
hash: string
|
||||
): Promise<UserCredentials> {
|
||||
const user = this.repository.create({ email, hash });
|
||||
return this.repository.save(user);
|
||||
}
|
||||
|
||||
public async findUserByEmail(
|
||||
email: string
|
||||
): Promise<UserCredentials | undefined> {
|
||||
return this.repository.findOne({ where: { email } });
|
||||
}
|
||||
|
||||
public async findUserById(
|
||||
userId: number
|
||||
): Promise<UserCredentials | undefined> {
|
||||
return this.repository.findOne({ where: { id: userId } });
|
||||
}
|
||||
|
||||
public async updateUserTokenHash(
|
||||
userId: number,
|
||||
hashedRt: string | null
|
||||
): Promise<number> {
|
||||
const result = await this.repository.update(userId, { hashedRt });
|
||||
return result.affected ?? 0;
|
||||
}
|
||||
}
|
|
@ -1,85 +0,0 @@
|
|||
import { ForbiddenException, Injectable } from '@nestjs/common';
|
||||
import { UserCredentialsDto } from '../models/dto';
|
||||
import { Tokens } from '../models/types';
|
||||
import { EncryptionService } from './encryption.service';
|
||||
import { UserRepository } from '../repositories/user.repository';
|
||||
import { TokenManagementService } from './token-management.service';
|
||||
|
||||
@Injectable()
|
||||
export class AuthService {
|
||||
constructor(
|
||||
private readonly userRepository: UserRepository,
|
||||
private readonly tokenManagementService: TokenManagementService,
|
||||
private readonly encryptionService: EncryptionService
|
||||
) {}
|
||||
|
||||
public async signup(userCredentials: UserCredentialsDto): Promise<Tokens> {
|
||||
const passwordHashed = await this.encryptionService.hashData(
|
||||
userCredentials.password
|
||||
);
|
||||
const user = await this.userRepository.createUser(
|
||||
userCredentials.email,
|
||||
passwordHashed
|
||||
);
|
||||
return this.generateAndPersistTokens(user.id, user.email);
|
||||
}
|
||||
|
||||
public async signin(userCredentials: UserCredentialsDto): Promise<Tokens> {
|
||||
const user = await this.userRepository.findUserByEmail(
|
||||
userCredentials.email
|
||||
);
|
||||
if (!user) {
|
||||
throw new ForbiddenException('Access Denied');
|
||||
}
|
||||
|
||||
const passwordMatch = await this.encryptionService.compareHash(
|
||||
userCredentials.password,
|
||||
user.hash
|
||||
);
|
||||
if (!passwordMatch) {
|
||||
throw new ForbiddenException('Access Denied');
|
||||
}
|
||||
|
||||
return this.generateAndPersistTokens(user.id, user.email);
|
||||
}
|
||||
|
||||
public async refresh(userId: number, refreshToken: string): Promise<Tokens> {
|
||||
const user = await this.userRepository.findUserById(userId);
|
||||
if (!user || !user.hashedRt) {
|
||||
throw new ForbiddenException('Access Denied');
|
||||
}
|
||||
|
||||
const refreshTokenMatch = await this.encryptionService.compareHash(
|
||||
refreshToken,
|
||||
user.hashedRt
|
||||
);
|
||||
if (!refreshTokenMatch) {
|
||||
throw new ForbiddenException('Access Denied');
|
||||
}
|
||||
|
||||
return this.generateAndPersistTokens(user.id, user.email);
|
||||
}
|
||||
|
||||
public async logout(userId: number): Promise<boolean> {
|
||||
const affected = await this.userRepository.updateUserTokenHash(
|
||||
userId,
|
||||
null
|
||||
);
|
||||
return affected > 0;
|
||||
}
|
||||
|
||||
private async generateAndPersistTokens(
|
||||
userId: number,
|
||||
email: string
|
||||
): Promise<Tokens> {
|
||||
const tokens = await this.tokenManagementService.generateTokens(
|
||||
userId,
|
||||
email
|
||||
);
|
||||
const hashedRefreshToken = await this.encryptionService.hashData(
|
||||
tokens.refresh_token
|
||||
);
|
||||
await this.userRepository.updateUserTokenHash(userId, hashedRefreshToken);
|
||||
return tokens;
|
||||
}
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
import { Injectable } from '@nestjs/common';
|
||||
import * as argon2 from 'argon2';
|
||||
import { Options } from 'argon2';
|
||||
|
||||
@Injectable()
|
||||
export class EncryptionService {
|
||||
private hashOptions: Options = {
|
||||
type: argon2.argon2id,
|
||||
memoryCost: 2 ** 16,
|
||||
timeCost: 3,
|
||||
parallelism: 1,
|
||||
};
|
||||
|
||||
public async hashData(data: string): Promise<string> {
|
||||
return await argon2.hash(data, this.hashOptions);
|
||||
}
|
||||
|
||||
public async compareHash(data: string, encrypted: string): Promise<boolean> {
|
||||
return await argon2.verify(encrypted, data);
|
||||
}
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
import { Injectable } from '@nestjs/common';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { Tokens } from '../models/types';
|
||||
import { JwtService } from '@nestjs/jwt';
|
||||
|
||||
@Injectable()
|
||||
export class TokenManagementService {
|
||||
private readonly ACCESS_TOKEN_EXPIRY: string;
|
||||
private readonly REFRESH_TOKEN_EXPIRY: string;
|
||||
private readonly JWT_SECRET_AT: string;
|
||||
private readonly JWT_SECRET_RT: string;
|
||||
|
||||
constructor(
|
||||
private readonly jwt: JwtService,
|
||||
private readonly configService: ConfigService
|
||||
) {
|
||||
this.ACCESS_TOKEN_EXPIRY = this.configService.get<string>(
|
||||
'ACCESS_TOKEN_EXPIRY'
|
||||
);
|
||||
this.REFRESH_TOKEN_EXPIRY = this.configService.get<string>(
|
||||
'REFRESH_TOKEN_EXPIRY'
|
||||
);
|
||||
this.JWT_SECRET_AT = this.configService.get<string>('JWT_SECRET_AT');
|
||||
this.JWT_SECRET_RT = this.configService.get<string>('JWT_SECRET_RT');
|
||||
}
|
||||
|
||||
public async generateTokens(userId: number, email: string): Promise<Tokens> {
|
||||
const access_token: string = await this.createAccessToken(userId, email);
|
||||
const refresh_token: string = await this.createRefreshToken(userId, email);
|
||||
return { access_token, refresh_token };
|
||||
}
|
||||
|
||||
private async createAccessToken(
|
||||
userId: number,
|
||||
email: string
|
||||
): Promise<string> {
|
||||
return this.jwt.signAsync(
|
||||
{ sub: userId, email },
|
||||
{
|
||||
expiresIn: this.ACCESS_TOKEN_EXPIRY,
|
||||
secret: this.JWT_SECRET_AT,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private async createRefreshToken(
|
||||
userId: number,
|
||||
email: string
|
||||
): Promise<string> {
|
||||
return this.jwt.signAsync(
|
||||
{ sub: userId, email },
|
||||
{
|
||||
expiresIn: this.REFRESH_TOKEN_EXPIRY,
|
||||
secret: this.JWT_SECRET_RT,
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
import { Injectable } from '@nestjs/common';
|
||||
import { PassportStrategy } from '@nestjs/passport';
|
||||
import { Strategy, ExtractJwt } from 'passport-jwt';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { JwtPayload } from '../models/types';
|
||||
|
||||
@Injectable()
|
||||
export class AccessTokenStrategy extends PassportStrategy(
|
||||
Strategy,
|
||||
'jwt-access-token'
|
||||
) {
|
||||
constructor(private readonly configService: ConfigService) {
|
||||
super(AccessTokenStrategy.getJwtConfig(configService));
|
||||
}
|
||||
|
||||
private static getJwtConfig(configService: ConfigService): any {
|
||||
return {
|
||||
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
|
||||
secretOrKey: configService.get<string>('JWT_SECRET_AT'),
|
||||
};
|
||||
}
|
||||
|
||||
public async validate(payload: JwtPayload): Promise<JwtPayload> {
|
||||
return payload;
|
||||
}
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
export * from './access-token.strategie';
|
||||
export * from './refresh-token.strategie';
|
|
@ -1,39 +0,0 @@
|
|||
import { Injectable, ForbiddenException } from '@nestjs/common';
|
||||
import { PassportStrategy } from '@nestjs/passport';
|
||||
import { Strategy, ExtractJwt } from 'passport-jwt';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { Request } from 'express';
|
||||
|
||||
@Injectable()
|
||||
export class RefreshTokenStrategy extends PassportStrategy(
|
||||
Strategy,
|
||||
'jwt-refresh-token'
|
||||
) {
|
||||
constructor(private readonly configService: ConfigService) {
|
||||
super(RefreshTokenStrategy.createJwtStrategyOptions(configService));
|
||||
}
|
||||
|
||||
private static createJwtStrategyOptions(configService: ConfigService): any {
|
||||
return {
|
||||
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
|
||||
secretOrKey: configService.get<string>('JWT_SECRET_RT'),
|
||||
passReqToCallback: true,
|
||||
};
|
||||
}
|
||||
|
||||
public async validate(req: Request, payload: any) {
|
||||
const refresh_token: string = req
|
||||
?.get('authorization')
|
||||
?.replace('Bearer', '')
|
||||
.trim();
|
||||
|
||||
if (!refresh_token) {
|
||||
throw new ForbiddenException('Refresh token malformed');
|
||||
}
|
||||
|
||||
return {
|
||||
...payload,
|
||||
refresh_token,
|
||||
};
|
||||
}
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
import { ConfigService } from '@nestjs/config';
|
||||
import { TypeOrmModuleOptions } from '@nestjs/typeorm';
|
||||
import { UserCredentials } from '../../entities/user-credentials.entity';
|
||||
import { ConfigService } from "@nestjs/config";
|
||||
import { TypeOrmModuleOptions } from "@nestjs/typeorm";
|
||||
|
||||
export const databaseConfigFactory = (
|
||||
configService: ConfigService
|
||||
|
@ -13,5 +12,5 @@ export const databaseConfigFactory = (
|
|||
database: configService.get('DB_NAME'),
|
||||
synchronize: true,
|
||||
logging: true,
|
||||
entities: [UserCredentials],
|
||||
entities: [],
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue