EdgeRateLimitService.js 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. const { Context } = require("../../util/context");
  2. const { asyncSafeSetInterval } = require("../../util/promise");
  3. const { MINUTE, HOUR } = require('../../util/time.js');
  4. const BaseService = require("../BaseService");
  5. class EdgeRateLimitService extends BaseService {
  6. _construct () {
  7. this.scopes = {
  8. ['login']: {
  9. limit: 3,
  10. window: 15 * MINUTE,
  11. },
  12. ['signup']: {
  13. limit: 10,
  14. window: 15 * MINUTE,
  15. },
  16. ['send-confirm-email']: {
  17. limit: 10,
  18. window: HOUR,
  19. },
  20. ['send-pass-recovery-email']: {
  21. limit: 10,
  22. window: HOUR,
  23. },
  24. ['set-pass-using-token']: {
  25. limit: 10,
  26. window: HOUR,
  27. },
  28. ['save-account']: {
  29. limit: 10,
  30. window: HOUR,
  31. },
  32. ['change-email-start']: {
  33. limit: 10,
  34. window: HOUR,
  35. },
  36. ['change-email-confirm']: {
  37. limit: 10,
  38. window: HOUR,
  39. },
  40. ['passwd']: {
  41. limit: 10,
  42. window: HOUR,
  43. },
  44. };
  45. this.requests = new Map();
  46. }
  47. async _init () {
  48. asyncSafeSetInterval(() => this.cleanup(), 5 * MINUTE);
  49. }
  50. check (scope) {
  51. const { window, limit } = this.scopes[scope];
  52. const requester = Context.get('requester');
  53. const rl_identifier = requester.rl_identifier;
  54. const key = `${scope}:${rl_identifier}`;
  55. const now = Date.now();
  56. const windowStart = now - window;
  57. if (!this.requests.has(key)) {
  58. this.requests.set(key, []);
  59. }
  60. // Access the timestamps of past requests for this scope and IP
  61. const timestamps = this.requests.get(key);
  62. // Remove timestamps that are outside the current window
  63. while (timestamps.length > 0 && timestamps[0] < windowStart) {
  64. timestamps.shift();
  65. }
  66. // Check if the current request exceeds the rate limit
  67. if (timestamps.length >= limit) {
  68. return false;
  69. } else {
  70. // Add current timestamp and allow the request
  71. timestamps.push(now);
  72. return true;
  73. }
  74. }
  75. cleanup() {
  76. this.log.tick('edge rate-limit cleanup task');
  77. for (const [key, timestamps] of this.requests.entries()) {
  78. if (timestamps.length === 0) {
  79. this.requests.delete(key);
  80. }
  81. }
  82. }
  83. }
  84. module.exports = { EdgeRateLimitService };