@proteinjs/user-server 1.0.33 → 1.0.35
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/dist/generated/index.d.ts +1 -0
- package/dist/generated/index.d.ts.map +1 -1
- package/dist/generated/index.js +8 -1
- package/dist/generated/index.js.map +1 -1
- package/dist/src/routes/executePasswordReset.d.ts +14 -0
- package/dist/src/routes/executePasswordReset.d.ts.map +1 -0
- package/dist/src/routes/executePasswordReset.js +101 -0
- package/dist/src/routes/executePasswordReset.js.map +1 -0
- package/dist/src/routes/initiatePasswordReset.d.ts +17 -0
- package/dist/src/routes/initiatePasswordReset.d.ts.map +1 -0
- package/dist/src/routes/initiatePasswordReset.js +134 -0
- package/dist/src/routes/initiatePasswordReset.js.map +1 -0
- package/dist/src/routes/validateResetPasswordToken.d.ts +3 -0
- package/dist/src/routes/validateResetPasswordToken.d.ts.map +1 -0
- package/dist/src/routes/validateResetPasswordToken.js +83 -0
- package/dist/src/routes/validateResetPasswordToken.js.map +1 -0
- package/generated/index.ts +8 -1
- package/package.json +8 -7
- package/src/routes/executePasswordReset.ts +56 -0
- package/src/routes/initiatePasswordReset.ts +90 -0
- package/src/routes/validateResetPasswordToken.ts +39 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,14 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [1.0.34](https://github.com/proteinjs/user/compare/@proteinjs/user-server@1.0.33...@proteinjs/user-server@1.0.34) (2024-07-12)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @proteinjs/user-server
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
6
14
|
## [1.0.27](https://github.com/proteinjs/user/compare/@proteinjs/user-server@1.0.26...@proteinjs/user-server@1.0.27) (2024-06-27)
|
|
7
15
|
|
|
8
16
|
**Note:** Version bump only for package @proteinjs/user-server
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../generated/index.ts"],"names":[],"mappings":"AAAA,oCAAoC;AAEpC,OAAO,eAAe,CAAC;AACvB,OAAO,uBAAuB,CAAC;AAC/B,OAAO,uBAAuB,CAAC;AAC/B,OAAO,iBAAiB,CAAC;AACzB,OAAO,iBAAiB,CAAC;AACzB,OAAO,WAAW,CAAC;AACnB,OAAO,iBAAiB,CAAC;AACzB,OAAO,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../generated/index.ts"],"names":[],"mappings":"AAAA,oCAAoC;AAEpC,OAAO,eAAe,CAAC;AACvB,OAAO,yBAAyB,CAAC;AACjC,OAAO,uBAAuB,CAAC;AAC/B,OAAO,uBAAuB,CAAC;AAC/B,OAAO,iBAAiB,CAAC;AACzB,OAAO,iBAAiB,CAAC;AACzB,OAAO,WAAW,CAAC;AACnB,OAAO,iBAAiB,CAAC;AACzB,OAAO,QAAQ,CAAC;AAqChB,cAAc,UAAU,CAAC"}
|
package/dist/generated/index.js
CHANGED
|
@@ -16,6 +16,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
16
16
|
};
|
|
17
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
18
|
require("@proteinjs/db");
|
|
19
|
+
require("@proteinjs/email-server");
|
|
19
20
|
require("@proteinjs/reflection");
|
|
20
21
|
require("@proteinjs/server-api");
|
|
21
22
|
require("@proteinjs/user");
|
|
@@ -24,19 +25,25 @@ require("crypto-js");
|
|
|
24
25
|
require("express-session");
|
|
25
26
|
require("moment");
|
|
26
27
|
/** Generate Source Graph */
|
|
27
|
-
var sourceGraph = "{\"options\":{\"directed\":true,\"multigraph\":false,\"compound\":false},\"nodes\":[{\"v\":\"@proteinjs/user-server/DbSessionStore\",\"value\":{\"packageName\":\"@proteinjs/user-server\",\"name\":\"DbSessionStore\",\"filePath\":\"/Users/veronica/Repositories/n3xa-meta-repo/packages/proteinjs/packages/user/packages/server/src/authentication/DbSessionStore.ts\",\"qualifiedName\":\"@proteinjs/user-server/DbSessionStore\",\"isAbstract\":false,\"isStatic\":false,\"visibility\":\"public\",\"properties\":[{\"name\":\"TWELVE_HOURS\",\"type\":null,\"isOptional\":false,\"isAbstract\":false,\"isStatic\":true,\"visibility\":\"private\"},{\"name\":\"get\",\"type\":null,\"isOptional\":false,\"isAbstract\":false,\"isStatic\":false,\"visibility\":\"public\"},{\"name\":\"set\",\"type\":null,\"isOptional\":false,\"isAbstract\":false,\"isStatic\":false,\"visibility\":\"public\"},{\"name\":\"touch\",\"type\":null,\"isOptional\":false,\"isAbstract\":false,\"isStatic\":false,\"visibility\":\"public\"},{\"name\":\"destroy\",\"type\":null,\"isOptional\":false,\"isAbstract\":false,\"isStatic\":false,\"visibility\":\"public\"}],\"methods\":[{\"name\":\"insertOrUpdate\",\"returnType\":{\"packageName\":\"\",\"name\":\"Promise<void>\",\"filePath\":null,\"qualifiedName\":\"/Promise<void>\",\"typeParameters\":null,\"directParents\":null},\"isAsync\":true,\"isOptional\":false,\"isAbstract\":false,\"isStatic\":false,\"visibility\":\"private\",\"parameters\":[{\"name\":\"sessionId\",\"type\":{\"packageName\":\"\",\"name\":\"string\",\"filePath\":null,\"qualifiedName\":\"/string\",\"typeParameters\":null,\"directParents\":null}},{\"name\":\"session\",\"type\":{\"packageName\":\"\",\"name\":\"Express.SessionData\",\"filePath\":null,\"qualifiedName\":\"/Express.SessionData\",\"typeParameters\":null,\"directParents\":null}},{\"name\":\"cb\",\"type\":{\"packageName\":\"\",\"name\":\"(error?: any) => void\",\"filePath\":null,\"qualifiedName\":\"/(error?: any) => void\",\"typeParameters\":null,\"directParents\":null}}]},{\"name\":\"sweep\",\"returnType\":{\"packageName\":\"\",\"name\":\"Promise<void>\",\"filePath\":null,\"qualifiedName\":\"/Promise<void>\",\"typeParameters\":null,\"directParents\":null},\"isAsync\":true,\"isOptional\":false,\"isAbstract\":false,\"isStatic\":false,\"visibility\":\"private\",\"parameters\":[]}],\"typeParameters\":[],\"directParentInterfaces\":[],\"directParentClasses\":[{\"packageName\":\"express-session\",\"name\":\"Store\",\"filePath\":null,\"qualifiedName\":\"express-session/Store\",\"isAbstract\":false,\"isStatic\":false,\"visibility\":\"public\",\"properties\":[],\"methods\":[],\"typeParameters\":[],\"directParentInterfaces\":[],\"directParentClasses\":[]}],\"sourceType\":2}},{\"v\":\"express-session/Store\"},{\"v\":\"@proteinjs/user-server/userCache\",\"value\":{\"packageName\":\"@proteinjs/user-server\",\"name\":\"userCache\",\"filePath\":\"/Users/veronica/Repositories/n3xa-meta-repo/packages/proteinjs/packages/user/packages/server/src/authorization/userCache.ts\",\"qualifiedName\":\"@proteinjs/user-server/userCache\",\"type\":{\"packageName\":\"\",\"name\":\"SessionDataCache<User>\",\"filePath\":null,\"qualifiedName\":\"/SessionDataCache<User>\",\"typeParameters\":[],\"directParents\":[{\"packageName\":\"@proteinjs/server-api\",\"name\":\"SessionDataCache\",\"filePath\":null,\"qualifiedName\":\"@proteinjs/server-api/SessionDataCache\",\"typeParameters\":[\"@proteinjs/user/User\"],\"directParents\":null}]},\"isExported\":true,\"isConst\":true,\"sourceType\":0}},{\"v\":\"@proteinjs/server-api/SessionDataCache\"},{\"v\":\"@proteinjs/user-server/createUser\",\"value\":{\"packageName\":\"@proteinjs/user-server\",\"name\":\"createUser\",\"filePath\":\"/Users/veronica/Repositories/n3xa-meta-repo/packages/proteinjs/packages/user/packages/server/src/routes/createUser.ts\",\"qualifiedName\":\"@proteinjs/user-server/createUser\",\"type\":{\"packageName\":\"@proteinjs/server-api\",\"name\":\"Route\",\"filePath\":null,\"qualifiedName\":\"@proteinjs/server-api/Route\",\"typeParameters\":[],\"directParents\":[{\"packageName\":\"@proteinjs/server-api\",\"name\":\"Route\",\"filePath\":null,\"qualifiedName\":\"@proteinjs/server-api/Route\",\"typeParameters\":[],\"directParents\":null}]},\"isExported\":true,\"isConst\":true,\"sourceType\":0}},{\"v\":\"@proteinjs/server-api/Route\"},{\"v\":\"@proteinjs/user-server/login\",\"value\":{\"packageName\":\"@proteinjs/user-server\",\"name\":\"login\",\"filePath\":\"/Users/veronica/Repositories/n3xa-meta-repo/packages/proteinjs/packages/user/packages/server/src/routes/login.ts\",\"qualifiedName\":\"@proteinjs/user-server/login\",\"type\":{\"packageName\":\"@proteinjs/server-api\",\"name\":\"Route\",\"filePath\":null,\"qualifiedName\":\"@proteinjs/server-api/Route\",\"typeParameters\":[],\"directParents\":[{\"packageName\":\"@proteinjs/server-api\",\"name\":\"Route\",\"filePath\":null,\"qualifiedName\":\"@proteinjs/server-api/Route\",\"typeParameters\":[],\"directParents\":null}]},\"isExported\":true,\"isConst\":true,\"sourceType\":0}},{\"v\":\"@proteinjs/user-server/logout\",\"value\":{\"packageName\":\"@proteinjs/user-server\",\"name\":\"logout\",\"filePath\":\"/Users/veronica/Repositories/n3xa-meta-repo/packages/proteinjs/packages/user/packages/server/src/routes/logout.ts\",\"qualifiedName\":\"@proteinjs/user-server/logout\",\"type\":{\"packageName\":\"@proteinjs/server-api\",\"name\":\"Route\",\"filePath\":null,\"qualifiedName\":\"@proteinjs/server-api/Route\",\"typeParameters\":[],\"directParents\":[{\"packageName\":\"@proteinjs/server-api\",\"name\":\"Route\",\"filePath\":null,\"qualifiedName\":\"@proteinjs/server-api/Route\",\"typeParameters\":[],\"directParents\":null}]},\"isExported\":true,\"isConst\":true,\"sourceType\":0}}],\"edges\":[{\"v\":\"@proteinjs/user-server/DbSessionStore\",\"w\":\"express-session/Store\",\"value\":\"extends class\"},{\"v\":\"@proteinjs/user-server/userCache\",\"w\":\"@proteinjs/server-api/SessionDataCache\",\"value\":\"has type\"},{\"v\":\"@proteinjs/user-server/createUser\",\"w\":\"@proteinjs/server-api/Route\",\"value\":\"has type\"},{\"v\":\"@proteinjs/user-server/login\",\"w\":\"@proteinjs/server-api/Route\",\"value\":\"has type\"},{\"v\":\"@proteinjs/user-server/logout\",\"w\":\"@proteinjs/server-api/Route\",\"value\":\"has type\"}]}";
|
|
28
|
+
var sourceGraph = "{\"options\":{\"directed\":true,\"multigraph\":false,\"compound\":false},\"nodes\":[{\"v\":\"@proteinjs/user-server/DbSessionStore\",\"value\":{\"packageName\":\"@proteinjs/user-server\",\"name\":\"DbSessionStore\",\"filePath\":\"/Users/veronica/Repositories/n3xa-meta-repo/packages/proteinjs/packages/user/packages/server/src/authentication/DbSessionStore.ts\",\"qualifiedName\":\"@proteinjs/user-server/DbSessionStore\",\"isAbstract\":false,\"isStatic\":false,\"visibility\":\"public\",\"properties\":[{\"name\":\"TWELVE_HOURS\",\"type\":null,\"isOptional\":false,\"isAbstract\":false,\"isStatic\":true,\"visibility\":\"private\"},{\"name\":\"get\",\"type\":null,\"isOptional\":false,\"isAbstract\":false,\"isStatic\":false,\"visibility\":\"public\"},{\"name\":\"set\",\"type\":null,\"isOptional\":false,\"isAbstract\":false,\"isStatic\":false,\"visibility\":\"public\"},{\"name\":\"touch\",\"type\":null,\"isOptional\":false,\"isAbstract\":false,\"isStatic\":false,\"visibility\":\"public\"},{\"name\":\"destroy\",\"type\":null,\"isOptional\":false,\"isAbstract\":false,\"isStatic\":false,\"visibility\":\"public\"}],\"methods\":[{\"name\":\"insertOrUpdate\",\"returnType\":{\"packageName\":\"\",\"name\":\"Promise<void>\",\"filePath\":null,\"qualifiedName\":\"/Promise<void>\",\"typeParameters\":null,\"directParents\":null},\"isAsync\":true,\"isOptional\":false,\"isAbstract\":false,\"isStatic\":false,\"visibility\":\"private\",\"parameters\":[{\"name\":\"sessionId\",\"type\":{\"packageName\":\"\",\"name\":\"string\",\"filePath\":null,\"qualifiedName\":\"/string\",\"typeParameters\":null,\"directParents\":null}},{\"name\":\"session\",\"type\":{\"packageName\":\"\",\"name\":\"Express.SessionData\",\"filePath\":null,\"qualifiedName\":\"/Express.SessionData\",\"typeParameters\":null,\"directParents\":null}},{\"name\":\"cb\",\"type\":{\"packageName\":\"\",\"name\":\"(error?: any) => void\",\"filePath\":null,\"qualifiedName\":\"/(error?: any) => void\",\"typeParameters\":null,\"directParents\":null}}]},{\"name\":\"sweep\",\"returnType\":{\"packageName\":\"\",\"name\":\"Promise<void>\",\"filePath\":null,\"qualifiedName\":\"/Promise<void>\",\"typeParameters\":null,\"directParents\":null},\"isAsync\":true,\"isOptional\":false,\"isAbstract\":false,\"isStatic\":false,\"visibility\":\"private\",\"parameters\":[]}],\"typeParameters\":[],\"directParentInterfaces\":[],\"directParentClasses\":[{\"packageName\":\"express-session\",\"name\":\"Store\",\"filePath\":null,\"qualifiedName\":\"express-session/Store\",\"isAbstract\":false,\"isStatic\":false,\"visibility\":\"public\",\"properties\":[],\"methods\":[],\"typeParameters\":[],\"directParentInterfaces\":[],\"directParentClasses\":[]}],\"sourceType\":2}},{\"v\":\"express-session/Store\"},{\"v\":\"@proteinjs/user-server/userCache\",\"value\":{\"packageName\":\"@proteinjs/user-server\",\"name\":\"userCache\",\"filePath\":\"/Users/veronica/Repositories/n3xa-meta-repo/packages/proteinjs/packages/user/packages/server/src/authorization/userCache.ts\",\"qualifiedName\":\"@proteinjs/user-server/userCache\",\"type\":{\"packageName\":\"\",\"name\":\"SessionDataCache<User>\",\"filePath\":null,\"qualifiedName\":\"/SessionDataCache<User>\",\"typeParameters\":[],\"directParents\":[{\"packageName\":\"@proteinjs/server-api\",\"name\":\"SessionDataCache\",\"filePath\":null,\"qualifiedName\":\"@proteinjs/server-api/SessionDataCache\",\"typeParameters\":[\"@proteinjs/user/User\"],\"directParents\":null}]},\"isExported\":true,\"isConst\":true,\"sourceType\":0}},{\"v\":\"@proteinjs/server-api/SessionDataCache\"},{\"v\":\"@proteinjs/user-server/createUser\",\"value\":{\"packageName\":\"@proteinjs/user-server\",\"name\":\"createUser\",\"filePath\":\"/Users/veronica/Repositories/n3xa-meta-repo/packages/proteinjs/packages/user/packages/server/src/routes/createUser.ts\",\"qualifiedName\":\"@proteinjs/user-server/createUser\",\"type\":{\"packageName\":\"@proteinjs/server-api\",\"name\":\"Route\",\"filePath\":null,\"qualifiedName\":\"@proteinjs/server-api/Route\",\"typeParameters\":[],\"directParents\":[{\"packageName\":\"@proteinjs/server-api\",\"name\":\"Route\",\"filePath\":null,\"qualifiedName\":\"@proteinjs/server-api/Route\",\"typeParameters\":[],\"directParents\":null}]},\"isExported\":true,\"isConst\":true,\"sourceType\":0}},{\"v\":\"@proteinjs/server-api/Route\"},{\"v\":\"@proteinjs/user-server/executePasswordReset\",\"value\":{\"packageName\":\"@proteinjs/user-server\",\"name\":\"executePasswordReset\",\"filePath\":\"/Users/veronica/Repositories/n3xa-meta-repo/packages/proteinjs/packages/user/packages/server/src/routes/executePasswordReset.ts\",\"qualifiedName\":\"@proteinjs/user-server/executePasswordReset\",\"type\":{\"packageName\":\"@proteinjs/server-api\",\"name\":\"Route\",\"filePath\":null,\"qualifiedName\":\"@proteinjs/server-api/Route\",\"typeParameters\":[],\"directParents\":[{\"packageName\":\"@proteinjs/server-api\",\"name\":\"Route\",\"filePath\":null,\"qualifiedName\":\"@proteinjs/server-api/Route\",\"typeParameters\":[],\"directParents\":null}]},\"isExported\":true,\"isConst\":true,\"sourceType\":0}},{\"v\":\"@proteinjs/user-server/initiatePasswordReset\",\"value\":{\"packageName\":\"@proteinjs/user-server\",\"name\":\"initiatePasswordReset\",\"filePath\":\"/Users/veronica/Repositories/n3xa-meta-repo/packages/proteinjs/packages/user/packages/server/src/routes/initiatePasswordReset.ts\",\"qualifiedName\":\"@proteinjs/user-server/initiatePasswordReset\",\"type\":{\"packageName\":\"@proteinjs/server-api\",\"name\":\"Route\",\"filePath\":null,\"qualifiedName\":\"@proteinjs/server-api/Route\",\"typeParameters\":[],\"directParents\":[{\"packageName\":\"@proteinjs/server-api\",\"name\":\"Route\",\"filePath\":null,\"qualifiedName\":\"@proteinjs/server-api/Route\",\"typeParameters\":[],\"directParents\":null}]},\"isExported\":true,\"isConst\":true,\"sourceType\":0}},{\"v\":\"@proteinjs/user-server/login\",\"value\":{\"packageName\":\"@proteinjs/user-server\",\"name\":\"login\",\"filePath\":\"/Users/veronica/Repositories/n3xa-meta-repo/packages/proteinjs/packages/user/packages/server/src/routes/login.ts\",\"qualifiedName\":\"@proteinjs/user-server/login\",\"type\":{\"packageName\":\"@proteinjs/server-api\",\"name\":\"Route\",\"filePath\":null,\"qualifiedName\":\"@proteinjs/server-api/Route\",\"typeParameters\":[],\"directParents\":[{\"packageName\":\"@proteinjs/server-api\",\"name\":\"Route\",\"filePath\":null,\"qualifiedName\":\"@proteinjs/server-api/Route\",\"typeParameters\":[],\"directParents\":null}]},\"isExported\":true,\"isConst\":true,\"sourceType\":0}},{\"v\":\"@proteinjs/user-server/logout\",\"value\":{\"packageName\":\"@proteinjs/user-server\",\"name\":\"logout\",\"filePath\":\"/Users/veronica/Repositories/n3xa-meta-repo/packages/proteinjs/packages/user/packages/server/src/routes/logout.ts\",\"qualifiedName\":\"@proteinjs/user-server/logout\",\"type\":{\"packageName\":\"@proteinjs/server-api\",\"name\":\"Route\",\"filePath\":null,\"qualifiedName\":\"@proteinjs/server-api/Route\",\"typeParameters\":[],\"directParents\":[{\"packageName\":\"@proteinjs/server-api\",\"name\":\"Route\",\"filePath\":null,\"qualifiedName\":\"@proteinjs/server-api/Route\",\"typeParameters\":[],\"directParents\":null}]},\"isExported\":true,\"isConst\":true,\"sourceType\":0}},{\"v\":\"@proteinjs/user-server/validateResetPasswordToken\",\"value\":{\"packageName\":\"@proteinjs/user-server\",\"name\":\"validateResetPasswordToken\",\"filePath\":\"/Users/veronica/Repositories/n3xa-meta-repo/packages/proteinjs/packages/user/packages/server/src/routes/validateResetPasswordToken.ts\",\"qualifiedName\":\"@proteinjs/user-server/validateResetPasswordToken\",\"type\":{\"packageName\":\"@proteinjs/server-api\",\"name\":\"Route\",\"filePath\":null,\"qualifiedName\":\"@proteinjs/server-api/Route\",\"typeParameters\":[],\"directParents\":[{\"packageName\":\"@proteinjs/server-api\",\"name\":\"Route\",\"filePath\":null,\"qualifiedName\":\"@proteinjs/server-api/Route\",\"typeParameters\":[],\"directParents\":null}]},\"isExported\":true,\"isConst\":true,\"sourceType\":0}}],\"edges\":[{\"v\":\"@proteinjs/user-server/DbSessionStore\",\"w\":\"express-session/Store\",\"value\":\"extends class\"},{\"v\":\"@proteinjs/user-server/userCache\",\"w\":\"@proteinjs/server-api/SessionDataCache\",\"value\":\"has type\"},{\"v\":\"@proteinjs/user-server/createUser\",\"w\":\"@proteinjs/server-api/Route\",\"value\":\"has type\"},{\"v\":\"@proteinjs/user-server/executePasswordReset\",\"w\":\"@proteinjs/server-api/Route\",\"value\":\"has type\"},{\"v\":\"@proteinjs/user-server/initiatePasswordReset\",\"w\":\"@proteinjs/server-api/Route\",\"value\":\"has type\"},{\"v\":\"@proteinjs/user-server/login\",\"w\":\"@proteinjs/server-api/Route\",\"value\":\"has type\"},{\"v\":\"@proteinjs/user-server/logout\",\"w\":\"@proteinjs/server-api/Route\",\"value\":\"has type\"},{\"v\":\"@proteinjs/user-server/validateResetPasswordToken\",\"w\":\"@proteinjs/server-api/Route\",\"value\":\"has type\"}]}";
|
|
28
29
|
/** Generate Source Links */
|
|
29
30
|
var DbSessionStore_1 = require("../src/authentication/DbSessionStore");
|
|
30
31
|
var userCache_1 = require("../src/authorization/userCache");
|
|
31
32
|
var createUser_1 = require("../src/routes/createUser");
|
|
33
|
+
var executePasswordReset_1 = require("../src/routes/executePasswordReset");
|
|
34
|
+
var initiatePasswordReset_1 = require("../src/routes/initiatePasswordReset");
|
|
32
35
|
var login_1 = require("../src/routes/login");
|
|
33
36
|
var logout_1 = require("../src/routes/logout");
|
|
37
|
+
var validateResetPasswordToken_1 = require("../src/routes/validateResetPasswordToken");
|
|
34
38
|
var sourceLinks = {
|
|
35
39
|
'@proteinjs/user-server/DbSessionStore': DbSessionStore_1.DbSessionStore,
|
|
36
40
|
'@proteinjs/user-server/userCache': userCache_1.userCache,
|
|
37
41
|
'@proteinjs/user-server/createUser': createUser_1.createUser,
|
|
42
|
+
'@proteinjs/user-server/executePasswordReset': executePasswordReset_1.executePasswordReset,
|
|
43
|
+
'@proteinjs/user-server/initiatePasswordReset': initiatePasswordReset_1.initiatePasswordReset,
|
|
38
44
|
'@proteinjs/user-server/login': login_1.login,
|
|
39
45
|
'@proteinjs/user-server/logout': logout_1.logout,
|
|
46
|
+
'@proteinjs/user-server/validateResetPasswordToken': validateResetPasswordToken_1.validateResetPasswordToken,
|
|
40
47
|
};
|
|
41
48
|
/** Load Source Graph and Links */
|
|
42
49
|
var reflection_1 = require("@proteinjs/reflection");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../generated/index.ts"],"names":[],"mappings":";AAAA,oCAAoC;;;;;;;;;;;;;;;;AAEpC,yBAAuB;AACvB,iCAA+B;AAC/B,iCAA+B;AAC/B,2BAAyB;AACzB,2BAAyB;AACzB,qBAAmB;AACnB,2BAAyB;AACzB,kBAAgB;AAGhB,4BAA4B;AAE5B,IAAM,WAAW,GAAG,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../generated/index.ts"],"names":[],"mappings":";AAAA,oCAAoC;;;;;;;;;;;;;;;;AAEpC,yBAAuB;AACvB,mCAAiC;AACjC,iCAA+B;AAC/B,iCAA+B;AAC/B,2BAAyB;AACzB,2BAAyB;AACzB,qBAAmB;AACnB,2BAAyB;AACzB,kBAAgB;AAGhB,4BAA4B;AAE5B,IAAM,WAAW,GAAG,+yRAA+yR,CAAC;AAGp0R,4BAA4B;AAE5B,uEAAsE;AACtE,4DAA2D;AAC3D,uDAAsD;AACtD,2EAA0E;AAC1E,6EAA4E;AAC5E,6CAA4C;AAC5C,+CAA8C;AAC9C,uFAAsF;AAEtF,IAAM,WAAW,GAAG;IACnB,uCAAuC,EAAE,+BAAc;IACvD,kCAAkC,EAAE,qBAAS;IAC7C,mCAAmC,EAAE,uBAAU;IAC/C,6CAA6C,EAAE,2CAAoB;IACnE,8CAA8C,EAAE,6CAAqB;IACrE,8BAA8B,EAAE,aAAK;IACrC,+BAA+B,EAAE,eAAM;IACvC,mDAAmD,EAAE,uDAA0B;CAC/E,CAAC;AAGF,kCAAkC;AAElC,oDAAyD;AACzD,6BAAgB,CAAC,KAAK,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;AAGjD,2CAAyB"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Route } from '@proteinjs/server-api';
|
|
2
|
+
/**
|
|
3
|
+
* Route handler for executing a password reset.
|
|
4
|
+
*
|
|
5
|
+
* This function handles the process of resetting a user's password using a provided reset token.
|
|
6
|
+
* It verifies the token, checks its expiration, and updates the user's password if everything is valid.
|
|
7
|
+
*
|
|
8
|
+
* @bodyParam {string} token - The password reset token.
|
|
9
|
+
* @bodyParam {string} newPassword - The new password for the user.
|
|
10
|
+
*
|
|
11
|
+
* @throws {Error} If there's an issue with the database operations or if the token is invalid or expired.
|
|
12
|
+
*/
|
|
13
|
+
export declare const executePasswordReset: Route;
|
|
14
|
+
//# sourceMappingURL=executePasswordReset.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executePasswordReset.d.ts","sourceRoot":"","sources":["../../../src/routes/executePasswordReset.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAO9C;;;;;;;;;;GAUG;AACH,eAAO,MAAM,oBAAoB,EAAE,KAqClC,CAAC"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
12
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
13
|
+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
14
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
15
|
+
function step(op) {
|
|
16
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
17
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
18
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
19
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
20
|
+
switch (op[0]) {
|
|
21
|
+
case 0: case 1: t = op; break;
|
|
22
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
23
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
24
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
25
|
+
default:
|
|
26
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
27
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
28
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
29
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
30
|
+
if (t[2]) _.ops.pop();
|
|
31
|
+
_.trys.pop(); continue;
|
|
32
|
+
}
|
|
33
|
+
op = body.call(thisArg, _);
|
|
34
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
35
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
39
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
40
|
+
};
|
|
41
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
42
|
+
exports.executePasswordReset = void 0;
|
|
43
|
+
var db_1 = require("@proteinjs/db");
|
|
44
|
+
var user_1 = require("@proteinjs/user");
|
|
45
|
+
var util_1 = require("@proteinjs/util");
|
|
46
|
+
var moment_1 = __importDefault(require("moment"));
|
|
47
|
+
var sha256_1 = __importDefault(require("crypto-js/sha256"));
|
|
48
|
+
/**
|
|
49
|
+
* Route handler for executing a password reset.
|
|
50
|
+
*
|
|
51
|
+
* This function handles the process of resetting a user's password using a provided reset token.
|
|
52
|
+
* It verifies the token, checks its expiration, and updates the user's password if everything is valid.
|
|
53
|
+
*
|
|
54
|
+
* @bodyParam {string} token - The password reset token.
|
|
55
|
+
* @bodyParam {string} newPassword - The new password for the user.
|
|
56
|
+
*
|
|
57
|
+
* @throws {Error} If there's an issue with the database operations or if the token is invalid or expired.
|
|
58
|
+
*/
|
|
59
|
+
exports.executePasswordReset = {
|
|
60
|
+
path: user_1.routes.executePasswordReset.path,
|
|
61
|
+
method: user_1.routes.executePasswordReset.method,
|
|
62
|
+
onRequest: function (request, response) { return __awaiter(void 0, void 0, void 0, function () {
|
|
63
|
+
var logger, _a, token, newPassword, db, user, currentTime, tokenExpiration, hashedPassword;
|
|
64
|
+
return __generator(this, function (_b) {
|
|
65
|
+
switch (_b.label) {
|
|
66
|
+
case 0:
|
|
67
|
+
logger = new util_1.Logger('executePasswordReset');
|
|
68
|
+
_a = request.body, token = _a.token, newPassword = _a.newPassword;
|
|
69
|
+
db = (0, db_1.getDbAsSystem)();
|
|
70
|
+
return [4 /*yield*/, db.get(user_1.tables.User, { passwordResetToken: token })];
|
|
71
|
+
case 1:
|
|
72
|
+
user = _b.sent();
|
|
73
|
+
if (!user) {
|
|
74
|
+
logger.info("Invalid reset token used: ".concat(token));
|
|
75
|
+
response.status(400).send({ error: 'Invalid or expired reset token' });
|
|
76
|
+
return [2 /*return*/];
|
|
77
|
+
}
|
|
78
|
+
currentTime = (0, moment_1.default)();
|
|
79
|
+
tokenExpiration = (0, moment_1.default)(user.passwordResetTokenExpiration);
|
|
80
|
+
if (currentTime.isAfter(tokenExpiration)) {
|
|
81
|
+
logger.info("Expired reset token used for user: ".concat(user.email));
|
|
82
|
+
response.status(400).send({ error: 'Reset token has expired' });
|
|
83
|
+
return [2 /*return*/];
|
|
84
|
+
}
|
|
85
|
+
hashedPassword = (0, sha256_1.default)(newPassword).toString();
|
|
86
|
+
return [4 /*yield*/, db.update(user_1.tables.User, {
|
|
87
|
+
id: user.id,
|
|
88
|
+
password: hashedPassword,
|
|
89
|
+
passwordResetToken: null,
|
|
90
|
+
passwordResetTokenExpiration: null,
|
|
91
|
+
})];
|
|
92
|
+
case 2:
|
|
93
|
+
_b.sent();
|
|
94
|
+
logger.info("Password successfully reset for user: ".concat(user.email));
|
|
95
|
+
response.send({ message: 'Password has been successfully reset' });
|
|
96
|
+
return [2 /*return*/];
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
}); },
|
|
100
|
+
};
|
|
101
|
+
//# sourceMappingURL=executePasswordReset.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executePasswordReset.js","sourceRoot":"","sources":["../../../src/routes/executePasswordReset.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,oCAA8C;AAC9C,wCAAiD;AACjD,wCAAyC;AACzC,kDAA4B;AAC5B,4DAAsC;AAEtC;;;;;;;;;;GAUG;AACU,QAAA,oBAAoB,GAAU;IACzC,IAAI,EAAE,aAAM,CAAC,oBAAoB,CAAC,IAAI;IACtC,MAAM,EAAE,aAAM,CAAC,oBAAoB,CAAC,MAAM;IAC1C,SAAS,EAAE,UAAO,OAAO,EAAE,QAAQ;;;;;oBAC3B,MAAM,GAAG,IAAI,aAAM,CAAC,sBAAsB,CAAC,CAAC;oBAC5C,KAAyB,OAAO,CAAC,IAAI,EAAnC,KAAK,WAAA,EAAE,WAAW,iBAAA,CAAkB;oBACtC,EAAE,GAAG,IAAA,kBAAa,GAAE,CAAC;oBAGd,qBAAM,EAAE,CAAC,GAAG,CAAC,aAAM,CAAC,IAAI,EAAE,EAAE,kBAAkB,EAAE,KAAK,EAAE,CAAC,EAAA;;oBAA/D,IAAI,GAAG,SAAwD;oBACrE,IAAI,CAAC,IAAI,EAAE;wBACT,MAAM,CAAC,IAAI,CAAC,oCAA6B,KAAK,CAAE,CAAC,CAAC;wBAClD,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,gCAAgC,EAAE,CAAC,CAAC;wBACvE,sBAAO;qBACR;oBAGK,WAAW,GAAG,IAAA,gBAAM,GAAE,CAAC;oBACvB,eAAe,GAAG,IAAA,gBAAM,EAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;oBAClE,IAAI,WAAW,CAAC,OAAO,CAAC,eAAe,CAAC,EAAE;wBACxC,MAAM,CAAC,IAAI,CAAC,6CAAsC,IAAI,CAAC,KAAK,CAAE,CAAC,CAAC;wBAChE,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,yBAAyB,EAAE,CAAC,CAAC;wBAChE,sBAAO;qBACR;oBAGK,cAAc,GAAG,IAAA,gBAAM,EAAC,WAAW,CAAC,CAAC,QAAQ,EAAE,CAAC;oBACtD,qBAAM,EAAE,CAAC,MAAM,CAAC,aAAM,CAAC,IAAI,EAAE;4BAC3B,EAAE,EAAE,IAAI,CAAC,EAAE;4BACX,QAAQ,EAAE,cAAc;4BACxB,kBAAkB,EAAE,IAAI;4BACxB,4BAA4B,EAAE,IAAI;yBACnC,CAAC,EAAA;;oBALF,SAKE,CAAC;oBAEH,MAAM,CAAC,IAAI,CAAC,gDAAyC,IAAI,CAAC,KAAK,CAAE,CAAC,CAAC;oBACnE,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,sCAAsC,EAAE,CAAC,CAAC;;;;SACpE;CACF,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Route } from '@proteinjs/server-api';
|
|
2
|
+
/**
|
|
3
|
+
* Route for initiating a password reset process.
|
|
4
|
+
*
|
|
5
|
+
* This route handles the process of generating a password reset token,
|
|
6
|
+
* sending a reset email to the user, and storing the token and expiration of the token in the database.
|
|
7
|
+
*
|
|
8
|
+
* Requires an implementation of `DefaultPasswordResetEmailConfigFactory` to build the password reset email with.
|
|
9
|
+
*
|
|
10
|
+
* @bodyParam {string} email - The email address of the user requesting a password reset.
|
|
11
|
+
* @bodyParam {string} resetPath - The path to the password reset page in the client application.
|
|
12
|
+
* This will be combined with the generated token to create the reset link that is emailed to the user.
|
|
13
|
+
*
|
|
14
|
+
* @throws {Error} If there's an issue with sending the email or updating the database.
|
|
15
|
+
*/
|
|
16
|
+
export declare const initiatePasswordReset: Route;
|
|
17
|
+
//# sourceMappingURL=initiatePasswordReset.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"initiatePasswordReset.d.ts","sourceRoot":"","sources":["../../../src/routes/initiatePasswordReset.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAW9C;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,qBAAqB,EAAE,KAgEnC,CAAC"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
12
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
13
|
+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
14
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
15
|
+
function step(op) {
|
|
16
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
17
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
18
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
19
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
20
|
+
switch (op[0]) {
|
|
21
|
+
case 0: case 1: t = op; break;
|
|
22
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
23
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
24
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
25
|
+
default:
|
|
26
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
27
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
28
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
29
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
30
|
+
if (t[2]) _.ops.pop();
|
|
31
|
+
_.trys.pop(); continue;
|
|
32
|
+
}
|
|
33
|
+
op = body.call(thisArg, _);
|
|
34
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
35
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
39
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
40
|
+
};
|
|
41
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
42
|
+
exports.initiatePasswordReset = void 0;
|
|
43
|
+
var db_1 = require("@proteinjs/db");
|
|
44
|
+
var user_1 = require("@proteinjs/user");
|
|
45
|
+
var util_1 = require("@proteinjs/util");
|
|
46
|
+
var moment_1 = __importDefault(require("moment"));
|
|
47
|
+
var email_server_1 = require("@proteinjs/email-server");
|
|
48
|
+
var crypto_js_1 = require("crypto-js");
|
|
49
|
+
/**
|
|
50
|
+
* Route for initiating a password reset process.
|
|
51
|
+
*
|
|
52
|
+
* This route handles the process of generating a password reset token,
|
|
53
|
+
* sending a reset email to the user, and storing the token and expiration of the token in the database.
|
|
54
|
+
*
|
|
55
|
+
* Requires an implementation of `DefaultPasswordResetEmailConfigFactory` to build the password reset email with.
|
|
56
|
+
*
|
|
57
|
+
* @bodyParam {string} email - The email address of the user requesting a password reset.
|
|
58
|
+
* @bodyParam {string} resetPath - The path to the password reset page in the client application.
|
|
59
|
+
* This will be combined with the generated token to create the reset link that is emailed to the user.
|
|
60
|
+
*
|
|
61
|
+
* @throws {Error} If there's an issue with sending the email or updating the database.
|
|
62
|
+
*/
|
|
63
|
+
exports.initiatePasswordReset = {
|
|
64
|
+
path: user_1.routes.initiatePasswordReset.path,
|
|
65
|
+
method: user_1.routes.initiatePasswordReset.method,
|
|
66
|
+
onRequest: function (request, response) { return __awaiter(void 0, void 0, void 0, function () {
|
|
67
|
+
var logger, _a, email, resetPath, db, genericResponse, user, currentTime, tokenAge, emailSender, defaultConfigFactory, passwordResetToken, passwordResetTokenExpiration, config, _b, text, html, error_1;
|
|
68
|
+
var _c;
|
|
69
|
+
return __generator(this, function (_d) {
|
|
70
|
+
switch (_d.label) {
|
|
71
|
+
case 0:
|
|
72
|
+
logger = new util_1.Logger('initiatePasswordReset');
|
|
73
|
+
_a = request.body, email = _a.email, resetPath = _a.resetPath;
|
|
74
|
+
db = (0, db_1.getDbAsSystem)();
|
|
75
|
+
genericResponse = { message: 'If an account with that email exists, we have sent a password reset link.' };
|
|
76
|
+
return [4 /*yield*/, db.get(user_1.tables.User, { email: email })];
|
|
77
|
+
case 1:
|
|
78
|
+
user = _d.sent();
|
|
79
|
+
if (!user) {
|
|
80
|
+
logger.info("Password reset requested for non-existent user: ".concat(email));
|
|
81
|
+
// Don't reveal that the user doesn't exist
|
|
82
|
+
response.send(genericResponse);
|
|
83
|
+
return [2 /*return*/];
|
|
84
|
+
}
|
|
85
|
+
currentTime = (0, moment_1.default)();
|
|
86
|
+
if (user.passwordResetToken && user.passwordResetTokenExpiration) {
|
|
87
|
+
tokenAge = currentTime.diff((0, moment_1.default)(user.passwordResetTokenExpiration), 'minutes');
|
|
88
|
+
if (tokenAge < -55) {
|
|
89
|
+
// Token is less than 5 minutes old
|
|
90
|
+
logger.info("Password reset requested too soon for user: ".concat(email));
|
|
91
|
+
response.send(genericResponse);
|
|
92
|
+
return [2 /*return*/];
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
emailSender = new email_server_1.EmailSender();
|
|
96
|
+
defaultConfigFactory = (0, email_server_1.getDefaultPasswordResetEmailConfigFactory)();
|
|
97
|
+
if (!defaultConfigFactory) {
|
|
98
|
+
throw new Error("Unable to find a @proteinjs/email-server/DefaultPasswordResetEmailConfigFactory implementation when initiating password reset.");
|
|
99
|
+
}
|
|
100
|
+
passwordResetToken = crypto_js_1.lib.WordArray.random(32).toString();
|
|
101
|
+
passwordResetTokenExpiration = (0, moment_1.default)().add(1, 'hour');
|
|
102
|
+
_d.label = 2;
|
|
103
|
+
case 2:
|
|
104
|
+
_d.trys.push([2, 5, , 6]);
|
|
105
|
+
config = defaultConfigFactory.getConfig();
|
|
106
|
+
_b = config.getEmailContent("".concat(resetPath, "?token=").concat(passwordResetToken)), text = _b.text, html = _b.html;
|
|
107
|
+
// Send email containing a reset link
|
|
108
|
+
return [4 /*yield*/, emailSender.sendEmail({
|
|
109
|
+
to: user.email,
|
|
110
|
+
subject: ((_c = config.options) === null || _c === void 0 ? void 0 : _c.subject) || 'Reset Password',
|
|
111
|
+
text: text,
|
|
112
|
+
html: html,
|
|
113
|
+
})];
|
|
114
|
+
case 3:
|
|
115
|
+
// Send email containing a reset link
|
|
116
|
+
_d.sent();
|
|
117
|
+
// If email is sent successfully, save reset token to user record
|
|
118
|
+
return [4 /*yield*/, db.update(user_1.tables.User, { id: user.id, passwordResetToken: passwordResetToken, passwordResetTokenExpiration: passwordResetTokenExpiration })];
|
|
119
|
+
case 4:
|
|
120
|
+
// If email is sent successfully, save reset token to user record
|
|
121
|
+
_d.sent();
|
|
122
|
+
response.send(genericResponse);
|
|
123
|
+
return [3 /*break*/, 6];
|
|
124
|
+
case 5:
|
|
125
|
+
error_1 = _d.sent();
|
|
126
|
+
logger.error("Failed to send password reset email to: ".concat(email), error_1);
|
|
127
|
+
response.status(500).send({ error: 'Failed to send password reset email. Please try again later.' });
|
|
128
|
+
return [3 /*break*/, 6];
|
|
129
|
+
case 6: return [2 /*return*/];
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
}); },
|
|
133
|
+
};
|
|
134
|
+
//# sourceMappingURL=initiatePasswordReset.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"initiatePasswordReset.js","sourceRoot":"","sources":["../../../src/routes/initiatePasswordReset.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,oCAA8C;AAC9C,wCAAiD;AACjD,wCAAyC;AACzC,kDAA4B;AAC5B,wDAGiC;AACjC,uCAAgC;AAEhC;;;;;;;;;;;;;GAaG;AACU,QAAA,qBAAqB,GAAU;IAC1C,IAAI,EAAE,aAAM,CAAC,qBAAqB,CAAC,IAAI;IACvC,MAAM,EAAE,aAAM,CAAC,qBAAqB,CAAC,MAAM;IAC3C,SAAS,EAAE,UAAO,OAAO,EAAE,QAAQ;;;;;;oBAC3B,MAAM,GAAG,IAAI,aAAM,CAAC,uBAAuB,CAAC,CAAC;oBAC7C,KAAuB,OAAO,CAAC,IAAI,EAAjC,KAAK,WAAA,EAAE,SAAS,eAAA,CAAkB;oBACpC,EAAE,GAAG,IAAA,kBAAa,GAAE,CAAC;oBAErB,eAAe,GAAG,EAAE,OAAO,EAAE,2EAA2E,EAAE,CAAC;oBAGpG,qBAAM,EAAE,CAAC,GAAG,CAAC,aAAM,CAAC,IAAI,EAAE,EAAE,KAAK,OAAA,EAAE,CAAC,EAAA;;oBAA3C,IAAI,GAAG,SAAoC;oBACjD,IAAI,CAAC,IAAI,EAAE;wBACT,MAAM,CAAC,IAAI,CAAC,0DAAmD,KAAK,CAAE,CAAC,CAAC;wBACxE,2CAA2C;wBAC3C,QAAQ,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;wBAC/B,sBAAO;qBACR;oBAGK,WAAW,GAAG,IAAA,gBAAM,GAAE,CAAC;oBAC7B,IAAI,IAAI,CAAC,kBAAkB,IAAI,IAAI,CAAC,4BAA4B,EAAE;wBAC1D,QAAQ,GAAG,WAAW,CAAC,IAAI,CAAC,IAAA,gBAAM,EAAC,IAAI,CAAC,4BAA4B,CAAC,EAAE,SAAS,CAAC,CAAC;wBACxF,IAAI,QAAQ,GAAG,CAAC,EAAE,EAAE;4BAClB,mCAAmC;4BACnC,MAAM,CAAC,IAAI,CAAC,sDAA+C,KAAK,CAAE,CAAC,CAAC;4BACpE,QAAQ,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;4BAC/B,sBAAO;yBACR;qBACF;oBAEK,WAAW,GAAG,IAAI,0BAAW,EAAE,CAAC;oBAEhC,oBAAoB,GAAG,IAAA,wDAAuB,GAAE,CAAC;oBACvD,IAAI,CAAC,oBAAoB,EAAE;wBACzB,MAAM,IAAI,KAAK,CACb,gIAAgI,CACjI,CAAC;qBACH;oBAGK,kBAAkB,GAAG,eAAG,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC;oBACzD,4BAA4B,GAAG,IAAA,gBAAM,GAAE,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;;;;oBAGrD,MAAM,GAAG,oBAAoB,CAAC,SAAS,EAAE,CAAC;oBAC1C,KAAiB,MAAM,CAAC,eAAe,CAAC,UAAG,SAAS,oBAAU,kBAAkB,CAAE,CAAC,EAAjF,IAAI,UAAA,EAAE,IAAI,UAAA,CAAwE;oBAE1F,qCAAqC;oBACrC,qBAAM,WAAW,CAAC,SAAS,CAAC;4BAC1B,EAAE,EAAE,IAAI,CAAC,KAAK;4BACd,OAAO,EAAE,CAAA,MAAA,MAAM,CAAC,OAAO,0CAAE,OAAO,KAAI,gBAAgB;4BACpD,IAAI,MAAA;4BACJ,IAAI,MAAA;yBACL,CAAC,EAAA;;oBANF,qCAAqC;oBACrC,SAKE,CAAC;oBAEH,iEAAiE;oBACjE,qBAAM,EAAE,CAAC,MAAM,CAAC,aAAM,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,kBAAkB,oBAAA,EAAE,4BAA4B,8BAAA,EAAE,CAAC,EAAA;;oBAD/F,iEAAiE;oBACjE,SAA+F,CAAC;oBAChG,QAAQ,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;;;;oBAE/B,MAAM,CAAC,KAAK,CAAC,kDAA2C,KAAK,CAAE,EAAE,OAAK,CAAC,CAAC;oBACxE,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,8DAA8D,EAAE,CAAC,CAAC;;;;;SAExG;CACF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validateResetPasswordToken.d.ts","sourceRoot":"","sources":["../../../src/routes/validateResetPasswordToken.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAM9C,eAAO,MAAM,0BAA0B,EAAE,KAgCxC,CAAC"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
12
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
13
|
+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
14
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
15
|
+
function step(op) {
|
|
16
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
17
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
18
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
19
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
20
|
+
switch (op[0]) {
|
|
21
|
+
case 0: case 1: t = op; break;
|
|
22
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
23
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
24
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
25
|
+
default:
|
|
26
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
27
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
28
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
29
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
30
|
+
if (t[2]) _.ops.pop();
|
|
31
|
+
_.trys.pop(); continue;
|
|
32
|
+
}
|
|
33
|
+
op = body.call(thisArg, _);
|
|
34
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
35
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
39
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
40
|
+
};
|
|
41
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
42
|
+
exports.validateResetPasswordToken = void 0;
|
|
43
|
+
var db_1 = require("@proteinjs/db");
|
|
44
|
+
var user_1 = require("@proteinjs/user");
|
|
45
|
+
var util_1 = require("@proteinjs/util");
|
|
46
|
+
var moment_1 = __importDefault(require("moment"));
|
|
47
|
+
exports.validateResetPasswordToken = {
|
|
48
|
+
path: user_1.routes.validateResetToken.path,
|
|
49
|
+
method: user_1.routes.validateResetToken.method,
|
|
50
|
+
onRequest: function (request, response) { return __awaiter(void 0, void 0, void 0, function () {
|
|
51
|
+
var logger, token, db, user, currentTime, tokenExpiration;
|
|
52
|
+
return __generator(this, function (_a) {
|
|
53
|
+
switch (_a.label) {
|
|
54
|
+
case 0:
|
|
55
|
+
logger = new util_1.Logger('validateResetToken');
|
|
56
|
+
token = request.query.token;
|
|
57
|
+
db = (0, db_1.getDbAsSystem)();
|
|
58
|
+
if (!token) {
|
|
59
|
+
response.status(400).send({ isValid: false, message: 'No token provided' });
|
|
60
|
+
return [2 /*return*/];
|
|
61
|
+
}
|
|
62
|
+
return [4 /*yield*/, db.get(user_1.tables.User, { passwordResetToken: token })];
|
|
63
|
+
case 1:
|
|
64
|
+
user = _a.sent();
|
|
65
|
+
if (!user) {
|
|
66
|
+
logger.info("Invalid reset token used: ".concat(token));
|
|
67
|
+
response.status(200).send({ isValid: false, message: 'Invalid token' });
|
|
68
|
+
return [2 /*return*/];
|
|
69
|
+
}
|
|
70
|
+
currentTime = (0, moment_1.default)();
|
|
71
|
+
tokenExpiration = (0, moment_1.default)(user.passwordResetTokenExpiration);
|
|
72
|
+
if (currentTime.isAfter(tokenExpiration)) {
|
|
73
|
+
logger.info("Expired reset token used for user: ".concat(user.email));
|
|
74
|
+
response.status(200).send({ isValid: false, message: 'Token has expired' });
|
|
75
|
+
return [2 /*return*/];
|
|
76
|
+
}
|
|
77
|
+
response.status(200).send({ isValid: true });
|
|
78
|
+
return [2 /*return*/];
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
}); },
|
|
82
|
+
};
|
|
83
|
+
//# sourceMappingURL=validateResetPasswordToken.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validateResetPasswordToken.js","sourceRoot":"","sources":["../../../src/routes/validateResetPasswordToken.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,oCAA8C;AAC9C,wCAAiD;AACjD,wCAAyC;AACzC,kDAA4B;AAEf,QAAA,0BAA0B,GAAU;IAC/C,IAAI,EAAE,aAAM,CAAC,kBAAkB,CAAC,IAAI;IACpC,MAAM,EAAE,aAAM,CAAC,kBAAkB,CAAC,MAAM;IACxC,SAAS,EAAE,UAAO,OAAO,EAAE,QAAQ;;;;;oBAC3B,MAAM,GAAG,IAAI,aAAM,CAAC,oBAAoB,CAAC,CAAC;oBACxC,KAAK,GAAK,OAAO,CAAC,KAAK,MAAlB,CAAmB;oBAC1B,EAAE,GAAG,IAAA,kBAAa,GAAE,CAAC;oBAE3B,IAAI,CAAC,KAAK,EAAE;wBACV,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,mBAAmB,EAAE,CAAC,CAAC;wBAC5E,sBAAO;qBACR;oBAGY,qBAAM,EAAE,CAAC,GAAG,CAAC,aAAM,CAAC,IAAI,EAAE,EAAE,kBAAkB,EAAE,KAAK,EAAE,CAAC,EAAA;;oBAA/D,IAAI,GAAG,SAAwD;oBACrE,IAAI,CAAC,IAAI,EAAE;wBACT,MAAM,CAAC,IAAI,CAAC,oCAA6B,KAAK,CAAE,CAAC,CAAC;wBAClD,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,eAAe,EAAE,CAAC,CAAC;wBACxE,sBAAO;qBACR;oBAGK,WAAW,GAAG,IAAA,gBAAM,GAAE,CAAC;oBACvB,eAAe,GAAG,IAAA,gBAAM,EAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;oBAClE,IAAI,WAAW,CAAC,OAAO,CAAC,eAAe,CAAC,EAAE;wBACxC,MAAM,CAAC,IAAI,CAAC,6CAAsC,IAAI,CAAC,KAAK,CAAE,CAAC,CAAC;wBAChE,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,mBAAmB,EAAE,CAAC,CAAC;wBAC5E,sBAAO;qBACR;oBAED,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;;;;SAC9C;CACF,CAAC"}
|
package/generated/index.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/** Load Dependency Source Graphs */
|
|
2
2
|
|
|
3
3
|
import '@proteinjs/db';
|
|
4
|
+
import '@proteinjs/email-server';
|
|
4
5
|
import '@proteinjs/reflection';
|
|
5
6
|
import '@proteinjs/server-api';
|
|
6
7
|
import '@proteinjs/user';
|
|
@@ -12,7 +13,7 @@ import 'moment';
|
|
|
12
13
|
|
|
13
14
|
/** Generate Source Graph */
|
|
14
15
|
|
|
15
|
-
const sourceGraph = "{\"options\":{\"directed\":true,\"multigraph\":false,\"compound\":false},\"nodes\":[{\"v\":\"@proteinjs/user-server/DbSessionStore\",\"value\":{\"packageName\":\"@proteinjs/user-server\",\"name\":\"DbSessionStore\",\"filePath\":\"/Users/veronica/Repositories/n3xa-meta-repo/packages/proteinjs/packages/user/packages/server/src/authentication/DbSessionStore.ts\",\"qualifiedName\":\"@proteinjs/user-server/DbSessionStore\",\"isAbstract\":false,\"isStatic\":false,\"visibility\":\"public\",\"properties\":[{\"name\":\"TWELVE_HOURS\",\"type\":null,\"isOptional\":false,\"isAbstract\":false,\"isStatic\":true,\"visibility\":\"private\"},{\"name\":\"get\",\"type\":null,\"isOptional\":false,\"isAbstract\":false,\"isStatic\":false,\"visibility\":\"public\"},{\"name\":\"set\",\"type\":null,\"isOptional\":false,\"isAbstract\":false,\"isStatic\":false,\"visibility\":\"public\"},{\"name\":\"touch\",\"type\":null,\"isOptional\":false,\"isAbstract\":false,\"isStatic\":false,\"visibility\":\"public\"},{\"name\":\"destroy\",\"type\":null,\"isOptional\":false,\"isAbstract\":false,\"isStatic\":false,\"visibility\":\"public\"}],\"methods\":[{\"name\":\"insertOrUpdate\",\"returnType\":{\"packageName\":\"\",\"name\":\"Promise<void>\",\"filePath\":null,\"qualifiedName\":\"/Promise<void>\",\"typeParameters\":null,\"directParents\":null},\"isAsync\":true,\"isOptional\":false,\"isAbstract\":false,\"isStatic\":false,\"visibility\":\"private\",\"parameters\":[{\"name\":\"sessionId\",\"type\":{\"packageName\":\"\",\"name\":\"string\",\"filePath\":null,\"qualifiedName\":\"/string\",\"typeParameters\":null,\"directParents\":null}},{\"name\":\"session\",\"type\":{\"packageName\":\"\",\"name\":\"Express.SessionData\",\"filePath\":null,\"qualifiedName\":\"/Express.SessionData\",\"typeParameters\":null,\"directParents\":null}},{\"name\":\"cb\",\"type\":{\"packageName\":\"\",\"name\":\"(error?: any) => void\",\"filePath\":null,\"qualifiedName\":\"/(error?: any) => void\",\"typeParameters\":null,\"directParents\":null}}]},{\"name\":\"sweep\",\"returnType\":{\"packageName\":\"\",\"name\":\"Promise<void>\",\"filePath\":null,\"qualifiedName\":\"/Promise<void>\",\"typeParameters\":null,\"directParents\":null},\"isAsync\":true,\"isOptional\":false,\"isAbstract\":false,\"isStatic\":false,\"visibility\":\"private\",\"parameters\":[]}],\"typeParameters\":[],\"directParentInterfaces\":[],\"directParentClasses\":[{\"packageName\":\"express-session\",\"name\":\"Store\",\"filePath\":null,\"qualifiedName\":\"express-session/Store\",\"isAbstract\":false,\"isStatic\":false,\"visibility\":\"public\",\"properties\":[],\"methods\":[],\"typeParameters\":[],\"directParentInterfaces\":[],\"directParentClasses\":[]}],\"sourceType\":2}},{\"v\":\"express-session/Store\"},{\"v\":\"@proteinjs/user-server/userCache\",\"value\":{\"packageName\":\"@proteinjs/user-server\",\"name\":\"userCache\",\"filePath\":\"/Users/veronica/Repositories/n3xa-meta-repo/packages/proteinjs/packages/user/packages/server/src/authorization/userCache.ts\",\"qualifiedName\":\"@proteinjs/user-server/userCache\",\"type\":{\"packageName\":\"\",\"name\":\"SessionDataCache<User>\",\"filePath\":null,\"qualifiedName\":\"/SessionDataCache<User>\",\"typeParameters\":[],\"directParents\":[{\"packageName\":\"@proteinjs/server-api\",\"name\":\"SessionDataCache\",\"filePath\":null,\"qualifiedName\":\"@proteinjs/server-api/SessionDataCache\",\"typeParameters\":[\"@proteinjs/user/User\"],\"directParents\":null}]},\"isExported\":true,\"isConst\":true,\"sourceType\":0}},{\"v\":\"@proteinjs/server-api/SessionDataCache\"},{\"v\":\"@proteinjs/user-server/createUser\",\"value\":{\"packageName\":\"@proteinjs/user-server\",\"name\":\"createUser\",\"filePath\":\"/Users/veronica/Repositories/n3xa-meta-repo/packages/proteinjs/packages/user/packages/server/src/routes/createUser.ts\",\"qualifiedName\":\"@proteinjs/user-server/createUser\",\"type\":{\"packageName\":\"@proteinjs/server-api\",\"name\":\"Route\",\"filePath\":null,\"qualifiedName\":\"@proteinjs/server-api/Route\",\"typeParameters\":[],\"directParents\":[{\"packageName\":\"@proteinjs/server-api\",\"name\":\"Route\",\"filePath\":null,\"qualifiedName\":\"@proteinjs/server-api/Route\",\"typeParameters\":[],\"directParents\":null}]},\"isExported\":true,\"isConst\":true,\"sourceType\":0}},{\"v\":\"@proteinjs/server-api/Route\"},{\"v\":\"@proteinjs/user-server/login\",\"value\":{\"packageName\":\"@proteinjs/user-server\",\"name\":\"login\",\"filePath\":\"/Users/veronica/Repositories/n3xa-meta-repo/packages/proteinjs/packages/user/packages/server/src/routes/login.ts\",\"qualifiedName\":\"@proteinjs/user-server/login\",\"type\":{\"packageName\":\"@proteinjs/server-api\",\"name\":\"Route\",\"filePath\":null,\"qualifiedName\":\"@proteinjs/server-api/Route\",\"typeParameters\":[],\"directParents\":[{\"packageName\":\"@proteinjs/server-api\",\"name\":\"Route\",\"filePath\":null,\"qualifiedName\":\"@proteinjs/server-api/Route\",\"typeParameters\":[],\"directParents\":null}]},\"isExported\":true,\"isConst\":true,\"sourceType\":0}},{\"v\":\"@proteinjs/user-server/logout\",\"value\":{\"packageName\":\"@proteinjs/user-server\",\"name\":\"logout\",\"filePath\":\"/Users/veronica/Repositories/n3xa-meta-repo/packages/proteinjs/packages/user/packages/server/src/routes/logout.ts\",\"qualifiedName\":\"@proteinjs/user-server/logout\",\"type\":{\"packageName\":\"@proteinjs/server-api\",\"name\":\"Route\",\"filePath\":null,\"qualifiedName\":\"@proteinjs/server-api/Route\",\"typeParameters\":[],\"directParents\":[{\"packageName\":\"@proteinjs/server-api\",\"name\":\"Route\",\"filePath\":null,\"qualifiedName\":\"@proteinjs/server-api/Route\",\"typeParameters\":[],\"directParents\":null}]},\"isExported\":true,\"isConst\":true,\"sourceType\":0}}],\"edges\":[{\"v\":\"@proteinjs/user-server/DbSessionStore\",\"w\":\"express-session/Store\",\"value\":\"extends class\"},{\"v\":\"@proteinjs/user-server/userCache\",\"w\":\"@proteinjs/server-api/SessionDataCache\",\"value\":\"has type\"},{\"v\":\"@proteinjs/user-server/createUser\",\"w\":\"@proteinjs/server-api/Route\",\"value\":\"has type\"},{\"v\":\"@proteinjs/user-server/login\",\"w\":\"@proteinjs/server-api/Route\",\"value\":\"has type\"},{\"v\":\"@proteinjs/user-server/logout\",\"w\":\"@proteinjs/server-api/Route\",\"value\":\"has type\"}]}";
|
|
16
|
+
const sourceGraph = "{\"options\":{\"directed\":true,\"multigraph\":false,\"compound\":false},\"nodes\":[{\"v\":\"@proteinjs/user-server/DbSessionStore\",\"value\":{\"packageName\":\"@proteinjs/user-server\",\"name\":\"DbSessionStore\",\"filePath\":\"/Users/veronica/Repositories/n3xa-meta-repo/packages/proteinjs/packages/user/packages/server/src/authentication/DbSessionStore.ts\",\"qualifiedName\":\"@proteinjs/user-server/DbSessionStore\",\"isAbstract\":false,\"isStatic\":false,\"visibility\":\"public\",\"properties\":[{\"name\":\"TWELVE_HOURS\",\"type\":null,\"isOptional\":false,\"isAbstract\":false,\"isStatic\":true,\"visibility\":\"private\"},{\"name\":\"get\",\"type\":null,\"isOptional\":false,\"isAbstract\":false,\"isStatic\":false,\"visibility\":\"public\"},{\"name\":\"set\",\"type\":null,\"isOptional\":false,\"isAbstract\":false,\"isStatic\":false,\"visibility\":\"public\"},{\"name\":\"touch\",\"type\":null,\"isOptional\":false,\"isAbstract\":false,\"isStatic\":false,\"visibility\":\"public\"},{\"name\":\"destroy\",\"type\":null,\"isOptional\":false,\"isAbstract\":false,\"isStatic\":false,\"visibility\":\"public\"}],\"methods\":[{\"name\":\"insertOrUpdate\",\"returnType\":{\"packageName\":\"\",\"name\":\"Promise<void>\",\"filePath\":null,\"qualifiedName\":\"/Promise<void>\",\"typeParameters\":null,\"directParents\":null},\"isAsync\":true,\"isOptional\":false,\"isAbstract\":false,\"isStatic\":false,\"visibility\":\"private\",\"parameters\":[{\"name\":\"sessionId\",\"type\":{\"packageName\":\"\",\"name\":\"string\",\"filePath\":null,\"qualifiedName\":\"/string\",\"typeParameters\":null,\"directParents\":null}},{\"name\":\"session\",\"type\":{\"packageName\":\"\",\"name\":\"Express.SessionData\",\"filePath\":null,\"qualifiedName\":\"/Express.SessionData\",\"typeParameters\":null,\"directParents\":null}},{\"name\":\"cb\",\"type\":{\"packageName\":\"\",\"name\":\"(error?: any) => void\",\"filePath\":null,\"qualifiedName\":\"/(error?: any) => void\",\"typeParameters\":null,\"directParents\":null}}]},{\"name\":\"sweep\",\"returnType\":{\"packageName\":\"\",\"name\":\"Promise<void>\",\"filePath\":null,\"qualifiedName\":\"/Promise<void>\",\"typeParameters\":null,\"directParents\":null},\"isAsync\":true,\"isOptional\":false,\"isAbstract\":false,\"isStatic\":false,\"visibility\":\"private\",\"parameters\":[]}],\"typeParameters\":[],\"directParentInterfaces\":[],\"directParentClasses\":[{\"packageName\":\"express-session\",\"name\":\"Store\",\"filePath\":null,\"qualifiedName\":\"express-session/Store\",\"isAbstract\":false,\"isStatic\":false,\"visibility\":\"public\",\"properties\":[],\"methods\":[],\"typeParameters\":[],\"directParentInterfaces\":[],\"directParentClasses\":[]}],\"sourceType\":2}},{\"v\":\"express-session/Store\"},{\"v\":\"@proteinjs/user-server/userCache\",\"value\":{\"packageName\":\"@proteinjs/user-server\",\"name\":\"userCache\",\"filePath\":\"/Users/veronica/Repositories/n3xa-meta-repo/packages/proteinjs/packages/user/packages/server/src/authorization/userCache.ts\",\"qualifiedName\":\"@proteinjs/user-server/userCache\",\"type\":{\"packageName\":\"\",\"name\":\"SessionDataCache<User>\",\"filePath\":null,\"qualifiedName\":\"/SessionDataCache<User>\",\"typeParameters\":[],\"directParents\":[{\"packageName\":\"@proteinjs/server-api\",\"name\":\"SessionDataCache\",\"filePath\":null,\"qualifiedName\":\"@proteinjs/server-api/SessionDataCache\",\"typeParameters\":[\"@proteinjs/user/User\"],\"directParents\":null}]},\"isExported\":true,\"isConst\":true,\"sourceType\":0}},{\"v\":\"@proteinjs/server-api/SessionDataCache\"},{\"v\":\"@proteinjs/user-server/createUser\",\"value\":{\"packageName\":\"@proteinjs/user-server\",\"name\":\"createUser\",\"filePath\":\"/Users/veronica/Repositories/n3xa-meta-repo/packages/proteinjs/packages/user/packages/server/src/routes/createUser.ts\",\"qualifiedName\":\"@proteinjs/user-server/createUser\",\"type\":{\"packageName\":\"@proteinjs/server-api\",\"name\":\"Route\",\"filePath\":null,\"qualifiedName\":\"@proteinjs/server-api/Route\",\"typeParameters\":[],\"directParents\":[{\"packageName\":\"@proteinjs/server-api\",\"name\":\"Route\",\"filePath\":null,\"qualifiedName\":\"@proteinjs/server-api/Route\",\"typeParameters\":[],\"directParents\":null}]},\"isExported\":true,\"isConst\":true,\"sourceType\":0}},{\"v\":\"@proteinjs/server-api/Route\"},{\"v\":\"@proteinjs/user-server/executePasswordReset\",\"value\":{\"packageName\":\"@proteinjs/user-server\",\"name\":\"executePasswordReset\",\"filePath\":\"/Users/veronica/Repositories/n3xa-meta-repo/packages/proteinjs/packages/user/packages/server/src/routes/executePasswordReset.ts\",\"qualifiedName\":\"@proteinjs/user-server/executePasswordReset\",\"type\":{\"packageName\":\"@proteinjs/server-api\",\"name\":\"Route\",\"filePath\":null,\"qualifiedName\":\"@proteinjs/server-api/Route\",\"typeParameters\":[],\"directParents\":[{\"packageName\":\"@proteinjs/server-api\",\"name\":\"Route\",\"filePath\":null,\"qualifiedName\":\"@proteinjs/server-api/Route\",\"typeParameters\":[],\"directParents\":null}]},\"isExported\":true,\"isConst\":true,\"sourceType\":0}},{\"v\":\"@proteinjs/user-server/initiatePasswordReset\",\"value\":{\"packageName\":\"@proteinjs/user-server\",\"name\":\"initiatePasswordReset\",\"filePath\":\"/Users/veronica/Repositories/n3xa-meta-repo/packages/proteinjs/packages/user/packages/server/src/routes/initiatePasswordReset.ts\",\"qualifiedName\":\"@proteinjs/user-server/initiatePasswordReset\",\"type\":{\"packageName\":\"@proteinjs/server-api\",\"name\":\"Route\",\"filePath\":null,\"qualifiedName\":\"@proteinjs/server-api/Route\",\"typeParameters\":[],\"directParents\":[{\"packageName\":\"@proteinjs/server-api\",\"name\":\"Route\",\"filePath\":null,\"qualifiedName\":\"@proteinjs/server-api/Route\",\"typeParameters\":[],\"directParents\":null}]},\"isExported\":true,\"isConst\":true,\"sourceType\":0}},{\"v\":\"@proteinjs/user-server/login\",\"value\":{\"packageName\":\"@proteinjs/user-server\",\"name\":\"login\",\"filePath\":\"/Users/veronica/Repositories/n3xa-meta-repo/packages/proteinjs/packages/user/packages/server/src/routes/login.ts\",\"qualifiedName\":\"@proteinjs/user-server/login\",\"type\":{\"packageName\":\"@proteinjs/server-api\",\"name\":\"Route\",\"filePath\":null,\"qualifiedName\":\"@proteinjs/server-api/Route\",\"typeParameters\":[],\"directParents\":[{\"packageName\":\"@proteinjs/server-api\",\"name\":\"Route\",\"filePath\":null,\"qualifiedName\":\"@proteinjs/server-api/Route\",\"typeParameters\":[],\"directParents\":null}]},\"isExported\":true,\"isConst\":true,\"sourceType\":0}},{\"v\":\"@proteinjs/user-server/logout\",\"value\":{\"packageName\":\"@proteinjs/user-server\",\"name\":\"logout\",\"filePath\":\"/Users/veronica/Repositories/n3xa-meta-repo/packages/proteinjs/packages/user/packages/server/src/routes/logout.ts\",\"qualifiedName\":\"@proteinjs/user-server/logout\",\"type\":{\"packageName\":\"@proteinjs/server-api\",\"name\":\"Route\",\"filePath\":null,\"qualifiedName\":\"@proteinjs/server-api/Route\",\"typeParameters\":[],\"directParents\":[{\"packageName\":\"@proteinjs/server-api\",\"name\":\"Route\",\"filePath\":null,\"qualifiedName\":\"@proteinjs/server-api/Route\",\"typeParameters\":[],\"directParents\":null}]},\"isExported\":true,\"isConst\":true,\"sourceType\":0}},{\"v\":\"@proteinjs/user-server/validateResetPasswordToken\",\"value\":{\"packageName\":\"@proteinjs/user-server\",\"name\":\"validateResetPasswordToken\",\"filePath\":\"/Users/veronica/Repositories/n3xa-meta-repo/packages/proteinjs/packages/user/packages/server/src/routes/validateResetPasswordToken.ts\",\"qualifiedName\":\"@proteinjs/user-server/validateResetPasswordToken\",\"type\":{\"packageName\":\"@proteinjs/server-api\",\"name\":\"Route\",\"filePath\":null,\"qualifiedName\":\"@proteinjs/server-api/Route\",\"typeParameters\":[],\"directParents\":[{\"packageName\":\"@proteinjs/server-api\",\"name\":\"Route\",\"filePath\":null,\"qualifiedName\":\"@proteinjs/server-api/Route\",\"typeParameters\":[],\"directParents\":null}]},\"isExported\":true,\"isConst\":true,\"sourceType\":0}}],\"edges\":[{\"v\":\"@proteinjs/user-server/DbSessionStore\",\"w\":\"express-session/Store\",\"value\":\"extends class\"},{\"v\":\"@proteinjs/user-server/userCache\",\"w\":\"@proteinjs/server-api/SessionDataCache\",\"value\":\"has type\"},{\"v\":\"@proteinjs/user-server/createUser\",\"w\":\"@proteinjs/server-api/Route\",\"value\":\"has type\"},{\"v\":\"@proteinjs/user-server/executePasswordReset\",\"w\":\"@proteinjs/server-api/Route\",\"value\":\"has type\"},{\"v\":\"@proteinjs/user-server/initiatePasswordReset\",\"w\":\"@proteinjs/server-api/Route\",\"value\":\"has type\"},{\"v\":\"@proteinjs/user-server/login\",\"w\":\"@proteinjs/server-api/Route\",\"value\":\"has type\"},{\"v\":\"@proteinjs/user-server/logout\",\"w\":\"@proteinjs/server-api/Route\",\"value\":\"has type\"},{\"v\":\"@proteinjs/user-server/validateResetPasswordToken\",\"w\":\"@proteinjs/server-api/Route\",\"value\":\"has type\"}]}";
|
|
16
17
|
|
|
17
18
|
|
|
18
19
|
/** Generate Source Links */
|
|
@@ -20,15 +21,21 @@ const sourceGraph = "{\"options\":{\"directed\":true,\"multigraph\":false,\"comp
|
|
|
20
21
|
import { DbSessionStore } from '../src/authentication/DbSessionStore';
|
|
21
22
|
import { userCache } from '../src/authorization/userCache';
|
|
22
23
|
import { createUser } from '../src/routes/createUser';
|
|
24
|
+
import { executePasswordReset } from '../src/routes/executePasswordReset';
|
|
25
|
+
import { initiatePasswordReset } from '../src/routes/initiatePasswordReset';
|
|
23
26
|
import { login } from '../src/routes/login';
|
|
24
27
|
import { logout } from '../src/routes/logout';
|
|
28
|
+
import { validateResetPasswordToken } from '../src/routes/validateResetPasswordToken';
|
|
25
29
|
|
|
26
30
|
const sourceLinks = {
|
|
27
31
|
'@proteinjs/user-server/DbSessionStore': DbSessionStore,
|
|
28
32
|
'@proteinjs/user-server/userCache': userCache,
|
|
29
33
|
'@proteinjs/user-server/createUser': createUser,
|
|
34
|
+
'@proteinjs/user-server/executePasswordReset': executePasswordReset,
|
|
35
|
+
'@proteinjs/user-server/initiatePasswordReset': initiatePasswordReset,
|
|
30
36
|
'@proteinjs/user-server/login': login,
|
|
31
37
|
'@proteinjs/user-server/logout': logout,
|
|
38
|
+
'@proteinjs/user-server/validateResetPasswordToken': validateResetPasswordToken,
|
|
32
39
|
};
|
|
33
40
|
|
|
34
41
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@proteinjs/user-server",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.35",
|
|
4
4
|
"description": "User server components",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -21,17 +21,18 @@
|
|
|
21
21
|
"watch": "reflection-watch"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@proteinjs/db": "1.3.
|
|
25
|
-
"@proteinjs/
|
|
26
|
-
"@proteinjs/
|
|
27
|
-
"@proteinjs/
|
|
28
|
-
"@proteinjs/
|
|
24
|
+
"@proteinjs/db": "1.3.2",
|
|
25
|
+
"@proteinjs/email-server": "1.0.4",
|
|
26
|
+
"@proteinjs/reflection": "1.1.7",
|
|
27
|
+
"@proteinjs/server-api": "1.3.4",
|
|
28
|
+
"@proteinjs/user": "^1.0.35",
|
|
29
|
+
"@proteinjs/util": "1.3.1",
|
|
29
30
|
"crypto-js": "4.0.0",
|
|
30
31
|
"express-session": "1.17.1",
|
|
31
32
|
"moment": "2.29.4"
|
|
32
33
|
},
|
|
33
34
|
"devDependencies": {
|
|
34
|
-
"@proteinjs/reflection-build": "1.0.
|
|
35
|
+
"@proteinjs/reflection-build": "1.0.22",
|
|
35
36
|
"@types/crypto-js": "4.0.1",
|
|
36
37
|
"@types/express-session": "1.17.0",
|
|
37
38
|
"@types/node": "14.0.13",
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { Route } from '@proteinjs/server-api';
|
|
2
|
+
import { getDbAsSystem } from '@proteinjs/db';
|
|
3
|
+
import { routes, tables } from '@proteinjs/user';
|
|
4
|
+
import { Logger } from '@proteinjs/util';
|
|
5
|
+
import moment from 'moment';
|
|
6
|
+
import sha256 from 'crypto-js/sha256';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Route handler for executing a password reset.
|
|
10
|
+
*
|
|
11
|
+
* This function handles the process of resetting a user's password using a provided reset token.
|
|
12
|
+
* It verifies the token, checks its expiration, and updates the user's password if everything is valid.
|
|
13
|
+
*
|
|
14
|
+
* @bodyParam {string} token - The password reset token.
|
|
15
|
+
* @bodyParam {string} newPassword - The new password for the user.
|
|
16
|
+
*
|
|
17
|
+
* @throws {Error} If there's an issue with the database operations or if the token is invalid or expired.
|
|
18
|
+
*/
|
|
19
|
+
export const executePasswordReset: Route = {
|
|
20
|
+
path: routes.executePasswordReset.path,
|
|
21
|
+
method: routes.executePasswordReset.method,
|
|
22
|
+
onRequest: async (request, response): Promise<void> => {
|
|
23
|
+
const logger = new Logger('executePasswordReset');
|
|
24
|
+
const { token, newPassword } = request.body;
|
|
25
|
+
const db = getDbAsSystem();
|
|
26
|
+
|
|
27
|
+
// Find user with the given reset token
|
|
28
|
+
const user = await db.get(tables.User, { passwordResetToken: token });
|
|
29
|
+
if (!user) {
|
|
30
|
+
logger.info(`Invalid reset token used: ${token}`);
|
|
31
|
+
response.status(400).send({ error: 'Invalid or expired reset token' });
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Check if token is expired
|
|
36
|
+
const currentTime = moment();
|
|
37
|
+
const tokenExpiration = moment(user.passwordResetTokenExpiration);
|
|
38
|
+
if (currentTime.isAfter(tokenExpiration)) {
|
|
39
|
+
logger.info(`Expired reset token used for user: ${user.email}`);
|
|
40
|
+
response.status(400).send({ error: 'Reset token has expired' });
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Update user's password
|
|
45
|
+
const hashedPassword = sha256(newPassword).toString();
|
|
46
|
+
await db.update(tables.User, {
|
|
47
|
+
id: user.id,
|
|
48
|
+
password: hashedPassword,
|
|
49
|
+
passwordResetToken: null,
|
|
50
|
+
passwordResetTokenExpiration: null,
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
logger.info(`Password successfully reset for user: ${user.email}`);
|
|
54
|
+
response.send({ message: 'Password has been successfully reset' });
|
|
55
|
+
},
|
|
56
|
+
};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { Route } from '@proteinjs/server-api';
|
|
2
|
+
import { getDbAsSystem } from '@proteinjs/db';
|
|
3
|
+
import { routes, tables } from '@proteinjs/user';
|
|
4
|
+
import { Logger } from '@proteinjs/util';
|
|
5
|
+
import moment from 'moment';
|
|
6
|
+
import {
|
|
7
|
+
EmailSender,
|
|
8
|
+
getDefaultPasswordResetEmailConfigFactory as getDefaultConfigFactory,
|
|
9
|
+
} from '@proteinjs/email-server';
|
|
10
|
+
import { lib } from 'crypto-js';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Route for initiating a password reset process.
|
|
14
|
+
*
|
|
15
|
+
* This route handles the process of generating a password reset token,
|
|
16
|
+
* sending a reset email to the user, and storing the token and expiration of the token in the database.
|
|
17
|
+
*
|
|
18
|
+
* Requires an implementation of `DefaultPasswordResetEmailConfigFactory` to build the password reset email with.
|
|
19
|
+
*
|
|
20
|
+
* @bodyParam {string} email - The email address of the user requesting a password reset.
|
|
21
|
+
* @bodyParam {string} resetPath - The path to the password reset page in the client application.
|
|
22
|
+
* This will be combined with the generated token to create the reset link that is emailed to the user.
|
|
23
|
+
*
|
|
24
|
+
* @throws {Error} If there's an issue with sending the email or updating the database.
|
|
25
|
+
*/
|
|
26
|
+
export const initiatePasswordReset: Route = {
|
|
27
|
+
path: routes.initiatePasswordReset.path,
|
|
28
|
+
method: routes.initiatePasswordReset.method,
|
|
29
|
+
onRequest: async (request, response): Promise<void> => {
|
|
30
|
+
const logger = new Logger('initiatePasswordReset');
|
|
31
|
+
const { email, resetPath } = request.body;
|
|
32
|
+
const db = getDbAsSystem();
|
|
33
|
+
|
|
34
|
+
const genericResponse = { message: 'If an account with that email exists, we have sent a password reset link.' };
|
|
35
|
+
|
|
36
|
+
// Check if user exists
|
|
37
|
+
const user = await db.get(tables.User, { email });
|
|
38
|
+
if (!user) {
|
|
39
|
+
logger.info(`Password reset requested for non-existent user: ${email}`);
|
|
40
|
+
// Don't reveal that the user doesn't exist
|
|
41
|
+
response.send(genericResponse);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Check if there's an existing token and it's less than 5 minutes old
|
|
46
|
+
const currentTime = moment();
|
|
47
|
+
if (user.passwordResetToken && user.passwordResetTokenExpiration) {
|
|
48
|
+
const tokenAge = currentTime.diff(moment(user.passwordResetTokenExpiration), 'minutes');
|
|
49
|
+
if (tokenAge < -55) {
|
|
50
|
+
// Token is less than 5 minutes old
|
|
51
|
+
logger.info(`Password reset requested too soon for user: ${email}`);
|
|
52
|
+
response.send(genericResponse);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const emailSender = new EmailSender();
|
|
58
|
+
|
|
59
|
+
const defaultConfigFactory = getDefaultConfigFactory();
|
|
60
|
+
if (!defaultConfigFactory) {
|
|
61
|
+
throw new Error(
|
|
62
|
+
`Unable to find a @proteinjs/email-server/DefaultPasswordResetEmailConfigFactory implementation when initiating password reset.`
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Generate reset token
|
|
67
|
+
const passwordResetToken = lib.WordArray.random(32).toString();
|
|
68
|
+
const passwordResetTokenExpiration = moment().add(1, 'hour');
|
|
69
|
+
|
|
70
|
+
try {
|
|
71
|
+
const config = defaultConfigFactory.getConfig();
|
|
72
|
+
const { text, html } = config.getEmailContent(`${resetPath}?token=${passwordResetToken}`);
|
|
73
|
+
|
|
74
|
+
// Send email containing a reset link
|
|
75
|
+
await emailSender.sendEmail({
|
|
76
|
+
to: user.email,
|
|
77
|
+
subject: config.options?.subject || 'Reset Password',
|
|
78
|
+
text,
|
|
79
|
+
html,
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
// If email is sent successfully, save reset token to user record
|
|
83
|
+
await db.update(tables.User, { id: user.id, passwordResetToken, passwordResetTokenExpiration });
|
|
84
|
+
response.send(genericResponse);
|
|
85
|
+
} catch (error: any) {
|
|
86
|
+
logger.error(`Failed to send password reset email to: ${email}`, error);
|
|
87
|
+
response.status(500).send({ error: 'Failed to send password reset email. Please try again later.' });
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Route } from '@proteinjs/server-api';
|
|
2
|
+
import { getDbAsSystem } from '@proteinjs/db';
|
|
3
|
+
import { routes, tables } from '@proteinjs/user';
|
|
4
|
+
import { Logger } from '@proteinjs/util';
|
|
5
|
+
import moment from 'moment';
|
|
6
|
+
|
|
7
|
+
export const validateResetPasswordToken: Route = {
|
|
8
|
+
path: routes.validateResetToken.path,
|
|
9
|
+
method: routes.validateResetToken.method,
|
|
10
|
+
onRequest: async (request, response): Promise<void> => {
|
|
11
|
+
const logger = new Logger('validateResetToken');
|
|
12
|
+
const { token } = request.query;
|
|
13
|
+
const db = getDbAsSystem();
|
|
14
|
+
|
|
15
|
+
if (!token) {
|
|
16
|
+
response.status(400).send({ isValid: false, message: 'No token provided' });
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Find user with the given reset token
|
|
21
|
+
const user = await db.get(tables.User, { passwordResetToken: token });
|
|
22
|
+
if (!user) {
|
|
23
|
+
logger.info(`Invalid reset token used: ${token}`);
|
|
24
|
+
response.status(200).send({ isValid: false, message: 'Invalid token' });
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Check if token is expired
|
|
29
|
+
const currentTime = moment();
|
|
30
|
+
const tokenExpiration = moment(user.passwordResetTokenExpiration);
|
|
31
|
+
if (currentTime.isAfter(tokenExpiration)) {
|
|
32
|
+
logger.info(`Expired reset token used for user: ${user.email}`);
|
|
33
|
+
response.status(200).send({ isValid: false, message: 'Token has expired' });
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
response.status(200).send({ isValid: true });
|
|
38
|
+
},
|
|
39
|
+
};
|