@proteinjs/user-server 1.22.1 → 1.22.3

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.
Files changed (152) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/dist/generated/index.js +1 -1
  3. package/dist/generated/index.js.map +1 -1
  4. package/dist/index.d.ts +3 -0
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +9 -1
  7. package/dist/index.js.map +1 -1
  8. package/dist/src/authentication/PasswordHasher.d.ts +9 -0
  9. package/dist/src/authentication/PasswordHasher.d.ts.map +1 -1
  10. package/dist/src/authentication/PasswordHasher.js +25 -0
  11. package/dist/src/authentication/PasswordHasher.js.map +1 -1
  12. package/dist/src/authentication/SocketIOSessionWatcher.d.ts +5 -0
  13. package/dist/src/authentication/SocketIOSessionWatcher.d.ts.map +1 -1
  14. package/dist/src/authentication/SocketIOSessionWatcher.js +13 -2
  15. package/dist/src/authentication/SocketIOSessionWatcher.js.map +1 -1
  16. package/dist/src/authentication/UserStatusTableWatcher.d.ts.map +1 -1
  17. package/dist/src/authentication/UserStatusTableWatcher.js +2 -1
  18. package/dist/src/authentication/UserStatusTableWatcher.js.map +1 -1
  19. package/dist/src/authentication/authenticate.d.ts +15 -0
  20. package/dist/src/authentication/authenticate.d.ts.map +1 -1
  21. package/dist/src/authentication/authenticate.js +55 -20
  22. package/dist/src/authentication/authenticate.js.map +1 -1
  23. package/dist/src/authorization/userCache.d.ts.map +1 -1
  24. package/dist/src/authorization/userCache.js +3 -2
  25. package/dist/src/authorization/userCache.js.map +1 -1
  26. package/dist/src/routes/devLogin.d.ts.map +1 -1
  27. package/dist/src/routes/devLogin.js +29 -14
  28. package/dist/src/routes/devLogin.js.map +1 -1
  29. package/dist/src/routes/executePasswordReset.d.ts +4 -0
  30. package/dist/src/routes/executePasswordReset.d.ts.map +1 -1
  31. package/dist/src/routes/executePasswordReset.js +12 -4
  32. package/dist/src/routes/executePasswordReset.js.map +1 -1
  33. package/dist/src/routes/initiatePasswordReset.d.ts +7 -0
  34. package/dist/src/routes/initiatePasswordReset.d.ts.map +1 -1
  35. package/dist/src/routes/initiatePasswordReset.js +28 -10
  36. package/dist/src/routes/initiatePasswordReset.js.map +1 -1
  37. package/dist/src/routes/login.d.ts +8 -0
  38. package/dist/src/routes/login.d.ts.map +1 -1
  39. package/dist/src/routes/login.js +63 -22
  40. package/dist/src/routes/login.js.map +1 -1
  41. package/dist/src/routes/signup.d.ts.map +1 -1
  42. package/dist/src/routes/signup.js +5 -2
  43. package/dist/src/routes/signup.js.map +1 -1
  44. package/dist/src/routes/validateResetPasswordToken.d.ts.map +1 -1
  45. package/dist/src/routes/validateResetPasswordToken.js +5 -1
  46. package/dist/src/routes/validateResetPasswordToken.js.map +1 -1
  47. package/dist/src/services/MachineCredentials.d.ts +10 -1
  48. package/dist/src/services/MachineCredentials.d.ts.map +1 -1
  49. package/dist/src/services/MachineCredentials.js +46 -15
  50. package/dist/src/services/MachineCredentials.js.map +1 -1
  51. package/dist/src/services/Roles.d.ts.map +1 -1
  52. package/dist/src/services/Roles.js +6 -2
  53. package/dist/src/services/Roles.js.map +1 -1
  54. package/dist/src/services/Signup.d.ts +5 -0
  55. package/dist/src/services/Signup.d.ts.map +1 -1
  56. package/dist/src/services/Signup.js +28 -6
  57. package/dist/src/services/Signup.js.map +1 -1
  58. package/dist/src/throttle/ClientAddress.d.ts +35 -0
  59. package/dist/src/throttle/ClientAddress.d.ts.map +1 -0
  60. package/dist/src/throttle/ClientAddress.js +48 -0
  61. package/dist/src/throttle/ClientAddress.js.map +1 -0
  62. package/dist/src/throttle/PasswordResetThrottle.d.ts +39 -0
  63. package/dist/src/throttle/PasswordResetThrottle.d.ts.map +1 -0
  64. package/dist/src/throttle/PasswordResetThrottle.js +59 -0
  65. package/dist/src/throttle/PasswordResetThrottle.js.map +1 -0
  66. package/dist/src/throttle/RequestDigests.d.ts +42 -0
  67. package/dist/src/throttle/RequestDigests.d.ts.map +1 -0
  68. package/dist/src/throttle/RequestDigests.js +96 -0
  69. package/dist/src/throttle/RequestDigests.js.map +1 -0
  70. package/dist/src/throttle/SignInThrottle.d.ts +67 -0
  71. package/dist/src/throttle/SignInThrottle.d.ts.map +1 -0
  72. package/dist/src/throttle/SignInThrottle.js +91 -0
  73. package/dist/src/throttle/SignInThrottle.js.map +1 -0
  74. package/dist/src/throttle/SlidingWindow.d.ts +51 -0
  75. package/dist/src/throttle/SlidingWindow.d.ts.map +1 -0
  76. package/dist/src/throttle/SlidingWindow.js +85 -0
  77. package/dist/src/throttle/SlidingWindow.js.map +1 -0
  78. package/dist/test/ClientAddress.test.d.ts +2 -0
  79. package/dist/test/ClientAddress.test.d.ts.map +1 -0
  80. package/dist/test/ClientAddress.test.js +51 -0
  81. package/dist/test/ClientAddress.test.js.map +1 -0
  82. package/dist/test/DevLogin.test.js +68 -0
  83. package/dist/test/DevLogin.test.js.map +1 -1
  84. package/dist/test/InitiatePasswordReset.test.js +373 -5
  85. package/dist/test/InitiatePasswordReset.test.js.map +1 -1
  86. package/dist/test/LogCapture.d.ts +10 -0
  87. package/dist/test/LogCapture.d.ts.map +1 -1
  88. package/dist/test/LogCapture.js +19 -0
  89. package/dist/test/LogCapture.js.map +1 -1
  90. package/dist/test/LogCapture.test.d.ts +2 -0
  91. package/dist/test/LogCapture.test.d.ts.map +1 -0
  92. package/dist/test/LogCapture.test.js +86 -0
  93. package/dist/test/LogCapture.test.js.map +1 -0
  94. package/dist/test/LoginThrottle.integration.test.d.ts +2 -0
  95. package/dist/test/LoginThrottle.integration.test.d.ts.map +1 -0
  96. package/dist/test/LoginThrottle.integration.test.js +616 -0
  97. package/dist/test/LoginThrottle.integration.test.js.map +1 -0
  98. package/dist/test/MachineAccounts.integration.test.js +156 -28
  99. package/dist/test/MachineAccounts.integration.test.js.map +1 -1
  100. package/dist/test/NoAddressesInLogs.integration.test.d.ts +2 -0
  101. package/dist/test/NoAddressesInLogs.integration.test.d.ts.map +1 -0
  102. package/dist/test/NoAddressesInLogs.integration.test.js +717 -0
  103. package/dist/test/NoAddressesInLogs.integration.test.js.map +1 -0
  104. package/dist/test/RequestDigests.test.d.ts +2 -0
  105. package/dist/test/RequestDigests.test.d.ts.map +1 -0
  106. package/dist/test/RequestDigests.test.js +73 -0
  107. package/dist/test/RequestDigests.test.js.map +1 -0
  108. package/dist/test/SignupRoute.test.js +80 -1
  109. package/dist/test/SignupRoute.test.js.map +1 -1
  110. package/dist/test/SlidingWindow.test.d.ts +2 -0
  111. package/dist/test/SlidingWindow.test.d.ts.map +1 -0
  112. package/dist/test/SlidingWindow.test.js +72 -0
  113. package/dist/test/SlidingWindow.test.js.map +1 -0
  114. package/dist/test/SocketIOSessionWatcher.test.d.ts +2 -0
  115. package/dist/test/SocketIOSessionWatcher.test.d.ts.map +1 -0
  116. package/dist/test/SocketIOSessionWatcher.test.js +144 -0
  117. package/dist/test/SocketIOSessionWatcher.test.js.map +1 -0
  118. package/generated/index.ts +1 -1
  119. package/index.ts +5 -0
  120. package/package.json +6 -5
  121. package/src/authentication/PasswordHasher.ts +18 -1
  122. package/src/authentication/SocketIOSessionWatcher.ts +13 -1
  123. package/src/authentication/UserStatusTableWatcher.ts +2 -1
  124. package/src/authentication/authenticate.ts +36 -9
  125. package/src/authorization/userCache.ts +3 -2
  126. package/src/routes/devLogin.ts +22 -10
  127. package/src/routes/executePasswordReset.ts +11 -3
  128. package/src/routes/initiatePasswordReset.ts +29 -11
  129. package/src/routes/login.ts +39 -8
  130. package/src/routes/signup.ts +5 -2
  131. package/src/routes/validateResetPasswordToken.ts +5 -1
  132. package/src/services/MachineCredentials.ts +44 -9
  133. package/src/services/Roles.ts +6 -2
  134. package/src/services/Signup.ts +30 -4
  135. package/src/throttle/ClientAddress.ts +47 -0
  136. package/src/throttle/PasswordResetThrottle.ts +62 -0
  137. package/src/throttle/RequestDigests.ts +97 -0
  138. package/src/throttle/SignInThrottle.ts +98 -0
  139. package/src/throttle/SlidingWindow.ts +90 -0
  140. package/test/ClientAddress.test.ts +54 -0
  141. package/test/DevLogin.test.ts +35 -1
  142. package/test/InitiatePasswordReset.test.ts +212 -6
  143. package/test/LogCapture.test.ts +29 -0
  144. package/test/LogCapture.ts +16 -0
  145. package/test/LoginThrottle.integration.test.ts +339 -0
  146. package/test/MachineAccounts.integration.test.ts +97 -22
  147. package/test/NoAddressesInLogs.integration.test.ts +409 -0
  148. package/test/RequestDigests.test.ts +81 -0
  149. package/test/SignupRoute.test.ts +54 -1
  150. package/test/SlidingWindow.test.ts +85 -0
  151. package/test/SocketIOSessionWatcher.test.ts +86 -0
  152. package/test/setup.js +2 -0
@@ -1 +1 @@
1
- {"version":3,"file":"PasswordHasher.d.ts","sourceRoot":"","sources":["../../../src/authentication/PasswordHasher.ts"],"names":[],"mappings":"AAGA;;;;;GAKG;AACH,MAAM,MAAM,gBAAgB,GAAG,OAAO,GAAG,SAAS,CAAC;AAEnD;;;;;;;;;;;;GAYG;AACH,qBAAa,cAAc;IACzB;;;;;OAKG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAKpC;IAEF,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAgB;IAEjD,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,GAAE,gBAA0B,GAAG,OAAO,CAAC,MAAM,CAAC;IAQ/E;;;OAGG;IACG,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAYvF;;;OAGG;IACH,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,GAAE,gBAA0B,GAAG,OAAO;IAQ1E,uGAAuG;IACvG,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,iBAAiB;CAK1B"}
1
+ {"version":3,"file":"PasswordHasher.d.ts","sourceRoot":"","sources":["../../../src/authentication/PasswordHasher.ts"],"names":[],"mappings":"AAGA;;;;;GAKG;AACH,MAAM,MAAM,gBAAgB,GAAG,OAAO,GAAG,SAAS,CAAC;AAEnD;;;;;;;;;;;;GAYG;AACH,qBAAa,cAAc;IACzB;;;;;OAKG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAKpC;IAEF,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAgB;IAEvD,iIAAiI;IACjI,OAAO,CAAC,MAAM,CAAC,OAAO,CAA8B;IAE9C,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,GAAE,gBAA0B,GAAG,OAAO,CAAC,MAAM,CAAC;IAQ/E;;;OAGG;IACG,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAYvF;;;;;OAKG;IACG,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;IAQ5D;;;OAGG;IACH,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,GAAE,gBAA0B,GAAG,OAAO;IAQ1E,uGAAuG;IACvG,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,iBAAiB;CAK1B"}
@@ -113,6 +113,31 @@ var PasswordHasher = /** @class */ (function () {
113
113
  });
114
114
  });
115
115
  };
116
+ /**
117
+ * Spends what verifying a human credential spends, and matches nothing: the refusal for an
118
+ * address with no account pays the same argon2 verification a wrong password pays, so how
119
+ * long a refusal takes says nothing about whether the address has an account. (The stand-in
120
+ * hash is minted on the first call; that one call also pays a hash.)
121
+ */
122
+ PasswordHasher.prototype.verifyAgainstNothing = function (password) {
123
+ return __awaiter(this, void 0, void 0, function () {
124
+ var _a, _b;
125
+ return __generator(this, function (_c) {
126
+ switch (_c.label) {
127
+ case 0:
128
+ if (!PasswordHasher.standIn) {
129
+ PasswordHasher.standIn = argon2.hash((0, crypto_1.randomBytes)(32).toString('hex'), PasswordHasher.ARGON2_OPTIONS);
130
+ }
131
+ _b = (_a = argon2).verify;
132
+ return [4 /*yield*/, PasswordHasher.standIn];
133
+ case 1: return [4 /*yield*/, _b.apply(_a, [_c.sent(), password])];
134
+ case 2:
135
+ _c.sent();
136
+ return [2 /*return*/, false];
137
+ }
138
+ });
139
+ });
140
+ };
116
141
  /**
117
142
  * True when a verified credential should be re-written in the current format: legacy sha256
118
143
  * under `human` mode. Machine rows never rehash — sha256 IS their current format.
@@ -1 +1 @@
1
- {"version":3,"file":"PasswordHasher.js","sourceRoot":"","sources":["../../../src/authentication/PasswordHasher.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,iCAAqD;AACrD,6CAAiC;AAUjC;;;;;;;;;;;;GAYG;AACH;IAAA;IA8DA,CAAC;IA9CO,6BAAI,GAAV,UAAW,QAAgB,EAAE,IAAgC;QAAhC,qBAAA,EAAA,cAAgC;;;;;wBAC3D,IAAI,IAAI,KAAK,SAAS,EAAE;4BACtB,sBAAO,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAC;yBACjC;wBAEM,qBAAM,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,cAAc,CAAC,cAAc,CAAC,EAAA;4BAAjE,sBAAO,SAA0D,EAAC;;;;KACnE;IAED;;;OAGG;IACG,+BAAM,GAAZ,UAAa,UAAqC,EAAE,QAAgB;;;;;wBAClE,IAAI,CAAC,UAAU,EAAE;4BACf,sBAAO,KAAK,EAAC;yBACd;6BAEG,UAAU,CAAC,UAAU,CAAC,cAAc,CAAC,eAAe,CAAC,EAArD,wBAAqD;wBAChD,qBAAM,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,QAAQ,CAAC,EAAA;4BAAhD,sBAAO,SAAyC,EAAC;4BAGnD,sBAAO,IAAI,CAAC,iBAAiB,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,EAAC;;;;KACrE;IAED;;;OAGG;IACH,oCAAW,GAAX,UAAY,UAAkB,EAAE,IAAgC;QAAhC,qBAAA,EAAA,cAAgC;QAC9D,IAAI,IAAI,KAAK,SAAS,EAAE;YACtB,OAAO,KAAK,CAAC;SACd;QAED,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC,cAAc,CAAC,eAAe,CAAC,CAAC;IAChE,CAAC;IAED,uGAAuG;IAC/F,kCAAS,GAAjB,UAAkB,KAAa;QAC7B,OAAO,IAAA,mBAAU,EAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAClE,CAAC;IAEO,0CAAiB,GAAzB,UAA0B,MAAc,EAAE,SAAiB;QACzD,IAAM,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAChD,IAAM,cAAc,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;QACtD,OAAO,WAAW,CAAC,MAAM,KAAK,cAAc,CAAC,MAAM,IAAI,IAAA,wBAAe,EAAC,WAAW,EAAE,cAAc,CAAC,CAAC;IACtG,CAAC;IA5DD;;;;;OAKG;IACqB,6BAAc,GAAuB;QAC3D,IAAI,EAAE,MAAM,CAAC,QAAQ;QACrB,UAAU,EAAE,KAAK;QACjB,QAAQ,EAAE,CAAC;QACX,WAAW,EAAE,CAAC;KACf,CAAC;IAEsB,8BAAe,GAAG,YAAY,CAAC;IAgDzD,qBAAC;CAAA,AA9DD,IA8DC;AA9DY,wCAAc"}
1
+ {"version":3,"file":"PasswordHasher.js","sourceRoot":"","sources":["../../../src/authentication/PasswordHasher.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,iCAAkE;AAClE,6CAAiC;AAUjC;;;;;;;;;;;;GAYG;AACH;IAAA;IA+EA,CAAC;IA5DO,6BAAI,GAAV,UAAW,QAAgB,EAAE,IAAgC;QAAhC,qBAAA,EAAA,cAAgC;;;;;wBAC3D,IAAI,IAAI,KAAK,SAAS,EAAE;4BACtB,sBAAO,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAC;yBACjC;wBAEM,qBAAM,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,cAAc,CAAC,cAAc,CAAC,EAAA;4BAAjE,sBAAO,SAA0D,EAAC;;;;KACnE;IAED;;;OAGG;IACG,+BAAM,GAAZ,UAAa,UAAqC,EAAE,QAAgB;;;;;wBAClE,IAAI,CAAC,UAAU,EAAE;4BACf,sBAAO,KAAK,EAAC;yBACd;6BAEG,UAAU,CAAC,UAAU,CAAC,cAAc,CAAC,eAAe,CAAC,EAArD,wBAAqD;wBAChD,qBAAM,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,QAAQ,CAAC,EAAA;4BAAhD,sBAAO,SAAyC,EAAC;4BAGnD,sBAAO,IAAI,CAAC,iBAAiB,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,EAAC;;;;KACrE;IAED;;;;;OAKG;IACG,6CAAoB,GAA1B,UAA2B,QAAgB;;;;;;wBACzC,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE;4BAC3B,cAAc,CAAC,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,IAAA,oBAAW,EAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,cAAc,CAAC,cAAc,CAAC,CAAC;yBACtG;wBACK,KAAA,CAAA,KAAA,MAAM,CAAA,CAAC,MAAM,CAAA;wBAAC,qBAAM,cAAc,CAAC,OAAO,EAAA;4BAAhD,qBAAM,cAAc,SAA4B,EAAE,QAAQ,EAAC,EAAA;;wBAA3D,SAA2D,CAAC;wBAC5D,sBAAO,KAAK,EAAC;;;;KACd;IAED;;;OAGG;IACH,oCAAW,GAAX,UAAY,UAAkB,EAAE,IAAgC;QAAhC,qBAAA,EAAA,cAAgC;QAC9D,IAAI,IAAI,KAAK,SAAS,EAAE;YACtB,OAAO,KAAK,CAAC;SACd;QAED,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC,cAAc,CAAC,eAAe,CAAC,CAAC;IAChE,CAAC;IAED,uGAAuG;IAC/F,kCAAS,GAAjB,UAAkB,KAAa;QAC7B,OAAO,IAAA,mBAAU,EAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAClE,CAAC;IAEO,0CAAiB,GAAzB,UAA0B,MAAc,EAAE,SAAiB;QACzD,IAAM,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAChD,IAAM,cAAc,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;QACtD,OAAO,WAAW,CAAC,MAAM,KAAK,cAAc,CAAC,MAAM,IAAI,IAAA,wBAAe,EAAC,WAAW,EAAE,cAAc,CAAC,CAAC;IACtG,CAAC;IA7ED;;;;;OAKG;IACqB,6BAAc,GAAuB;QAC3D,IAAI,EAAE,MAAM,CAAC,QAAQ;QACrB,UAAU,EAAE,KAAK;QACjB,QAAQ,EAAE,CAAC;QACX,WAAW,EAAE,CAAC;KACf,CAAC;IAEsB,8BAAe,GAAG,YAAY,CAAC;IAiEzD,qBAAC;CAAA,AA/ED,IA+EC;AA/EY,wCAAc"}
@@ -3,6 +3,11 @@ import { Session } from '@proteinjs/user';
3
3
  /**
4
4
  * Handles Socket.IO session cleanup (such as disconnecting sockets)
5
5
  * when sessions are deleted.
6
+ *
7
+ * A deletion is not always made by a running server: a boot's source-record sync — and a
8
+ * migration Job, which never starts one — deactivates a withdrawn machine account and deletes its
9
+ * sessions before any socket server exists. Then no socket can be open, and there is nothing to
10
+ * close.
6
11
  */
7
12
  export declare class SocketIOSessionWatcher implements TableWatcher<Session> {
8
13
  name(): string;
@@ -1 +1 @@
1
- {"version":3,"file":"SocketIOSessionWatcher.d.ts","sourceRoot":"","sources":["../../../src/authentication/SocketIOSessionWatcher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAClE,OAAO,EAAE,OAAO,EAAgB,MAAM,iBAAiB,CAAC;AAGxD;;;GAGG;AACH,qBAAa,sBAAuB,YAAW,YAAY,CAAC,OAAO,CAAC;IAClE,IAAI,IAAI,MAAM;IAId,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC;IAIjB,WAAW,CAAC,CAAC,SAAS,OAAO,EACjC,iBAAiB,EAAE,MAAM,EACzB,cAAc,EAAE,CAAC,EAAE,EACnB,SAAS,EAAE,YAAY,CAAC,CAAC,CAAC,EAC1B,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC,GACxB,OAAO,CAAC,IAAI,CAAC;CAIjB"}
1
+ {"version":3,"file":"SocketIOSessionWatcher.d.ts","sourceRoot":"","sources":["../../../src/authentication/SocketIOSessionWatcher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAClE,OAAO,EAAE,OAAO,EAAgB,MAAM,iBAAiB,CAAC;AAGxD;;;;;;;;GAQG;AACH,qBAAa,sBAAuB,YAAW,YAAY,CAAC,OAAO,CAAC;IAClE,IAAI,IAAI,MAAM;IAId,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC;IAIjB,WAAW,CAAC,CAAC,SAAS,OAAO,EACjC,iBAAiB,EAAE,MAAM,EACzB,cAAc,EAAE,CAAC,EAAE,EACnB,SAAS,EAAE,YAAY,CAAC,CAAC,CAAC,EAC1B,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC,GACxB,OAAO,CAAC,IAAI,CAAC;CAWjB"}
@@ -42,6 +42,11 @@ var server_1 = require("@proteinjs/server");
42
42
  /**
43
43
  * Handles Socket.IO session cleanup (such as disconnecting sockets)
44
44
  * when sessions are deleted.
45
+ *
46
+ * A deletion is not always made by a running server: a boot's source-record sync — and a
47
+ * migration Job, which never starts one — deactivates a withdrawn machine account and deletes its
48
+ * sessions before any socket server exists. Then no socket can be open, and there is nothing to
49
+ * close.
45
50
  */
46
51
  var SocketIOSessionWatcher = /** @class */ (function () {
47
52
  function SocketIOSessionWatcher() {
@@ -54,10 +59,16 @@ var SocketIOSessionWatcher = /** @class */ (function () {
54
59
  };
55
60
  SocketIOSessionWatcher.prototype.afterDelete = function (recordDeleteCount, deletedRecords, initialQb, deleteQb) {
56
61
  return __awaiter(this, void 0, void 0, function () {
57
- var deletedSessionIds;
62
+ var socketIOServer, deletedSessionIds;
58
63
  return __generator(this, function (_a) {
64
+ socketIOServer = server_1.SocketIOServerRepo.getSocketIOServerIfExists();
59
65
  deletedSessionIds = deletedRecords.map(function (deletedRecord) { return deletedRecord.sessionId; });
60
- server_1.SocketIOServerRepo.getSocketIOServer().in(deletedSessionIds).disconnectSockets(true);
66
+ // No rooms is never sent: socket.io applies an operation with an empty room list to EVERY
67
+ // socket on the namespace.
68
+ if (!socketIOServer || deletedSessionIds.length === 0) {
69
+ return [2 /*return*/];
70
+ }
71
+ socketIOServer.in(deletedSessionIds).disconnectSockets(true);
61
72
  return [2 /*return*/];
62
73
  });
63
74
  });
@@ -1 +1 @@
1
- {"version":3,"file":"SocketIOSessionWatcher.js","sourceRoot":"","sources":["../../../src/authentication/SocketIOSessionWatcher.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,wCAAwD;AACxD,4CAAuD;AAEvD;;;GAGG;AACH;IAAA;IAkBA,CAAC;IAjBC,qCAAI,GAAJ;QACE,OAAO,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;IAC/B,CAAC;IAED,sCAAK,GAAL;QACE,OAAO,IAAI,mBAAY,EAAE,CAAC;IAC5B,CAAC;IAEK,4CAAW,GAAjB,UACE,iBAAyB,EACzB,cAAmB,EACnB,SAA0B,EAC1B,QAAyB;;;;gBAEnB,iBAAiB,GAAG,cAAc,CAAC,GAAG,CAAC,UAAC,aAAa,IAAK,OAAA,aAAa,CAAC,SAAS,EAAvB,CAAuB,CAAC,CAAC;gBACzF,2BAAkB,CAAC,iBAAiB,EAAE,CAAC,EAAE,CAAC,iBAAiB,CAAC,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;;;;KACtF;IACH,6BAAC;AAAD,CAAC,AAlBD,IAkBC;AAlBY,wDAAsB"}
1
+ {"version":3,"file":"SocketIOSessionWatcher.js","sourceRoot":"","sources":["../../../src/authentication/SocketIOSessionWatcher.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,wCAAwD;AACxD,4CAAuD;AAEvD;;;;;;;;GAQG;AACH;IAAA;IAyBA,CAAC;IAxBC,qCAAI,GAAJ;QACE,OAAO,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;IAC/B,CAAC;IAED,sCAAK,GAAL;QACE,OAAO,IAAI,mBAAY,EAAE,CAAC;IAC5B,CAAC;IAEK,4CAAW,GAAjB,UACE,iBAAyB,EACzB,cAAmB,EACnB,SAA0B,EAC1B,QAAyB;;;;gBAEnB,cAAc,GAAG,2BAAkB,CAAC,yBAAyB,EAAE,CAAC;gBAChE,iBAAiB,GAAG,cAAc,CAAC,GAAG,CAAC,UAAC,aAAa,IAAK,OAAA,aAAa,CAAC,SAAS,EAAvB,CAAuB,CAAC,CAAC;gBACzF,0FAA0F;gBAC1F,2BAA2B;gBAC3B,IAAI,CAAC,cAAc,IAAI,iBAAiB,CAAC,MAAM,KAAK,CAAC,EAAE;oBACrD,sBAAO;iBACR;gBAED,cAAc,CAAC,EAAE,CAAC,iBAAiB,CAAC,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;;;;KAC9D;IACH,6BAAC;AAAD,CAAC,AAzBD,IAyBC;AAzBY,wDAAsB"}
@@ -1 +1 @@
1
- {"version":3,"file":"UserStatusTableWatcher.d.ts","sourceRoot":"","sources":["../../../src/authentication/UserStatusTableWatcher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,EAAiB,MAAM,eAAe,CAAC;AACjF,OAAO,EAAE,IAAI,EAAU,MAAM,iBAAiB,CAAC;AAG/C;;;;;;;;;GASG;AACH,qBAAa,sBAAuB,YAAW,YAAY,CAAC,IAAI,CAAC;IAC/D,OAAO,CAAC,MAAM,CAA+C;IAE7D,IAAI,IAAI,MAAM;IAId,KAAK,IAAI,KAAK,CAAC,IAAI,CAAC;IAId,WAAW,CAAC,CAAC,SAAS,IAAI,EAAE,iBAAiB,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;CA8BrH"}
1
+ {"version":3,"file":"UserStatusTableWatcher.d.ts","sourceRoot":"","sources":["../../../src/authentication/UserStatusTableWatcher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,EAAiB,MAAM,eAAe,CAAC;AACjF,OAAO,EAAE,IAAI,EAAU,MAAM,iBAAiB,CAAC;AAI/C;;;;;;;;;GASG;AACH,qBAAa,sBAAuB,YAAW,YAAY,CAAC,IAAI,CAAC;IAC/D,OAAO,CAAC,MAAM,CAA+C;IAE7D,IAAI,IAAI,MAAM;IAId,KAAK,IAAI,KAAK,CAAC,IAAI,CAAC;IAId,WAAW,CAAC,CAAC,SAAS,IAAI,EAAE,iBAAiB,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;CA8BrH"}
@@ -40,6 +40,7 @@ exports.UserStatusTableWatcher = void 0;
40
40
  var db_1 = require("@proteinjs/db");
41
41
  var user_1 = require("@proteinjs/user");
42
42
  var logger_1 = require("@proteinjs/logger");
43
+ var util_node_1 = require("@proteinjs/util-node");
43
44
  /**
44
45
  * The one owner of "deactivated ⇒ sessions die": any user-table update writing
45
46
  * `status: 'deactivated'` deletes the account's session rows (SocketIOSessionWatcher kicks the
@@ -95,7 +96,7 @@ var UserStatusTableWatcher = /** @class */ (function () {
95
96
  if (deletedSessions > 0) {
96
97
  this.logger.info({
97
98
  message: "Deactivation killed sessions",
98
- obj: { email: user.email, sessions: deletedSessions },
99
+ obj: { account: new util_node_1.RequestDigests().account(user.email), sessions: deletedSessions },
99
100
  });
100
101
  }
101
102
  return [2 /*return*/];
@@ -1 +1 @@
1
- {"version":3,"file":"UserStatusTableWatcher.js","sourceRoot":"","sources":["../../../src/authentication/UserStatusTableWatcher.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,oCAAiF;AACjF,wCAA+C;AAC/C,4CAA2C;AAE3C;;;;;;;;;GASG;AACH;IAAA;QACU,WAAM,GAAG,IAAI,eAAM,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC;IAwC/D,CAAC;IAtCC,qCAAI,GAAJ;QACE,OAAO,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;IAC/B,CAAC;IAED,sCAAK,GAAL;QACE,OAAO,aAAM,CAAC,IAAI,CAAC;IACrB,CAAC;IAEK,4CAAW,GAAjB,UAAkC,iBAAyB,EAAE,MAAkB,EAAE,EAAmB;;;;;;;wBAClG,IAAI,MAAM,CAAC,MAAM,KAAK,aAAa,IAAI,iBAAiB,KAAK,CAAC,EAAE;4BAC9D,sBAAO;yBACR;wBAED,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE;4BACd,yFAAyF;4BACzF,sFAAsF;4BACtF,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;gCAChB,OAAO,EAAE,kIAA6H;6BACvI,CAAC,CAAC;4BACH,sBAAO;yBACR;wBAEK,EAAE,GAAG,IAAA,kBAAa,GAAE,CAAC;wBAC3B,qBAAM,EAAE,CAAC,cAAc,CAAC;;;;gDACT,qBAAM,EAAE,CAAC,GAAG,CAAC,aAAM,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,EAAA;;4CAAnD,IAAI,GAAG,SAA4C;4CACzD,IAAI,CAAC,IAAI,EAAE;gDACT,sBAAO,CAAC,mEAAmE;6CAC5E;4CAEuB,qBAAM,EAAE,CAAC,MAAM,CAAC,aAAM,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,EAAA;;4CAA5E,eAAe,GAAG,SAA0D;4CAClF,IAAI,eAAe,GAAG,CAAC,EAAE;gDACvB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;oDACf,OAAO,EAAE,8BAA8B;oDACvC,GAAG,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,QAAQ,EAAE,eAAe,EAAE;iDACtD,CAAC,CAAC;6CACJ;;;;iCACF,CAAC,EAAA;;wBAbF,SAaE,CAAC;;;;;KACJ;IACH,6BAAC;AAAD,CAAC,AAzCD,IAyCC;AAzCY,wDAAsB"}
1
+ {"version":3,"file":"UserStatusTableWatcher.js","sourceRoot":"","sources":["../../../src/authentication/UserStatusTableWatcher.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,oCAAiF;AACjF,wCAA+C;AAC/C,4CAA2C;AAC3C,kDAAsD;AAEtD;;;;;;;;;GASG;AACH;IAAA;QACU,WAAM,GAAG,IAAI,eAAM,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC;IAwC/D,CAAC;IAtCC,qCAAI,GAAJ;QACE,OAAO,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;IAC/B,CAAC;IAED,sCAAK,GAAL;QACE,OAAO,aAAM,CAAC,IAAI,CAAC;IACrB,CAAC;IAEK,4CAAW,GAAjB,UAAkC,iBAAyB,EAAE,MAAkB,EAAE,EAAmB;;;;;;;wBAClG,IAAI,MAAM,CAAC,MAAM,KAAK,aAAa,IAAI,iBAAiB,KAAK,CAAC,EAAE;4BAC9D,sBAAO;yBACR;wBAED,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE;4BACd,yFAAyF;4BACzF,sFAAsF;4BACtF,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;gCAChB,OAAO,EAAE,kIAA6H;6BACvI,CAAC,CAAC;4BACH,sBAAO;yBACR;wBAEK,EAAE,GAAG,IAAA,kBAAa,GAAE,CAAC;wBAC3B,qBAAM,EAAE,CAAC,cAAc,CAAC;;;;gDACT,qBAAM,EAAE,CAAC,GAAG,CAAC,aAAM,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,EAAA;;4CAAnD,IAAI,GAAG,SAA4C;4CACzD,IAAI,CAAC,IAAI,EAAE;gDACT,sBAAO,CAAC,mEAAmE;6CAC5E;4CAEuB,qBAAM,EAAE,CAAC,MAAM,CAAC,aAAM,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,EAAA;;4CAA5E,eAAe,GAAG,SAA0D;4CAClF,IAAI,eAAe,GAAG,CAAC,EAAE;gDACvB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;oDACf,OAAO,EAAE,8BAA8B;oDACvC,GAAG,EAAE,EAAE,OAAO,EAAE,IAAI,0BAAc,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,QAAQ,EAAE,eAAe,EAAE;iDACtF,CAAC,CAAC;6CACJ;;;;iCACF,CAAC,EAAA;;wBAbF,SAaE,CAAC;;;;;KACJ;IACH,6BAAC;AAAD,CAAC,AAzCD,IAyCC;AAzCY,wDAAsB"}
@@ -1,6 +1,21 @@
1
+ import { User } from '@proteinjs/user';
1
2
  export declare function createAuthentication(defaultAdminCredentials?: {
2
3
  username: string;
3
4
  password: string;
4
5
  }): typeof authenticate;
5
6
  export declare function authenticate(email: string, password: string): Promise<true | string>;
7
+ /**
8
+ * Looks the account up and verifies the password — the cost every refusal pays, whether or not
9
+ * the address has an account: with none, the password is verified against a stand-in of the
10
+ * same cost (`PasswordHasher.verifyAgainstNothing`), so a refusal's timing says nothing about
11
+ * the address; a human row still in the legacy sha256 format (verified in microseconds) pays the
12
+ * stand-in too, so a refusal's timing says nothing about whether the account has signed in since
13
+ * the format changed either. The login door also runs it on a throttled try and discards the
14
+ * verdict, so a throttled answer takes as long as a refused password. No side effects (no
15
+ * rehash, no log).
16
+ */
17
+ export declare function checkPassword(email: string, password: string): Promise<{
18
+ user?: User;
19
+ matches: boolean;
20
+ }>;
6
21
  //# sourceMappingURL=authenticate.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"authenticate.d.ts","sourceRoot":"","sources":["../../../src/authentication/authenticate.ts"],"names":[],"mappings":"AAMA,wBAAgB,oBAAoB,CAAC,uBAAuB,CAAC,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,uBAMpG;AAED,wBAAsB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,MAAM,CAAC,CA8C1F"}
1
+ {"version":3,"file":"authenticate.d.ts","sourceRoot":"","sources":["../../../src/authentication/authenticate.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAU,MAAM,iBAAiB,CAAC;AAM/C,wBAAgB,oBAAoB,CAAC,uBAAuB,CAAC,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,uBAMpG;AAED,wBAAsB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,MAAM,CAAC,CA8C1F;AAED;;;;;;;;;GASG;AACH,wBAAsB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,IAAI,CAAC,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC,CAc/G"}
@@ -36,10 +36,11 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
36
36
  }
37
37
  };
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.authenticate = exports.createAuthentication = void 0;
39
+ exports.checkPassword = exports.authenticate = exports.createAuthentication = void 0;
40
40
  var db_1 = require("@proteinjs/db");
41
41
  var user_1 = require("@proteinjs/user");
42
42
  var logger_1 = require("@proteinjs/logger");
43
+ var util_node_1 = require("@proteinjs/util-node");
43
44
  var DefaultAdminCredentials_1 = require("./DefaultAdminCredentials");
44
45
  var PasswordHasher_1 = require("./PasswordHasher");
45
46
  function createAuthentication(defaultAdminCredentials) {
@@ -51,7 +52,7 @@ function createAuthentication(defaultAdminCredentials) {
51
52
  exports.createAuthentication = createAuthentication;
52
53
  function authenticate(email, password) {
53
54
  return __awaiter(this, void 0, void 0, function () {
54
- var logger, defaultAdminCredentials, db, user, hasher, _a, mode, _b, _c, _d;
55
+ var logger, defaultAdminCredentials, _a, user, matches, db, hasher, mode, _b, _c, _d;
55
56
  var _e;
56
57
  return __generator(this, function (_f) {
57
58
  switch (_f.label) {
@@ -64,32 +65,25 @@ function authenticate(email, password) {
64
65
  logger.info({ message: 'Authenitcated default admin user' });
65
66
  return [2 /*return*/, true];
66
67
  }
67
- db = (0, db_1.getDbAsSystem)();
68
- return [4 /*yield*/, db.get(user_1.tables.User, { email: email.toLowerCase() })];
68
+ return [4 /*yield*/, checkPassword(email, password)];
69
69
  case 1:
70
- user = _f.sent();
71
- hasher = new PasswordHasher_1.PasswordHasher();
72
- _a = !user;
73
- if (_a) return [3 /*break*/, 3];
74
- return [4 /*yield*/, hasher.verify(user.password, password)];
75
- case 2:
76
- _a = !(_f.sent());
77
- _f.label = 3;
78
- case 3:
79
- if (_a) {
70
+ _a = _f.sent(), user = _a.user, matches = _a.matches;
71
+ if (!user || !matches) {
80
72
  return [2 /*return*/, 'User name or password incorrect'];
81
73
  }
74
+ db = (0, db_1.getDbAsSystem)();
75
+ hasher = new PasswordHasher_1.PasswordHasher();
82
76
  mode = user.isLoadedFromSource === true ? 'machine' : 'human';
83
- if (!hasher.needsRehash(user.password, mode)) return [3 /*break*/, 6];
77
+ if (!hasher.needsRehash(user.password, mode)) return [3 /*break*/, 4];
84
78
  _c = (_b = db).update;
85
79
  _d = [user_1.tables.User];
86
80
  _e = { id: user.id };
87
81
  return [4 /*yield*/, hasher.hash(password)];
88
- case 4: return [4 /*yield*/, _c.apply(_b, _d.concat([(_e.password = _f.sent(), _e)]))];
89
- case 5:
82
+ case 2: return [4 /*yield*/, _c.apply(_b, _d.concat([(_e.password = _f.sent(), _e)]))];
83
+ case 3:
90
84
  _f.sent();
91
- _f.label = 6;
92
- case 6:
85
+ _f.label = 4;
86
+ case 4:
93
87
  // Deactivated accounts are refused a new session even with correct credentials; the session
94
88
  // side of the same gate lives in userCache (deactivated sessions resolve as guest).
95
89
  if (user.status === 'deactivated') {
@@ -100,7 +94,10 @@ function authenticate(email, password) {
100
94
  if (user.deleteRequestedAt != null) {
101
95
  return [2 /*return*/, true];
102
96
  }
103
- logger.warn({ message: 'Refused login for deactivated account', obj: { email: email.toLowerCase() } });
97
+ logger.warn({
98
+ message: 'Refused login for deactivated account',
99
+ obj: { account: new util_node_1.RequestDigests().account(email) },
100
+ });
104
101
  return [2 /*return*/, 'This account has been deactivated'];
105
102
  }
106
103
  return [2 /*return*/, true];
@@ -109,4 +106,42 @@ function authenticate(email, password) {
109
106
  });
110
107
  }
111
108
  exports.authenticate = authenticate;
109
+ /**
110
+ * Looks the account up and verifies the password — the cost every refusal pays, whether or not
111
+ * the address has an account: with none, the password is verified against a stand-in of the
112
+ * same cost (`PasswordHasher.verifyAgainstNothing`), so a refusal's timing says nothing about
113
+ * the address; a human row still in the legacy sha256 format (verified in microseconds) pays the
114
+ * stand-in too, so a refusal's timing says nothing about whether the account has signed in since
115
+ * the format changed either. The login door also runs it on a throttled try and discards the
116
+ * verdict, so a throttled answer takes as long as a refused password. No side effects (no
117
+ * rehash, no log).
118
+ */
119
+ function checkPassword(email, password) {
120
+ return __awaiter(this, void 0, void 0, function () {
121
+ var user, hasher, matches;
122
+ var _a;
123
+ return __generator(this, function (_b) {
124
+ switch (_b.label) {
125
+ case 0: return [4 /*yield*/, (0, db_1.getDbAsSystem)().get(user_1.tables.User, { email: email.toLowerCase() })];
126
+ case 1:
127
+ user = _b.sent();
128
+ hasher = new PasswordHasher_1.PasswordHasher();
129
+ if (!!user) return [3 /*break*/, 3];
130
+ _a = {};
131
+ return [4 /*yield*/, hasher.verifyAgainstNothing(password)];
132
+ case 2: return [2 /*return*/, (_a.matches = _b.sent(), _a)];
133
+ case 3: return [4 /*yield*/, hasher.verify(user.password, password)];
134
+ case 4:
135
+ matches = _b.sent();
136
+ if (!hasher.needsRehash(user.password, user.isLoadedFromSource === true ? 'machine' : 'human')) return [3 /*break*/, 6];
137
+ return [4 /*yield*/, hasher.verifyAgainstNothing(password)];
138
+ case 5:
139
+ _b.sent();
140
+ _b.label = 6;
141
+ case 6: return [2 /*return*/, { user: user, matches: matches }];
142
+ }
143
+ });
144
+ });
145
+ }
146
+ exports.checkPassword = checkPassword;
112
147
  //# sourceMappingURL=authenticate.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"authenticate.js","sourceRoot":"","sources":["../../../src/authentication/authenticate.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,oCAA8C;AAC9C,wCAAyC;AACzC,4CAA2C;AAC3C,qEAAoE;AACpE,mDAAkD;AAElD,SAAgB,oBAAoB,CAAC,uBAAgE;IACnG,IAAI,uBAAuB,EAAE;QAC3B,iDAAuB,CAAC,cAAc,CAAC,uBAAuB,CAAC,CAAC;KACjE;IAED,OAAO,YAAY,CAAC;AACtB,CAAC;AAND,oDAMC;AAED,SAAsB,YAAY,CAAC,KAAa,EAAE,QAAgB;;;;;;;oBAC1D,MAAM,GAAG,IAAI,eAAM,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC,CAAC;oBAC9C,uBAAuB,GAAG,iDAAuB,CAAC,cAAc,EAAE,CAAC;oBACzE,IACE,uBAAuB;wBACvB,uBAAuB,CAAC,QAAQ,IAAI,KAAK;wBACzC,uBAAuB,CAAC,QAAQ,IAAI,QAAQ,EAC5C;wBACA,MAAM,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,kCAAkC,EAAE,CAAC,CAAC;wBAC7D,sBAAO,IAAI,EAAC;qBACb;oBAKK,EAAE,GAAG,IAAA,kBAAa,GAAE,CAAC;oBACd,qBAAM,EAAE,CAAC,GAAG,CAAC,aAAM,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC,EAAA;;oBAAhE,IAAI,GAAG,SAAyD;oBAChE,MAAM,GAAG,IAAI,+BAAc,EAAE,CAAC;oBAChC,KAAA,CAAC,IAAI,CAAA;4BAAL,wBAAK;oBAAM,qBAAM,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,EAAA;;oBAA9C,KAAA,CAAC,CAAC,SAA4C,CAAC,CAAA;;;oBAA5D,QAA8D;wBAC5D,sBAAO,iCAAiC,EAAC;qBAC1C;oBAKK,IAAI,GAAG,IAAI,CAAC,kBAAkB,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC;yBAChE,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,EAAvC,wBAAuC;oBACnC,KAAA,CAAA,KAAA,EAAE,CAAA,CAAC,MAAM,CAAA;0BAAC,aAAM,CAAC,IAAI;2BAAI,EAAE,EAAE,IAAI,CAAC,EAAE;oBAAY,qBAAM,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAA;wBAAjF,qBAAM,yBAAsC,WAAQ,GAAE,SAA2B,QAAG,EAAA;;oBAApF,SAAoF,CAAC;;;oBAGvF,4FAA4F;oBAC5F,oFAAoF;oBACpF,IAAI,IAAI,CAAC,MAAM,KAAK,aAAa,EAAE;wBACjC,6FAA6F;wBAC7F,2FAA2F;wBAC3F,6FAA6F;wBAC7F,0FAA0F;wBAC1F,IAAI,IAAI,CAAC,iBAAiB,IAAI,IAAI,EAAE;4BAClC,sBAAO,IAAI,EAAC;yBACb;wBAED,MAAM,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,uCAAuC,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,WAAW,EAAE,EAAE,EAAE,CAAC,CAAC;wBACvG,sBAAO,mCAAmC,EAAC;qBAC5C;oBAED,sBAAO,IAAI,EAAC;;;;CACb;AA9CD,oCA8CC"}
1
+ {"version":3,"file":"authenticate.js","sourceRoot":"","sources":["../../../src/authentication/authenticate.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"userCache.d.ts","sourceRoot":"","sources":["../../../src/authorization/userCache.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAGzD,OAAO,EAAE,IAAI,EAA6C,MAAM,iBAAiB,CAAC;AAKlF;;;;;;;;GAQG;AACH,eAAO,MAAM,SAAS,EAAE,gBAAgB,CAAC,IAAI,CA8C5C,CAAC"}
1
+ {"version":3,"file":"userCache.d.ts","sourceRoot":"","sources":["../../../src/authorization/userCache.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAIzD,OAAO,EAAE,IAAI,EAA6C,MAAM,iBAAiB,CAAC;AAKlF;;;;;;;;GAQG;AACH,eAAO,MAAM,SAAS,EAAE,gBAAgB,CAAC,IAAI,CA8C5C,CAAC"}
@@ -43,6 +43,7 @@ exports.userCache = void 0;
43
43
  var moment_1 = __importDefault(require("moment"));
44
44
  var db_1 = require("@proteinjs/db");
45
45
  var logger_1 = require("@proteinjs/logger");
46
+ var util_node_1 = require("@proteinjs/util-node");
46
47
  var user_1 = require("@proteinjs/user");
47
48
  var DefaultAdminCredentials_1 = require("../authentication/DefaultAdminCredentials");
48
49
  var logger = new logger_1.Logger({ name: 'userCache' });
@@ -87,7 +88,7 @@ exports.userCache = {
87
88
  // account is deactivated — every request runs as the unauthenticated guest.
88
89
  logger.warn({
89
90
  message: "Session references a deactivated account; resolving as unauthenticated",
90
- obj: { sessionId: sessionId, userEmail: userEmail },
91
+ obj: { sessionId: sessionId, account: new util_node_1.RequestDigests().account(userEmail) },
91
92
  });
92
93
  }
93
94
  else if (accountUser) {
@@ -101,7 +102,7 @@ exports.userCache = {
101
102
  // build as an unhandled rejection and downs the process.
102
103
  logger.warn({
103
104
  message: "Session references an account that does not exist; resolving as unauthenticated",
104
- obj: { sessionId: sessionId, userEmail: userEmail },
105
+ obj: { sessionId: sessionId, account: new util_node_1.RequestDigests().account(userEmail) },
105
106
  });
106
107
  }
107
108
  _a.label = 3;
@@ -1 +1 @@
1
- {"version":3,"file":"userCache.js","sourceRoot":"","sources":["../../../src/authorization/userCache.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,kDAA4B;AAE5B,oCAA8C;AAC9C,4CAA2C;AAC3C,wCAAkF;AAClF,qFAAoF;AAEpF,IAAM,MAAM,GAAG,IAAI,eAAM,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC;AAEjD;;;;;;;;GAQG;AACU,QAAA,SAAS,GAA2B;IAC/C,GAAG,EAAE,6BAAsB;IAC3B,MAAM,EAAE,UAAO,SAAiB,EAAE,SAAiB;;;;;oBAC7C,IAAI,GAAG,gBAAS,CAAC;yBACjB,SAAS,EAAT,wBAAS;oBACL,gBAAgB,GAAG,iDAAuB,CAAC,cAAc,EAAE,CAAC;yBAC9D,CAAA,gBAAgB,IAAI,SAAS,IAAI,gBAAgB,CAAC,QAAQ,CAAA,EAA1D,wBAA0D;oBACtD,SAAS,GAAS;wBACtB,IAAI,EAAE,OAAO;wBACb,KAAK,EAAE,gBAAgB,CAAC,QAAQ;wBAChC,QAAQ,EAAE,gBAAgB,CAAC,QAAQ;wBACnC,aAAa,EAAE,IAAI;wBACnB,KAAK,EAAE,CAAC,OAAO,CAAC;wBAChB,OAAO,EAAE,IAAA,gBAAM,GAAE;wBACjB,OAAO,EAAE,IAAA,gBAAM,GAAE;wBACjB,EAAE,EAAE,OAAO;qBACZ,CAAC;oBACF,IAAI,GAAG,SAAS,CAAC;;wBAEG,qBAAM,IAAA,kBAAa,GAAE,CAAC,GAAG,CAAC,aAAM,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,SAAS,CAAC,WAAW,EAAE,EAAE,CAAC,EAAA;;oBAAxF,WAAW,GAAG,SAA0E;oBAC9F,IAAI,WAAW,IAAI,WAAW,CAAC,MAAM,KAAK,aAAa,EAAE;wBACvD,sFAAsF;wBACtF,iFAAiF;wBACjF,4EAA4E;wBAC5E,MAAM,CAAC,IAAI,CAAC;4BACV,OAAO,EAAE,wEAAwE;4BACjF,GAAG,EAAE,EAAE,SAAS,WAAA,EAAE,SAAS,WAAA,EAAE;yBAC9B,CAAC,CAAC;qBACJ;yBAAM,IAAI,WAAW,EAAE;wBACtB,OAAQ,WAAmB,CAAC,UAAU,CAAC,CAAC;wBACxC,IAAI,GAAG,WAAW,CAAC;qBACpB;yBAAM;wBACL,0FAA0F;wBAC1F,+EAA+E;wBAC/E,sFAAsF;wBACtF,yDAAyD;wBACzD,MAAM,CAAC,IAAI,CAAC;4BACV,OAAO,EAAE,iFAAiF;4BAC1F,GAAG,EAAE,EAAE,SAAS,WAAA,EAAE,SAAS,WAAA,EAAE;yBAC9B,CAAC,CAAC;qBACJ;;wBAIL,sBAAO,IAAI,EAAC;;;SACb;CACF,CAAC"}
1
+ {"version":3,"file":"userCache.js","sourceRoot":"","sources":["../../../src/authorization/userCache.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,kDAA4B;AAE5B,oCAA8C;AAC9C,4CAA2C;AAC3C,kDAAsD;AACtD,wCAAkF;AAClF,qFAAoF;AAEpF,IAAM,MAAM,GAAG,IAAI,eAAM,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC;AAEjD;;;;;;;;GAQG;AACU,QAAA,SAAS,GAA2B;IAC/C,GAAG,EAAE,6BAAsB;IAC3B,MAAM,EAAE,UAAO,SAAiB,EAAE,SAAiB;;;;;oBAC7C,IAAI,GAAG,gBAAS,CAAC;yBACjB,SAAS,EAAT,wBAAS;oBACL,gBAAgB,GAAG,iDAAuB,CAAC,cAAc,EAAE,CAAC;yBAC9D,CAAA,gBAAgB,IAAI,SAAS,IAAI,gBAAgB,CAAC,QAAQ,CAAA,EAA1D,wBAA0D;oBACtD,SAAS,GAAS;wBACtB,IAAI,EAAE,OAAO;wBACb,KAAK,EAAE,gBAAgB,CAAC,QAAQ;wBAChC,QAAQ,EAAE,gBAAgB,CAAC,QAAQ;wBACnC,aAAa,EAAE,IAAI;wBACnB,KAAK,EAAE,CAAC,OAAO,CAAC;wBAChB,OAAO,EAAE,IAAA,gBAAM,GAAE;wBACjB,OAAO,EAAE,IAAA,gBAAM,GAAE;wBACjB,EAAE,EAAE,OAAO;qBACZ,CAAC;oBACF,IAAI,GAAG,SAAS,CAAC;;wBAEG,qBAAM,IAAA,kBAAa,GAAE,CAAC,GAAG,CAAC,aAAM,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,SAAS,CAAC,WAAW,EAAE,EAAE,CAAC,EAAA;;oBAAxF,WAAW,GAAG,SAA0E;oBAC9F,IAAI,WAAW,IAAI,WAAW,CAAC,MAAM,KAAK,aAAa,EAAE;wBACvD,sFAAsF;wBACtF,iFAAiF;wBACjF,4EAA4E;wBAC5E,MAAM,CAAC,IAAI,CAAC;4BACV,OAAO,EAAE,wEAAwE;4BACjF,GAAG,EAAE,EAAE,SAAS,WAAA,EAAE,OAAO,EAAE,IAAI,0BAAc,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE;yBACrE,CAAC,CAAC;qBACJ;yBAAM,IAAI,WAAW,EAAE;wBACtB,OAAQ,WAAmB,CAAC,UAAU,CAAC,CAAC;wBACxC,IAAI,GAAG,WAAW,CAAC;qBACpB;yBAAM;wBACL,0FAA0F;wBAC1F,+EAA+E;wBAC/E,sFAAsF;wBACtF,yDAAyD;wBACzD,MAAM,CAAC,IAAI,CAAC;4BACV,OAAO,EAAE,iFAAiF;4BAC1F,GAAG,EAAE,EAAE,SAAS,WAAA,EAAE,OAAO,EAAE,IAAI,0BAAc,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE;yBACrE,CAAC,CAAC;qBACJ;;wBAIL,sBAAO,IAAI,EAAC;;;SACb;CACF,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"devLogin.d.ts","sourceRoot":"","sources":["../../../src/routes/devLogin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAc9C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AACH,eAAO,MAAM,QAAQ,EAAE,KA4DtB,CAAC"}
1
+ {"version":3,"file":"devLogin.d.ts","sourceRoot":"","sources":["../../../src/routes/devLogin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAe9C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AACH,eAAO,MAAM,QAAQ,EAAE,KAuEtB,CAAC"}
@@ -38,6 +38,7 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
39
  exports.devLogin = void 0;
40
40
  var logger_1 = require("@proteinjs/logger");
41
+ var util_node_1 = require("@proteinjs/util-node");
41
42
  var util_1 = require("@proteinjs/util");
42
43
  var establishSession_1 = require("../authentication/establishSession");
43
44
  var Roles_1 = require("../services/Roles");
@@ -97,7 +98,7 @@ exports.devLogin = {
97
98
  path: '/dev/login',
98
99
  method: 'get',
99
100
  onRequest: function (request, response) { return __awaiter(void 0, void 0, void 0, function () {
100
- var envEmail, email, emailParam, requested, creation, bootstrapEmail, outcome, bootstrapRoles, outcome;
101
+ var envEmail, email, emailParam, requested, digests, creation, error_1, bootstrapEmail, outcome, bootstrapRoles, outcome;
101
102
  var _a, _b, _c;
102
103
  return __generator(this, function (_d) {
103
104
  switch (_d.label) {
@@ -125,6 +126,10 @@ exports.devLogin = {
125
126
  email = requested;
126
127
  }
127
128
  email = email.toLowerCase();
129
+ digests = new util_node_1.RequestDigests();
130
+ _d.label = 1;
131
+ case 1:
132
+ _d.trys.push([1, 3, , 4]);
128
133
  return [4 /*yield*/, new Signup_1.Signup().createAccount({
129
134
  name: email.slice(0, email.indexOf('@')),
130
135
  email: email,
@@ -132,35 +137,45 @@ exports.devLogin = {
132
137
  emailVerified: false,
133
138
  invitedBy: null,
134
139
  })];
135
- case 1:
140
+ case 2:
136
141
  creation = _d.sent();
142
+ return [3 /*break*/, 4];
143
+ case 3:
144
+ error_1 = _d.sent();
145
+ // createAccount refuses in plain words (an address a machine-account declaration owns); the
146
+ // dev door answers the way its other refusals do — the words, no session, no row.
147
+ response
148
+ .status(400)
149
+ .send("/dev/login: ".concat(error_1 instanceof Error ? error_1.message : 'the account could not be created'));
150
+ return [2 /*return*/];
151
+ case 4:
137
152
  if (creation === 'created') {
138
- logger.info({ message: 'Dev auto-login created missing test account', obj: { email: email } });
153
+ logger.info({ message: 'Dev auto-login created missing test account', obj: { account: digests.account(email) } });
139
154
  }
140
155
  bootstrapEmail = ((_c = process.env.DEV_BOOTSTRAP_ADMIN_EMAIL) !== null && _c !== void 0 ? _c : '').trim().toLowerCase();
141
- if (!(bootstrapEmail && email === bootstrapEmail)) return [3 /*break*/, 3];
156
+ if (!(bootstrapEmail && email === bootstrapEmail)) return [3 /*break*/, 6];
142
157
  return [4 /*yield*/, new Roles_1.Roles().bootstrapAdmin(email)];
143
- case 2:
158
+ case 5:
144
159
  outcome = _d.sent();
145
- logger.info({ message: "Dev bootstrap admin door: ".concat(outcome), obj: { email: email } });
146
- _d.label = 3;
147
- case 3:
160
+ logger.info({ message: "Dev bootstrap admin door: ".concat(outcome), obj: { account: digests.account(email) } });
161
+ _d.label = 6;
162
+ case 6:
148
163
  bootstrapRoles = DevBootstrapRoles_1.DevBootstrapRoles.rolesFor(email);
149
- if (!(bootstrapRoles.length > 0)) return [3 /*break*/, 5];
164
+ if (!(bootstrapRoles.length > 0)) return [3 /*break*/, 8];
150
165
  return [4 /*yield*/, new Roles_1.Roles().bootstrapRoles(email, bootstrapRoles)];
151
- case 4:
166
+ case 7:
152
167
  outcome = _d.sent();
153
168
  logger.info({ message: DevBootstrapRoles_1.DevBootstrapRoles.markerLine(email, outcome) });
154
- _d.label = 5;
155
- case 5:
169
+ _d.label = 8;
170
+ case 8:
156
171
  // establishSession commits the session row before the redirect — the redirected GET / must
157
172
  // never read the store ahead of the write (observed: first /dev/login load landed on /login).
158
173
  return [4 /*yield*/, (0, establishSession_1.establishSession)(request, email)];
159
- case 6:
174
+ case 9:
160
175
  // establishSession commits the session row before the redirect — the redirected GET / must
161
176
  // never read the store ahead of the write (observed: first /dev/login load landed on /login).
162
177
  _d.sent();
163
- logger.info({ message: 'Dev auto-login session established', obj: { email: email } });
178
+ logger.info({ message: 'Dev auto-login session established', obj: { account: digests.account(email) } });
164
179
  response.redirect('/');
165
180
  return [2 /*return*/];
166
181
  }
@@ -1 +1 @@
1
- {"version":3,"file":"devLogin.js","sourceRoot":"","sources":["../../../src/routes/devLogin.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"devLogin.js","sourceRoot":"","sources":["../../../src/routes/devLogin.ts"],"names":[],"mappings":"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"}
@@ -8,6 +8,10 @@ import { Route } from '@proteinjs/server-api';
8
8
  * The token itself never reaches the log. A request that carries no body at all is refused like
9
9
  * one that carries a blank password.
10
10
  *
11
+ * A redeemed link also opens the account's sign-in window again (`SignInThrottle`): the person
12
+ * just proved the mailbox, so a reset made while wrong guesses held the door shut lets the new
13
+ * password in at once instead of waiting the window out.
14
+ *
11
15
  * @bodyParam {string} token - The password reset token.
12
16
  * @bodyParam {string} newPassword - The new password for the user.
13
17
  */
@@ -1 +1 @@
1
- {"version":3,"file":"executePasswordReset.d.ts","sourceRoot":"","sources":["../../../src/routes/executePasswordReset.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAM9C;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,oBAAoB,EAAE,KAuClC,CAAC"}
1
+ {"version":3,"file":"executePasswordReset.d.ts","sourceRoot":"","sources":["../../../src/routes/executePasswordReset.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAQ9C;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,oBAAoB,EAAE,KAyClC,CAAC"}
@@ -39,8 +39,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
39
39
  exports.executePasswordReset = void 0;
40
40
  var user_1 = require("@proteinjs/user");
41
41
  var logger_1 = require("@proteinjs/logger");
42
+ var util_node_1 = require("@proteinjs/util-node");
42
43
  var PasswordHasher_1 = require("../authentication/PasswordHasher");
43
44
  var PasswordResetToken_1 = require("../authentication/PasswordResetToken");
45
+ var SignInThrottle_1 = require("../throttle/SignInThrottle");
44
46
  /**
45
47
  * Route handler for executing a password reset.
46
48
  *
@@ -50,6 +52,10 @@ var PasswordResetToken_1 = require("../authentication/PasswordResetToken");
50
52
  * The token itself never reaches the log. A request that carries no body at all is refused like
51
53
  * one that carries a blank password.
52
54
  *
55
+ * A redeemed link also opens the account's sign-in window again (`SignInThrottle`): the person
56
+ * just proved the mailbox, so a reset made while wrong guesses held the door shut lets the new
57
+ * password in at once instead of waiting the window out.
58
+ *
53
59
  * @bodyParam {string} token - The password reset token.
54
60
  * @bodyParam {string} newPassword - The new password for the user.
55
61
  */
@@ -57,12 +63,13 @@ exports.executePasswordReset = {
57
63
  path: user_1.routes.executePasswordReset.path,
58
64
  method: user_1.routes.executePasswordReset.method,
59
65
  onRequest: function (request, response) { return __awaiter(void 0, void 0, void 0, function () {
60
- var logger, _a, token, newPassword, resetToken, resolution, user, hashedPassword;
66
+ var logger, digests, _a, token, newPassword, resetToken, resolution, user, hashedPassword;
61
67
  var _b;
62
68
  return __generator(this, function (_c) {
63
69
  switch (_c.label) {
64
70
  case 0:
65
71
  logger = new logger_1.Logger({ name: 'executePasswordReset' });
72
+ digests = new util_node_1.RequestDigests();
66
73
  _a = (_b = request.body) !== null && _b !== void 0 ? _b : {}, token = _a.token, newPassword = _a.newPassword;
67
74
  if (typeof newPassword !== 'string' || newPassword.length === 0) {
68
75
  response.status(400).send({ error: 'New password cannot be blank' });
@@ -81,7 +88,7 @@ exports.executePasswordReset = {
81
88
  return [2 /*return*/];
82
89
  }
83
90
  if (resolution.status === 'expired') {
84
- logger.info({ message: "Expired reset token used", obj: { email: resolution.user.email } });
91
+ logger.info({ message: "Expired reset token used", obj: { account: digests.account(resolution.user.email) } });
85
92
  response.status(400).send({ error: 'Reset token has expired' });
86
93
  return [2 /*return*/];
87
94
  }
@@ -92,11 +99,12 @@ exports.executePasswordReset = {
92
99
  return [4 /*yield*/, resetToken.redeem(user, resolution.token, hashedPassword)];
93
100
  case 3:
94
101
  if (!(_c.sent())) {
95
- logger.info({ message: "Reset token already redeemed", obj: { email: user.email } });
102
+ logger.info({ message: "Reset token already redeemed", obj: { account: digests.account(user.email) } });
96
103
  response.status(400).send({ error: 'Invalid or expired reset token' });
97
104
  return [2 /*return*/];
98
105
  }
99
- logger.info({ message: "Password successfully reset", obj: { email: user.email } });
106
+ SignInThrottle_1.signInThrottle.recordSuccess(digests.account(user.email));
107
+ logger.info({ message: "Password successfully reset", obj: { account: digests.account(user.email) } });
100
108
  response.send({ message: 'Password has been successfully reset' });
101
109
  return [2 /*return*/];
102
110
  }
@@ -1 +1 @@
1
- {"version":3,"file":"executePasswordReset.js","sourceRoot":"","sources":["../../../src/routes/executePasswordReset.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,wCAAyC;AACzC,4CAA2C;AAC3C,mEAAkE;AAClE,2EAA0E;AAE1E;;;;;;;;;;;GAWG;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,eAAM,CAAC,EAAE,IAAI,EAAE,sBAAsB,EAAE,CAAC,CAAC;oBACtD,KAAyB,MAAA,OAAO,CAAC,IAAI,mCAAI,EAAE,EAAzC,KAAK,WAAA,EAAE,WAAW,iBAAA,CAAwB;oBAClD,IAAI,OAAO,WAAW,KAAK,QAAQ,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE;wBAC/D,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,8BAA8B,EAAE,CAAC,CAAC;wBACrE,sBAAO;qBACR;oBAEK,UAAU,GAAG,IAAI,uCAAkB,EAAE,CAAC;oBACzB,qBAAM,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,EAAA;;oBAA5C,UAAU,GAAG,SAA+B;oBAClD,IAAI,UAAU,CAAC,MAAM,KAAK,WAAW,IAAI,UAAU,CAAC,MAAM,KAAK,SAAS,EAAE;wBACxE,MAAM,CAAC,IAAI,CAAC;4BACV,OAAO,EAAE,0BAA0B;4BACnC,GAAG,EAAE,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,KAAK,EAAE,UAAU,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE;yBACzE,CAAC,CAAC;wBACH,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,gCAAgC,EAAE,CAAC,CAAC;wBACvE,sBAAO;qBACR;oBAED,IAAI,UAAU,CAAC,MAAM,KAAK,SAAS,EAAE;wBACnC,MAAM,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,0BAA0B,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,UAAU,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;wBAC5F,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,yBAAyB,EAAE,CAAC,CAAC;wBAChE,sBAAO;qBACR;oBAEO,IAAI,GAAK,UAAU,KAAf,CAAgB;oBACL,qBAAM,IAAI,+BAAc,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,EAAA;;oBAA7D,cAAc,GAAG,SAA4C;oBAC7D,qBAAM,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC,KAAK,EAAE,cAAc,CAAC,EAAA;;oBAArE,IAAI,CAAC,CAAC,SAA+D,CAAC,EAAE;wBACtE,MAAM,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,8BAA8B,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;wBACrF,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,gCAAgC,EAAE,CAAC,CAAC;wBACvE,sBAAO;qBACR;oBAED,MAAM,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,6BAA6B,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;oBACpF,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,sCAAsC,EAAE,CAAC,CAAC;;;;SACpE;CACF,CAAC"}
1
+ {"version":3,"file":"executePasswordReset.js","sourceRoot":"","sources":["../../../src/routes/executePasswordReset.ts"],"names":[],"mappings":"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"}
@@ -6,6 +6,13 @@ import { Route } from '@proteinjs/server-api';
6
6
  * its expiry on the user row — and mails the token to the account as a reset link. The token is
7
7
  * withdrawn again when the mail fails to send.
8
8
  *
9
+ * ONE ANSWER: every request with an address is answered `ONE_ANSWER` — BEFORE the address is
10
+ * looked up — whether it has an account, is throttled (`PasswordResetThrottle`: per client and
11
+ * per address), is inside the account's five-minute gap, or its mail fails; so neither the
12
+ * words, the status nor the timing say whether an address has an account. The work runs after
13
+ * the answer. Every request is one outcome line carrying the account digest and the coarse IP
14
+ * hash (`RequestDigests`) — never the address.
15
+ *
9
16
  * Requires an implementation of `DefaultPasswordResetEmailConfigFactory` to build the password reset email with.
10
17
  *
11
18
  * @bodyParam {string} email - The email address of the user requesting a password reset.
@@ -1 +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,KAkEnC,CAAC"}
1
+ {"version":3,"file":"initiatePasswordReset.d.ts","sourceRoot":"","sources":["../../../src/routes/initiatePasswordReset.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAoB9C;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,qBAAqB,EAAE,KAoEnC,CAAC"}