refactor: changed otp to use cache
This commit is contained in:
@@ -20,7 +20,9 @@
|
|||||||
"test:e2e": "jest --config ./test/jest-e2e.json"
|
"test:e2e": "jest --config ./test/jest-e2e.json"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@keyv/redis": "^5.1.6",
|
||||||
"@nestjs/axios": "^4.0.1",
|
"@nestjs/axios": "^4.0.1",
|
||||||
|
"@nestjs/cache-manager": "^3.1.3",
|
||||||
"@nestjs/common": "^11.1.28",
|
"@nestjs/common": "^11.1.28",
|
||||||
"@nestjs/config": "^4.0.4",
|
"@nestjs/config": "^4.0.4",
|
||||||
"@nestjs/core": "^11.1.28",
|
"@nestjs/core": "^11.1.28",
|
||||||
@@ -31,9 +33,11 @@
|
|||||||
"@nestjs/typeorm": "^11.0.3",
|
"@nestjs/typeorm": "^11.0.3",
|
||||||
"axios": "^1.18.1",
|
"axios": "^1.18.1",
|
||||||
"bcrypt": "^6.0.0",
|
"bcrypt": "^6.0.0",
|
||||||
|
"cache-manager": "^7.2.9",
|
||||||
"class-transformer": "^0.5.1",
|
"class-transformer": "^0.5.1",
|
||||||
"class-validator": "^0.15.1",
|
"class-validator": "^0.15.1",
|
||||||
"joi": "^18.2.3",
|
"joi": "^18.2.3",
|
||||||
|
"keyv": "^5.6.0",
|
||||||
"ms": "^2.1.3",
|
"ms": "^2.1.3",
|
||||||
"passport": "^0.7.0",
|
"passport": "^0.7.0",
|
||||||
"passport-jwt": "^4.0.1",
|
"passport-jwt": "^4.0.1",
|
||||||
|
|||||||
Generated
+108
@@ -8,9 +8,15 @@ importers:
|
|||||||
|
|
||||||
.:
|
.:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
'@keyv/redis':
|
||||||
|
specifier: ^5.1.6
|
||||||
|
version: 5.1.6(keyv@5.6.0)
|
||||||
'@nestjs/axios':
|
'@nestjs/axios':
|
||||||
specifier: ^4.0.1
|
specifier: ^4.0.1
|
||||||
version: 4.0.1(@nestjs/common@11.1.28(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(axios@1.18.1)(rxjs@7.8.2)
|
version: 4.0.1(@nestjs/common@11.1.28(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(axios@1.18.1)(rxjs@7.8.2)
|
||||||
|
'@nestjs/cache-manager':
|
||||||
|
specifier: ^3.1.3
|
||||||
|
version: 3.1.3(@nestjs/common@11.1.28(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.28)(cache-manager@7.2.9)(keyv@5.6.0)(rxjs@7.8.2)
|
||||||
'@nestjs/common':
|
'@nestjs/common':
|
||||||
specifier: ^11.1.28
|
specifier: ^11.1.28
|
||||||
version: 11.1.28(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2)
|
version: 11.1.28(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2)
|
||||||
@@ -41,6 +47,9 @@ importers:
|
|||||||
bcrypt:
|
bcrypt:
|
||||||
specifier: ^6.0.0
|
specifier: ^6.0.0
|
||||||
version: 6.0.0
|
version: 6.0.0
|
||||||
|
cache-manager:
|
||||||
|
specifier: ^7.2.9
|
||||||
|
version: 7.2.9
|
||||||
class-transformer:
|
class-transformer:
|
||||||
specifier: ^0.5.1
|
specifier: ^0.5.1
|
||||||
version: 0.5.1
|
version: 0.5.1
|
||||||
@@ -50,6 +59,9 @@ importers:
|
|||||||
joi:
|
joi:
|
||||||
specifier: ^18.2.3
|
specifier: ^18.2.3
|
||||||
version: 18.2.3
|
version: 18.2.3
|
||||||
|
keyv:
|
||||||
|
specifier: ^5.6.0
|
||||||
|
version: 5.6.0
|
||||||
ms:
|
ms:
|
||||||
specifier: ^2.1.3
|
specifier: ^2.1.3
|
||||||
version: 2.1.3
|
version: 2.1.3
|
||||||
@@ -352,6 +364,9 @@ packages:
|
|||||||
'@borewit/text-codec@0.2.2':
|
'@borewit/text-codec@0.2.2':
|
||||||
resolution: {integrity: sha512-DDaRehssg1aNrH4+2hnj1B7vnUGEjU6OIlyRdkMd0aUdIUvKXrJfXsy8LVtXAy7DRvYVluWbMspsRhz2lcW0mQ==}
|
resolution: {integrity: sha512-DDaRehssg1aNrH4+2hnj1B7vnUGEjU6OIlyRdkMd0aUdIUvKXrJfXsy8LVtXAy7DRvYVluWbMspsRhz2lcW0mQ==}
|
||||||
|
|
||||||
|
'@cacheable/utils@2.5.0':
|
||||||
|
resolution: {integrity: sha512-buipgOVDkkPXNR5+xBpDw7Zk2n1EvU7qBJCNUcL7rhQ//kfpOXPAvQ511Os0vpLYJ1pZnvudNytkQt2hst3wqA==}
|
||||||
|
|
||||||
'@colors/colors@1.5.0':
|
'@colors/colors@1.5.0':
|
||||||
resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==}
|
resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==}
|
||||||
engines: {node: '>=0.1.90'}
|
engines: {node: '>=0.1.90'}
|
||||||
@@ -706,6 +721,15 @@ packages:
|
|||||||
'@jridgewell/trace-mapping@0.3.9':
|
'@jridgewell/trace-mapping@0.3.9':
|
||||||
resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==}
|
resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==}
|
||||||
|
|
||||||
|
'@keyv/redis@5.1.6':
|
||||||
|
resolution: {integrity: sha512-eKvW6pspvVaU5dxigaIDZr635/Uw6urTXL3gNbY9WTR8d3QigZQT+r8gxYSEOsw4+1cCBsC4s7T2ptR0WC9LfQ==}
|
||||||
|
engines: {node: '>= 18'}
|
||||||
|
peerDependencies:
|
||||||
|
keyv: ^5.6.0
|
||||||
|
|
||||||
|
'@keyv/serialize@1.1.1':
|
||||||
|
resolution: {integrity: sha512-dXn3FZhPv0US+7dtJsIi2R+c7qWYiReoEh5zUntWCf4oSpMNib8FDhSoed6m3QyZdx5hK7iLFkYk3rNxwt8vTA==}
|
||||||
|
|
||||||
'@lukeed/csprng@1.1.0':
|
'@lukeed/csprng@1.1.0':
|
||||||
resolution: {integrity: sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==}
|
resolution: {integrity: sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
@@ -726,6 +750,15 @@ packages:
|
|||||||
axios: ^1.3.1
|
axios: ^1.3.1
|
||||||
rxjs: ^7.0.0
|
rxjs: ^7.0.0
|
||||||
|
|
||||||
|
'@nestjs/cache-manager@3.1.3':
|
||||||
|
resolution: {integrity: sha512-HMtiOfHz75NZX7mJn1VnZGLSachVI04TnUc5wvEogIaKwk5BDQHgtP5htxreizjv7oxKalJbuTyxtiF6bE+bgQ==}
|
||||||
|
peerDependencies:
|
||||||
|
'@nestjs/common': ^9.0.0 || ^10.0.0 || ^11.0.0
|
||||||
|
'@nestjs/core': ^9.0.0 || ^10.0.0 || ^11.0.0
|
||||||
|
cache-manager: '>=6'
|
||||||
|
keyv: '>=5'
|
||||||
|
rxjs: ^7.8.1
|
||||||
|
|
||||||
'@nestjs/cli@11.0.24':
|
'@nestjs/cli@11.0.24':
|
||||||
resolution: {integrity: sha512-aIHxQLSYtXShifA3zwWIeznEsZnNa3Iz2QRykFj+sl9IcbERBHr5nH87FRgywM+He3NxoF5WazHfR8FsmVeWxw==}
|
resolution: {integrity: sha512-aIHxQLSYtXShifA3zwWIeznEsZnNa3Iz2QRykFj+sl9IcbERBHr5nH87FRgywM+He3NxoF5WazHfR8FsmVeWxw==}
|
||||||
engines: {node: '>= 20.11'}
|
engines: {node: '>= 20.11'}
|
||||||
@@ -869,6 +902,18 @@ packages:
|
|||||||
resolution: {integrity: sha512-SEeaJLb3qBNF/OaXnaR1NmmBbFYk1zC0ZH/52fATcRPLFg/p791YrcyFFy44Bo9sLaGuSuLp5Q6axbb/O+v/RA==}
|
resolution: {integrity: sha512-SEeaJLb3qBNF/OaXnaR1NmmBbFYk1zC0ZH/52fATcRPLFg/p791YrcyFFy44Bo9sLaGuSuLp5Q6axbb/O+v/RA==}
|
||||||
engines: {node: ^14.18.0 || >=16.0.0}
|
engines: {node: ^14.18.0 || >=16.0.0}
|
||||||
|
|
||||||
|
'@redis/client@5.12.1':
|
||||||
|
resolution: {integrity: sha512-7aPGWeqA3uFm43o19umzdl16CEjK/JQGtSXVPevplTaOU3VJA/rseBC1QvYUz9lLDIMBimc4SW/zrW4S89BaCA==}
|
||||||
|
engines: {node: '>= 18.19.0'}
|
||||||
|
peerDependencies:
|
||||||
|
'@node-rs/xxhash': ^1.1.0
|
||||||
|
'@opentelemetry/api': '>=1 <2'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@node-rs/xxhash':
|
||||||
|
optional: true
|
||||||
|
'@opentelemetry/api':
|
||||||
|
optional: true
|
||||||
|
|
||||||
'@scarf/scarf@1.4.0':
|
'@scarf/scarf@1.4.0':
|
||||||
resolution: {integrity: sha512-xxeapPiUXdZAE3che6f3xogoJPeZgig6omHEy1rIY5WVsB3H2BHNnZH+gHG6x91SCWyQCzWGsuL2Hh3ClO5/qQ==}
|
resolution: {integrity: sha512-xxeapPiUXdZAE3che6f3xogoJPeZgig6omHEy1rIY5WVsB3H2BHNnZH+gHG6x91SCWyQCzWGsuL2Hh3ClO5/qQ==}
|
||||||
|
|
||||||
@@ -1467,6 +1512,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==}
|
resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==}
|
||||||
engines: {node: '>= 0.8'}
|
engines: {node: '>= 0.8'}
|
||||||
|
|
||||||
|
cache-manager@7.2.9:
|
||||||
|
resolution: {integrity: sha512-d4vceEyYe95gPxEyQchlEOH9vJlkNRW8G6gzFzzMTxJK9PahYMhC9chrEqgZN0HulROjgw3IzmWVNk7Q7ytiGw==}
|
||||||
|
|
||||||
call-bind-apply-helpers@1.0.2:
|
call-bind-apply-helpers@1.0.2:
|
||||||
resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
|
resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
@@ -1550,6 +1598,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==}
|
resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==}
|
||||||
engines: {node: '>=0.8'}
|
engines: {node: '>=0.8'}
|
||||||
|
|
||||||
|
cluster-key-slot@1.1.2:
|
||||||
|
resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==}
|
||||||
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
co@4.6.0:
|
co@4.6.0:
|
||||||
resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==}
|
resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==}
|
||||||
engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'}
|
engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'}
|
||||||
@@ -2064,10 +2116,17 @@ packages:
|
|||||||
resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==}
|
resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
|
hashery@1.5.1:
|
||||||
|
resolution: {integrity: sha512-iZyKG96/JwPz1N55vj2Ie2vXbhu440zfUfJvSwEqEbeLluk7NnapfGqa7LH0mOsnDxTF85Mx8/dyR6HfqcbmbQ==}
|
||||||
|
engines: {node: '>=20'}
|
||||||
|
|
||||||
hasown@2.0.4:
|
hasown@2.0.4:
|
||||||
resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==}
|
resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
|
hookified@1.15.1:
|
||||||
|
resolution: {integrity: sha512-MvG/clsADq1GPM2KGo2nyfaWVyn9naPiXrqIe4jYjXNZQt238kWyOGrsyc/DmRAQ+Re6yeo6yX/yoNCG5KAEVg==}
|
||||||
|
|
||||||
html-escaper@2.0.2:
|
html-escaper@2.0.2:
|
||||||
resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==}
|
resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==}
|
||||||
|
|
||||||
@@ -2381,6 +2440,9 @@ packages:
|
|||||||
keyv@4.5.4:
|
keyv@4.5.4:
|
||||||
resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
|
resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
|
||||||
|
|
||||||
|
keyv@5.6.0:
|
||||||
|
resolution: {integrity: sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw==}
|
||||||
|
|
||||||
leven@3.1.0:
|
leven@3.1.0:
|
||||||
resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==}
|
resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
@@ -3690,6 +3752,11 @@ snapshots:
|
|||||||
|
|
||||||
'@borewit/text-codec@0.2.2': {}
|
'@borewit/text-codec@0.2.2': {}
|
||||||
|
|
||||||
|
'@cacheable/utils@2.5.0':
|
||||||
|
dependencies:
|
||||||
|
hashery: 1.5.1
|
||||||
|
keyv: 5.6.0
|
||||||
|
|
||||||
'@colors/colors@1.5.0':
|
'@colors/colors@1.5.0':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -4157,6 +4224,18 @@ snapshots:
|
|||||||
'@jridgewell/resolve-uri': 3.1.2
|
'@jridgewell/resolve-uri': 3.1.2
|
||||||
'@jridgewell/sourcemap-codec': 1.5.5
|
'@jridgewell/sourcemap-codec': 1.5.5
|
||||||
|
|
||||||
|
'@keyv/redis@5.1.6(keyv@5.6.0)':
|
||||||
|
dependencies:
|
||||||
|
'@redis/client': 5.12.1
|
||||||
|
cluster-key-slot: 1.1.2
|
||||||
|
hookified: 1.15.1
|
||||||
|
keyv: 5.6.0
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- '@node-rs/xxhash'
|
||||||
|
- '@opentelemetry/api'
|
||||||
|
|
||||||
|
'@keyv/serialize@1.1.1': {}
|
||||||
|
|
||||||
'@lukeed/csprng@1.1.0': {}
|
'@lukeed/csprng@1.1.0': {}
|
||||||
|
|
||||||
'@microsoft/tsdoc@0.16.0': {}
|
'@microsoft/tsdoc@0.16.0': {}
|
||||||
@@ -4174,6 +4253,14 @@ snapshots:
|
|||||||
axios: 1.18.1
|
axios: 1.18.1
|
||||||
rxjs: 7.8.2
|
rxjs: 7.8.2
|
||||||
|
|
||||||
|
'@nestjs/cache-manager@3.1.3(@nestjs/common@11.1.28(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.28)(cache-manager@7.2.9)(keyv@5.6.0)(rxjs@7.8.2)':
|
||||||
|
dependencies:
|
||||||
|
'@nestjs/common': 11.1.28(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2)
|
||||||
|
'@nestjs/core': 11.1.28(@nestjs/common@11.1.28(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.28)(reflect-metadata@0.2.2)(rxjs@7.8.2)
|
||||||
|
cache-manager: 7.2.9
|
||||||
|
keyv: 5.6.0
|
||||||
|
rxjs: 7.8.2
|
||||||
|
|
||||||
'@nestjs/cli@11.0.24(@types/node@22.20.1)(prettier@3.9.5)':
|
'@nestjs/cli@11.0.24(@types/node@22.20.1)(prettier@3.9.5)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@angular-devkit/core': 19.2.27(chokidar@4.0.3)
|
'@angular-devkit/core': 19.2.27(chokidar@4.0.3)
|
||||||
@@ -4332,6 +4419,10 @@ snapshots:
|
|||||||
|
|
||||||
'@pkgr/core@0.3.6': {}
|
'@pkgr/core@0.3.6': {}
|
||||||
|
|
||||||
|
'@redis/client@5.12.1':
|
||||||
|
dependencies:
|
||||||
|
cluster-key-slot: 1.1.2
|
||||||
|
|
||||||
'@scarf/scarf@1.4.0': {}
|
'@scarf/scarf@1.4.0': {}
|
||||||
|
|
||||||
'@sinclair/typebox@0.34.52': {}
|
'@sinclair/typebox@0.34.52': {}
|
||||||
@@ -5000,6 +5091,11 @@ snapshots:
|
|||||||
|
|
||||||
bytes@3.1.2: {}
|
bytes@3.1.2: {}
|
||||||
|
|
||||||
|
cache-manager@7.2.9:
|
||||||
|
dependencies:
|
||||||
|
'@cacheable/utils': 2.5.0
|
||||||
|
keyv: 5.6.0
|
||||||
|
|
||||||
call-bind-apply-helpers@1.0.2:
|
call-bind-apply-helpers@1.0.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
es-errors: 1.3.0
|
es-errors: 1.3.0
|
||||||
@@ -5073,6 +5169,8 @@ snapshots:
|
|||||||
|
|
||||||
clone@1.0.4: {}
|
clone@1.0.4: {}
|
||||||
|
|
||||||
|
cluster-key-slot@1.1.2: {}
|
||||||
|
|
||||||
co@4.6.0: {}
|
co@4.6.0: {}
|
||||||
|
|
||||||
collect-v8-coverage@1.0.3: {}
|
collect-v8-coverage@1.0.3: {}
|
||||||
@@ -5592,10 +5690,16 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
has-symbols: 1.1.0
|
has-symbols: 1.1.0
|
||||||
|
|
||||||
|
hashery@1.5.1:
|
||||||
|
dependencies:
|
||||||
|
hookified: 1.15.1
|
||||||
|
|
||||||
hasown@2.0.4:
|
hasown@2.0.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
function-bind: 1.1.2
|
function-bind: 1.1.2
|
||||||
|
|
||||||
|
hookified@1.15.1: {}
|
||||||
|
|
||||||
html-escaper@2.0.2: {}
|
html-escaper@2.0.2: {}
|
||||||
|
|
||||||
http-errors@2.0.1:
|
http-errors@2.0.1:
|
||||||
@@ -6100,6 +6204,10 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
json-buffer: 3.0.1
|
json-buffer: 3.0.1
|
||||||
|
|
||||||
|
keyv@5.6.0:
|
||||||
|
dependencies:
|
||||||
|
'@keyv/serialize': 1.1.1
|
||||||
|
|
||||||
leven@3.1.0: {}
|
leven@3.1.0: {}
|
||||||
|
|
||||||
levn@0.4.1:
|
levn@0.4.1:
|
||||||
|
|||||||
+16
-3
@@ -10,21 +10,34 @@ import { OrganModule } from './modules/organ/organ.module';
|
|||||||
import { ComplaintModule } from './modules/complaint/complaint.module';
|
import { ComplaintModule } from './modules/complaint/complaint.module';
|
||||||
import { AttachmentModule } from './modules/attachment/attachment.module';
|
import { AttachmentModule } from './modules/attachment/attachment.module';
|
||||||
import { ReplyModule } from './modules/reply/reply.module';
|
import { ReplyModule } from './modules/reply/reply.module';
|
||||||
|
import { CacheModule } from '@nestjs/cache-manager';
|
||||||
|
import KeyvRedis from '@keyv/redis';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
ConfigModule.forRoot({
|
ConfigModule.forRoot({
|
||||||
isGlobal: true,
|
isGlobal: true,
|
||||||
validationSchema
|
validationSchema,
|
||||||
|
}),
|
||||||
|
CacheModule.registerAsync({
|
||||||
|
isGlobal: true,
|
||||||
|
inject: [ConfigService],
|
||||||
|
useFactory: (config: ConfigService) => ({
|
||||||
|
stores: [new KeyvRedis(config.getOrThrow('REDIS_URL'))],
|
||||||
|
}),
|
||||||
}),
|
}),
|
||||||
TypeOrmModule.forRootAsync(databaseConfig()),
|
TypeOrmModule.forRootAsync(databaseConfig()),
|
||||||
HttpModule.register({global: true, timeout: 10000, headers: {"Content-Type": "application/json"}}),
|
HttpModule.register({
|
||||||
|
global: true,
|
||||||
|
timeout: 10000,
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
}),
|
||||||
UsersModule,
|
UsersModule,
|
||||||
AuthModule,
|
AuthModule,
|
||||||
OrganModule,
|
OrganModule,
|
||||||
ComplaintModule,
|
ComplaintModule,
|
||||||
AttachmentModule,
|
AttachmentModule,
|
||||||
ReplyModule
|
ReplyModule,
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class AppModule {}
|
export class AppModule {}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { OtpRepository } from './repositories/otp.repository';
|
|||||||
import { UsersModule } from 'src/modules/users/users.module';
|
import { UsersModule } from 'src/modules/users/users.module';
|
||||||
import { PassportModule } from '@nestjs/passport';
|
import { PassportModule } from '@nestjs/passport';
|
||||||
import { JwtStrategy } from './strategies/jwt.strategy';
|
import { JwtStrategy } from './strategies/jwt.strategy';
|
||||||
|
import { OtpService } from './otp.service';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
@@ -19,7 +20,7 @@ import { JwtStrategy } from './strategies/jwt.strategy';
|
|||||||
UsersModule,
|
UsersModule,
|
||||||
],
|
],
|
||||||
controllers: [AuthController],
|
controllers: [AuthController],
|
||||||
providers: [AuthService, OtpRepository, JwtStrategy],
|
providers: [AuthService, OtpService, OtpRepository, JwtStrategy],
|
||||||
exports: [JwtModule, PassportModule]
|
exports: [JwtModule, PassportModule],
|
||||||
})
|
})
|
||||||
export class AuthModule {}
|
export class AuthModule {}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import { UsersService } from 'src/modules/users/users.service';
|
|||||||
import * as bcrypt from 'bcrypt';
|
import * as bcrypt from 'bcrypt';
|
||||||
import { JwtService } from '@nestjs/jwt';
|
import { JwtService } from '@nestjs/jwt';
|
||||||
import ms from 'ms';
|
import ms from 'ms';
|
||||||
|
import { OtpService } from './otp.service';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AuthService {
|
export class AuthService {
|
||||||
@@ -19,13 +20,13 @@ export class AuthService {
|
|||||||
@Inject(SMS_CONFIG) private smsConfig: ISmsConfigs,
|
@Inject(SMS_CONFIG) private smsConfig: ISmsConfigs,
|
||||||
private readonly smsService: SmsService,
|
private readonly smsService: SmsService,
|
||||||
private readonly configService: ConfigService,
|
private readonly configService: ConfigService,
|
||||||
private readonly OtpRepository: OtpRepository,
|
|
||||||
private readonly userService: UsersService,
|
private readonly userService: UsersService,
|
||||||
private readonly jwtService: JwtService,
|
private readonly jwtService: JwtService,
|
||||||
|
private readonly otpService: OtpService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async sendOTP(phone: string) {
|
async sendOTP(phone: string) {
|
||||||
const otp = this.generateOtp();
|
const otp = await this.otpService.generate(phone);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await this.smsService.sendSms({
|
await this.smsService.sendSms({
|
||||||
@@ -39,21 +40,6 @@ export class AuthService {
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
await this.OtpRepository.update(
|
|
||||||
{ phoneNumber: phone, status: OtpStatus.PENDING },
|
|
||||||
{ status: OtpStatus.EXPIRED },
|
|
||||||
);
|
|
||||||
|
|
||||||
await this.OtpRepository.save(
|
|
||||||
this.OtpRepository.create({
|
|
||||||
phoneNumber: phone,
|
|
||||||
code: otp,
|
|
||||||
expirationDate: new Date(Date.now() + 2 * 60 * 1000),
|
|
||||||
status: OtpStatus.PENDING,
|
|
||||||
numberOfTries: 0,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
return { otp };
|
return { otp };
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (this.configService.get('NODE_ENV') !== 'production') {
|
if (this.configService.get('NODE_ENV') !== 'production') {
|
||||||
@@ -65,48 +51,7 @@ export class AuthService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async verifyOTP(dto: VerifyOtpDto) {
|
async verifyOTP(dto: VerifyOtpDto) {
|
||||||
const otp = await this.OtpRepository.findOne({
|
await this.otpService.verify(dto.phoneNumber, dto.code);
|
||||||
where: { phoneNumber: dto.phoneNumber, status: OtpStatus.PENDING },
|
|
||||||
order: {
|
|
||||||
createdAt: 'DESC',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!otp) {
|
|
||||||
throw new BadRequestException(OTPMessages.OTP_NOT_FOUND);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (otp.expirationDate < new Date()) {
|
|
||||||
otp.status = OtpStatus.EXPIRED;
|
|
||||||
|
|
||||||
await this.OtpRepository.save(otp);
|
|
||||||
|
|
||||||
throw new BadRequestException(OTPMessages.OTP_EXPIRED);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (otp.code !== dto.code) {
|
|
||||||
otp.numberOfTries++;
|
|
||||||
|
|
||||||
if (otp.numberOfTries >= 3) {
|
|
||||||
otp.status = OtpStatus.EXPIRED;
|
|
||||||
|
|
||||||
await this.OtpRepository.save(otp);
|
|
||||||
|
|
||||||
throw new BadRequestException(OTPMessages.OTP_TOO_MANY_TRIES);
|
|
||||||
}
|
|
||||||
|
|
||||||
await this.OtpRepository.save(otp);
|
|
||||||
|
|
||||||
throw new BadRequestException(OTPMessages.OTP_INVALID);
|
|
||||||
}
|
|
||||||
|
|
||||||
otp.status = OtpStatus.VERIFIED;
|
|
||||||
|
|
||||||
await this.OtpRepository.save(otp);
|
|
||||||
}
|
|
||||||
|
|
||||||
private generateOtp(): string {
|
|
||||||
return Math.floor(100000 + Math.random() * 900000).toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async checkLoginCredentials(credential: LoginCredentialDto): Promise<void> {
|
async checkLoginCredentials(credential: LoginCredentialDto): Promise<void> {
|
||||||
|
|||||||
@@ -0,0 +1,74 @@
|
|||||||
|
import { CACHE_MANAGER } from '@nestjs/cache-manager';
|
||||||
|
import { BadRequestException, Inject, Injectable } from '@nestjs/common';
|
||||||
|
import { ConfigService } from '@nestjs/config';
|
||||||
|
import type { Cache } from 'cache-manager';
|
||||||
|
import { OTPMessages } from 'src/common/enums/messages.enum';
|
||||||
|
|
||||||
|
interface OtpCache {
|
||||||
|
code: string;
|
||||||
|
tries: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class OtpService {
|
||||||
|
private readonly TTL: number;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
@Inject(CACHE_MANAGER)
|
||||||
|
private readonly cache: Cache,
|
||||||
|
private readonly configService: ConfigService,
|
||||||
|
) {
|
||||||
|
this.TTL = this.configService.getOrThrow<number>('CACHE_TTL');
|
||||||
|
}
|
||||||
|
|
||||||
|
private getKey(phoneNumber: string) {
|
||||||
|
return `otp:${phoneNumber}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
async generate(phoneNumber: string): Promise<string> {
|
||||||
|
const code = Math.floor(100000 + Math.random() * 900000).toString();
|
||||||
|
|
||||||
|
const value: OtpCache = {
|
||||||
|
code,
|
||||||
|
tries: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
await this.cache.set(this.getKey(phoneNumber), value, this.TTL);
|
||||||
|
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
async verify(phoneNumber: string, code: string): Promise<boolean> {
|
||||||
|
const otp = await this.cache.get<OtpCache>(this.getKey(phoneNumber));
|
||||||
|
|
||||||
|
if (!otp) {
|
||||||
|
throw new BadRequestException(OTPMessages.OTP_EXPIRED);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (otp.tries >= 5) {
|
||||||
|
await this.cache.del(this.getKey(phoneNumber));
|
||||||
|
|
||||||
|
throw new BadRequestException(OTPMessages.OTP_TOO_MANY_TRIES);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (otp.code !== code) {
|
||||||
|
otp.tries++;
|
||||||
|
|
||||||
|
await this.cache.set(this.getKey(phoneNumber), otp, this.TTL);
|
||||||
|
|
||||||
|
throw new BadRequestException(OTPMessages.OTP_INVALID);
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.cache.del(this.getKey(phoneNumber));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
async delete(phoneNumber: string): Promise<void> {
|
||||||
|
await this.cache.del(this.getKey(phoneNumber));
|
||||||
|
}
|
||||||
|
|
||||||
|
async exists(phoneNumber: string): Promise<boolean> {
|
||||||
|
return !!(await this.cache.get(this.getKey(phoneNumber)));
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user