@moxon/api 6.1.0 → 6.2.0

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 (69) hide show
  1. package/README.md +21 -14
  2. package/dist/app.js +5 -3
  3. package/dist/app.js.map +1 -1
  4. package/dist/constants.d.ts +22 -0
  5. package/dist/constants.js +22 -0
  6. package/dist/constants.js.map +1 -1
  7. package/dist/middleware/cors.d.ts +15 -0
  8. package/dist/middleware/cors.js +25 -6
  9. package/dist/middleware/cors.js.map +1 -1
  10. package/dist/middleware/ratelimit.d.ts +53 -1
  11. package/dist/middleware/ratelimit.js +180 -71
  12. package/dist/middleware/ratelimit.js.map +1 -1
  13. package/dist/modules/v4/barcode.d.ts +1 -1
  14. package/dist/modules/v4/barcode.js +9 -2
  15. package/dist/modules/v4/barcode.js.map +1 -1
  16. package/dist/modules/v4/captcha.d.ts +1 -1
  17. package/dist/modules/v4/captcha.js +5 -1
  18. package/dist/modules/v4/captcha.js.map +1 -1
  19. package/dist/modules/v4/chat.js +61 -12
  20. package/dist/modules/v4/chat.js.map +1 -1
  21. package/dist/modules/v4/cron.js +20 -2
  22. package/dist/modules/v4/cron.js.map +1 -1
  23. package/dist/modules/v4/hyperplanning.d.ts +11 -0
  24. package/dist/modules/v4/hyperplanning.js +30 -29
  25. package/dist/modules/v4/hyperplanning.js.map +1 -1
  26. package/dist/modules/v4/qrcode.d.ts +10 -0
  27. package/dist/modules/v4/qrcode.js +138 -14
  28. package/dist/modules/v4/qrcode.js.map +1 -1
  29. package/dist/modules/v4/regex.d.ts +1 -1
  30. package/dist/modules/v4/regex.js +67 -22
  31. package/dist/modules/v4/regex.js.map +1 -1
  32. package/dist/modules/v4/tic_tac_toe.js +56 -15
  33. package/dist/modules/v4/tic_tac_toe.js.map +1 -1
  34. package/dist/modules/v5/asymmetric.d.ts +15 -0
  35. package/dist/modules/v5/asymmetric.js +67 -5
  36. package/dist/modules/v5/asymmetric.js.map +1 -1
  37. package/dist/modules/v5/barcode.d.ts +1 -1
  38. package/dist/modules/v5/barcode.js +9 -2
  39. package/dist/modules/v5/barcode.js.map +1 -1
  40. package/dist/modules/v5/captcha.d.ts +12 -4
  41. package/dist/modules/v5/captcha.js +25 -8
  42. package/dist/modules/v5/captcha.js.map +1 -1
  43. package/dist/modules/v5/chat.js +66 -17
  44. package/dist/modules/v5/chat.js.map +1 -1
  45. package/dist/modules/v5/cron.d.ts +26 -0
  46. package/dist/modules/v5/cron.js +356 -0
  47. package/dist/modules/v5/cron.js.map +1 -0
  48. package/dist/modules/v5/pow.js +1 -1
  49. package/dist/modules/v5/pow.js.map +1 -1
  50. package/dist/modules/v5/tic_tac_toe.js +61 -20
  51. package/dist/modules/v5/tic_tac_toe.js.map +1 -1
  52. package/dist/modules/v5.d.ts +3 -2
  53. package/dist/modules/v5.js +3 -2
  54. package/dist/modules/v5.js.map +1 -1
  55. package/dist/routes/post.js +12 -5
  56. package/dist/routes/post.js.map +1 -1
  57. package/dist/storage/index.js +9 -8
  58. package/dist/storage/index.js.map +1 -1
  59. package/dist/types/storage.d.ts +4 -0
  60. package/dist/utils/challenge.d.ts +5 -3
  61. package/dist/utils/challenge.js +52 -6
  62. package/dist/utils/challenge.js.map +1 -1
  63. package/dist/utils/helpers.d.ts +18 -0
  64. package/dist/utils/helpers.js +35 -1
  65. package/dist/utils/helpers.js.map +1 -1
  66. package/dist/utils/remote.d.ts +42 -0
  67. package/dist/utils/remote.js +313 -0
  68. package/dist/utils/remote.js.map +1 -0
  69. package/package.json +1 -1
package/README.md CHANGED
@@ -75,15 +75,15 @@ console.log(user.username);
75
75
 
76
76
  ## What's inside
77
77
 
78
- | Domain | Exports |
79
- | ------------------ | ------------------------------------------------------------------------------------- |
80
- | **Crypto** | `asymmetric` `symmetric` `hash` `jwt` `otp` `token` `password` `captcha` |
81
- | **Math & data** | **`matrix`** **`algorithms`** `evaluate` `statistics` `convert` `csv` |
82
- | **Text** | **`text`** **`encode`** **`validate`** `caseConvert` `levenshtein` `regex` `parseUrl` |
83
- | **Graphics** | **`chart`** `barcode` `qrcode` `avatar` `placeholder` `color` `palette` |
84
- | **Fake data** | `personal` `address` `credit` `username` `dice` `domain` `agent` |
85
- | **Network & time** | `ip` `geo` `time` `cron` `hyperplanning` |
86
- | **Stateful** | `chat` `tic_tac_toe` |
78
+ | Domain | Exports |
79
+ | ------------------ | ------------------------------------------------------------------------------------------ |
80
+ | **Crypto** | `asymmetric` `asymmetricAsync` `symmetric` `hash` `jwt` `otp` `token` `password` `captcha` |
81
+ | **Math & data** | **`matrix`** **`algorithms`** `evaluate` `statistics` `convert` `csv` |
82
+ | **Text** | **`text`** **`encode`** **`validate`** `caseConvert` `levenshtein` `regex` `parseUrl` |
83
+ | **Graphics** | **`chart`** `barcode` `qrcode` `avatar` `placeholder` `color` `palette` |
84
+ | **Fake data** | `personal` `address` `credit` `username` `dice` `domain` `agent` |
85
+ | **Network & time** | `ip` `geo` `time` `cron` `hyperplanning` |
86
+ | **Stateful** | `chat` `tic_tac_toe` |
87
87
 
88
88
  The six names in **bold** are namespaces — they group related functions, called as `namespace.method()`:
89
89
 
@@ -112,6 +112,7 @@ Two names differ from their HTTP endpoint, because `case` is a reserved word and
112
112
  ```js
113
113
  import {
114
114
  asymmetric,
115
+ asymmetricAsync,
115
116
  caseConvert,
116
117
  chart,
117
118
  csv,
@@ -130,6 +131,10 @@ const { result: encrypted } = asymmetric('encrypt', { text: 'secret message', pu
130
131
  const { result: decrypted } = asymmetric('decrypt', { text: encrypted, privateKey });
131
132
  console.log(decrypted); // 'secret message'
132
133
 
134
+ // Same result, but the key pair is generated off the main thread
135
+ const keys = await asymmetricAsync('keygen', { modulusLength: 4096 });
136
+ console.log(keys.modulusLength); // 4096
137
+
133
138
  // AES-256-GCM symmetric encryption, key derived with scrypt
134
139
  const { result: blob } = symmetric('encrypt', 'secret message', 'a-strong-key');
135
140
  const { result: plain } = symmetric('decrypt', blob, 'a-strong-key');
@@ -214,13 +219,13 @@ $ npm run build && npm start
214
219
  ```
215
220
 
216
221
  ```console
217
- > @moxon/api@6.1.0 build
222
+ > @moxon/api@6.2.0 build
218
223
  > npm run clean && tsc
219
224
 
220
- > @moxon/api@6.1.0 clean
225
+ > @moxon/api@6.2.0 clean
221
226
  > node -e "require('node:fs').rmSync('dist', { recursive: true, force: true })"
222
227
 
223
- > @moxon/api@6.1.0 start
228
+ > @moxon/api@6.2.0 start
224
229
  > node dist/app.js
225
230
 
226
231
  API is running on
@@ -248,7 +253,7 @@ Every setting is optional and read from the environment; a `.env` file at the pr
248
253
  | `INSTANCE_CREATED` | — | Launch date reported by `/:version/infos` |
249
254
  | `LOGS_TOKEN` | — | Value required in the `X-Logs-Token` header to read `/logs`; the route answers 404 while unset |
250
255
  | `CHALLENGE_SECRET` | random | Key signing the captcha and proof-of-work tokens; a random one is generated at startup while unset |
251
- | `TRUSTED_PROXIES` | one hop | CIDR blocks separated by spaces or commas, or the `loopback` / `linklocal` / `uniquelocal` shorthands, for deployments behind a CDN or platform router |
256
+ | `TRUSTED_PROXIES` | one hop | CIDR blocks or `loopback` / `linklocal` / `uniquelocal`, space or comma separated; unset, exactly one reverse proxy is assumed and a warning is logged |
252
257
  | `GLOBAL_LIMIT` | `50000` | Requests per hour accepted across the whole instance |
253
258
  | `DEFAULT_LIMIT` | `2000` | Per-client requests per hour |
254
259
  | `DEFAULT_BURST` | `50` | Per-client requests per 10-second window |
@@ -257,7 +262,9 @@ The three metadata variables are omitted from responses when unset, so an instan
257
262
 
258
263
  Higher quotas can be granted per client: `ADVANCED_`, `PRO_` and `BUSINESS_` variants of `_LIMIT` and `_BURST` define the tiers, and the matching `*_TOKEN_LIST` variables hold the space-separated bearer tokens that map to them. A client's tier and quota are reported by `GET /auth`.
259
264
 
260
- > _Rate-limit counters live in process memory, so each instance of a multi-instance deployment counts separately._
265
+ > _Rate-limit counters live in process memory, so each instance of a multi-instance deployment counts separately. Clients are counted by address: an IPv4-mapped IPv6 address counts as its IPv4 form and any other IPv6 address as its `/64` block, while all the `/64` blocks of one `/48` network share four times the per-client hourly quota. A forwarded address that is not an IP address counts as the connecting peer. Only requests the per-client limits let through use the `GLOBAL_LIMIT` budget._
266
+
267
+ > _The one-hop default reads the client address from the last `X-Forwarded-For` entry, which is right behind a single reverse proxy such as nginx or Caddy. Exposed directly, callers can forge that header and pick their own address; behind several hops, every caller is counted as the nearest proxy. Set `TRUSTED_PROXIES` to match the actual chain._
261
268
 
262
269
  > _Captcha and proof-of-work tokens are signed with `CHALLENGE_SECRET`. While it is unset each process invents its own key, so tokens stop verifying after a restart and are rejected by sibling instances — set it explicitly for any deployment running more than one process, with a full-entropy value such as `openssl rand -hex 32`._
263
270
 
package/dist/app.js CHANGED
@@ -2,7 +2,7 @@ import express from 'express';
2
2
  import { env } from './config/env.js';
3
3
  import { endpoints } from './endpoints/index.js';
4
4
  import { build } from './endpoints/router.js';
5
- import { setupCors } from './middleware/cors.js';
5
+ import { setupCors, setupParsers } from './middleware/cors.js';
6
6
  import { errorHandler } from './middleware/error.js';
7
7
  import { jsonResponseMiddleware } from './middleware/json.js';
8
8
  import { loggerMiddleware } from './middleware/logger.js';
@@ -15,12 +15,14 @@ import patchRoutes from './routes/patch.js';
15
15
  import postRoutes from './routes/post.js';
16
16
  import { error } from './utils/response.js';
17
17
  const app = express();
18
- // Setup CORS, body parsing, static files
18
+ // Security headers, CORS, static files
19
19
  setupCors(app);
20
20
  // Custom JSON response
21
21
  app.use(jsonResponseMiddleware);
22
- // Rate limiting
22
+ // Rate limiting, ahead of body parsing so malformed bodies are counted too
23
23
  app.use(rateLimitMiddleware);
24
+ // Body parsing
25
+ setupParsers(app);
24
26
  // Request logging
25
27
  app.use(loggerMiddleware);
26
28
  // Root routes (before version check)
package/dist/app.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"app.js","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"app.js","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"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"}
@@ -1,22 +1,33 @@
1
1
  export declare const APP_VERSION: string;
2
2
  export declare const DEFAULT_PORT = 3000;
3
3
  export declare const START_TIME: number;
4
+ export declare const CHALLENGE_MAX_ATTEMPTS = 5;
4
5
  export declare const CHALLENGE_TTL = 300000;
5
6
  export declare const GAME_CLEANUP_TTL = 600000;
6
7
  export declare const MAX_LOG_ENTRIES = 1000;
8
+ export declare const RATE_LIMIT_IPV6_NETWORK = 48;
9
+ export declare const RATE_LIMIT_IPV6_PREFIX = 64;
10
+ export declare const RATE_LIMIT_NETWORK_FACTOR = 4;
7
11
  export declare const RATE_LIMIT_WINDOW = 10000;
8
12
  export declare const RATE_LIMIT_MAX = 50;
9
13
  export declare const SESSION_TTL = 3600000;
10
14
  export declare const STATUS_MESSAGES: Record<number, string>;
11
15
  export declare const EARTH_RADIUS_KM = 6371;
12
16
  export declare const MAX_ADDRESS_COUNT = 10;
17
+ export declare const MAX_BARCODE_DATA_LENGTH = 128;
13
18
  export declare const MAX_BASE_VALUE_LENGTH = 100;
19
+ export declare const MAX_CAPTCHA_TEXT_LENGTH = 32;
14
20
  export declare const MAX_CHART_DATASETS = 5;
15
21
  export declare const MAX_CHART_LABELS = 20;
22
+ export declare const MAX_CHAT_MESSAGES = 200;
16
23
  export declare const MAX_CSV_LENGTH = 50000;
17
24
  export declare const MAX_CSV_ROWS = 1000;
18
25
  export declare const MAX_CREDIT_COUNT = 10;
26
+ export declare const MAX_CONCURRENT_KEYGENS = 2;
19
27
  export declare const MAX_COUNTDOWN_YEARS = 100;
28
+ export declare const MAX_CRON_DURATION = 250;
29
+ export declare const MAX_CRON_DURATION_V4 = 1000;
30
+ export declare const MAX_CRON_GAP: number;
20
31
  export declare const MAX_CRON_ITERATIONS: number;
21
32
  export declare const MAX_CRON_RESULTS = 20;
22
33
  export declare const MAX_DIFF_LENGTH = 10000;
@@ -25,6 +36,10 @@ export declare const MAX_EXPR_DEPTH = 100;
25
36
  export declare const MAX_EXPR_LENGTH = 500;
26
37
  export declare const MAX_FACTORIAL = 170;
27
38
  export declare const MAX_GCD_VALUE = 100000;
39
+ export declare const ICS_FETCH_TIMEOUT = 10000;
40
+ export declare const MAX_ICS_BYTES: number;
41
+ export declare const MAX_ICS_EVENTS = 5000;
42
+ export declare const MAX_ID_LENGTH = 256;
28
43
  export declare const MAX_JWT_LENGTH = 8192;
29
44
  export declare const MAX_LEVENSHTEIN_LENGTH = 1000;
30
45
  export declare const MIN_PASSWORD_LENGTH = 8;
@@ -34,15 +49,22 @@ export declare const MAX_MATRIX_SIZE = 20;
34
49
  export declare const MAX_PATTERN_LENGTH = 200;
35
50
  export declare const MAX_POW_DIFFICULTY = 6;
36
51
  export declare const MAX_PRIME_LIST = 10000;
52
+ export declare const MAX_PRIVATE_CHATS = 1000;
37
53
  export declare const POW_DEFAULT_DIFFICULTY = 4;
54
+ export declare const MAX_QRCODE_ICON_PIXELS = 16000000;
38
55
  export declare const MAX_QRCODE_LOGO_BYTES: number;
56
+ export declare const QRCODE_ICON_TIMEOUT = 5000;
39
57
  export declare const MAX_READ_LENGTH = 50000;
40
58
  export declare const MAX_REGEX_MATCHES = 100;
59
+ export declare const REGEX_TIMEOUT = 25;
60
+ export declare const MAX_REMOTE_REDIRECTS = 10;
41
61
  export declare const MAX_RSA_MODULUS = 4096;
42
62
  export declare const MAX_SEMVER_LENGTH = 256;
43
63
  export declare const MAX_STRING_LENGTH = 1000;
64
+ export declare const MAX_TIMESTAMP_LENGTH = 128;
44
65
  export declare const MIN_TOKEN_LENGTH = 12;
45
66
  export declare const MAX_TOKEN_LENGTH = 4096;
46
67
  export declare const MAX_URL_LENGTH = 2048;
68
+ export declare const MAX_USERNAME_LENGTH = 100;
47
69
  export declare const MAX_UUID_COUNT = 50;
48
70
  export declare const ROMAN_VALUES: [number, string][];
package/dist/constants.js CHANGED
@@ -4,9 +4,13 @@ export const APP_VERSION = pkg.version;
4
4
  export const DEFAULT_PORT = 3000;
5
5
  export const START_TIME = Date.now();
6
6
  // Server
7
+ export const CHALLENGE_MAX_ATTEMPTS = 5;
7
8
  export const CHALLENGE_TTL = 300_000;
8
9
  export const GAME_CLEANUP_TTL = 600_000;
9
10
  export const MAX_LOG_ENTRIES = 1000;
11
+ export const RATE_LIMIT_IPV6_NETWORK = 48;
12
+ export const RATE_LIMIT_IPV6_PREFIX = 64;
13
+ export const RATE_LIMIT_NETWORK_FACTOR = 4;
10
14
  export const RATE_LIMIT_WINDOW = 10_000;
11
15
  export const RATE_LIMIT_MAX = 50;
12
16
  export const SESSION_TTL = 3_600_000;
@@ -22,13 +26,20 @@ export const STATUS_MESSAGES = {
22
26
  // Modules
23
27
  export const EARTH_RADIUS_KM = 6371;
24
28
  export const MAX_ADDRESS_COUNT = 10;
29
+ export const MAX_BARCODE_DATA_LENGTH = 128;
25
30
  export const MAX_BASE_VALUE_LENGTH = 100;
31
+ export const MAX_CAPTCHA_TEXT_LENGTH = 32;
26
32
  export const MAX_CHART_DATASETS = 5;
27
33
  export const MAX_CHART_LABELS = 20;
34
+ export const MAX_CHAT_MESSAGES = 200;
28
35
  export const MAX_CSV_LENGTH = 50_000;
29
36
  export const MAX_CSV_ROWS = 1000;
30
37
  export const MAX_CREDIT_COUNT = 10;
38
+ export const MAX_CONCURRENT_KEYGENS = 2;
31
39
  export const MAX_COUNTDOWN_YEARS = 100;
40
+ export const MAX_CRON_DURATION = 250;
41
+ export const MAX_CRON_DURATION_V4 = 1000;
42
+ export const MAX_CRON_GAP = 401 * 366 * 86_400_000;
32
43
  export const MAX_CRON_ITERATIONS = 365 * 24 * 60;
33
44
  export const MAX_CRON_RESULTS = 20;
34
45
  export const MAX_DIFF_LENGTH = 10_000;
@@ -37,6 +48,10 @@ export const MAX_EXPR_DEPTH = 100;
37
48
  export const MAX_EXPR_LENGTH = 500;
38
49
  export const MAX_FACTORIAL = 170;
39
50
  export const MAX_GCD_VALUE = 100_000;
51
+ export const ICS_FETCH_TIMEOUT = 10_000;
52
+ export const MAX_ICS_BYTES = 1024 * 1024;
53
+ export const MAX_ICS_EVENTS = 5000;
54
+ export const MAX_ID_LENGTH = 256;
40
55
  export const MAX_JWT_LENGTH = 8192;
41
56
  export const MAX_LEVENSHTEIN_LENGTH = 1000;
42
57
  export const MIN_PASSWORD_LENGTH = 8;
@@ -46,16 +61,23 @@ export const MAX_MATRIX_SIZE = 20;
46
61
  export const MAX_PATTERN_LENGTH = 200;
47
62
  export const MAX_POW_DIFFICULTY = 6;
48
63
  export const MAX_PRIME_LIST = 10_000;
64
+ export const MAX_PRIVATE_CHATS = 1000;
49
65
  export const POW_DEFAULT_DIFFICULTY = 4;
66
+ export const MAX_QRCODE_ICON_PIXELS = 16_000_000;
50
67
  export const MAX_QRCODE_LOGO_BYTES = 2 * 1024 * 1024;
68
+ export const QRCODE_ICON_TIMEOUT = 5000;
51
69
  export const MAX_READ_LENGTH = 50_000;
52
70
  export const MAX_REGEX_MATCHES = 100;
71
+ export const REGEX_TIMEOUT = 25;
72
+ export const MAX_REMOTE_REDIRECTS = 10;
53
73
  export const MAX_RSA_MODULUS = 4096;
54
74
  export const MAX_SEMVER_LENGTH = 256;
55
75
  export const MAX_STRING_LENGTH = 1000;
76
+ export const MAX_TIMESTAMP_LENGTH = 128;
56
77
  export const MIN_TOKEN_LENGTH = 12;
57
78
  export const MAX_TOKEN_LENGTH = 4096;
58
79
  export const MAX_URL_LENGTH = 2048;
80
+ export const MAX_USERNAME_LENGTH = 100;
59
81
  export const MAX_UUID_COUNT = 50;
60
82
  export const ROMAN_VALUES = [
61
83
  [1000, 'M'],
@@ -1 +1 @@
1
- {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"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"}
@@ -1,2 +1,17 @@
1
1
  import { type Express } from 'express';
2
+ /**
3
+ * Applies the proxy setting, the security headers, CORS and the robots.txt route.
4
+ *
5
+ * The security headers come first so that every response carries them,
6
+ * preflights and errors included. Body parsing is mounted separately by
7
+ * setupParsers, after the rate limiter.
8
+ *
9
+ * @param app - Express application to configure
10
+ */
2
11
  export declare function setupCors(app: Express): void;
12
+ /**
13
+ * Mounts the URL-encoded and JSON body parsers, both capped at 10 KB.
14
+ *
15
+ * @param app - Express application to configure
16
+ */
17
+ export declare function setupParsers(app: Express): void;
@@ -5,8 +5,25 @@ import { fileURLToPath } from 'url';
5
5
  import { env } from '../config/env.js';
6
6
  const __filename = fileURLToPath(import.meta.url);
7
7
  const __dirname = dirname(__filename);
8
+ /**
9
+ * Applies the proxy setting, the security headers, CORS and the robots.txt route.
10
+ *
11
+ * The security headers come first so that every response carries them,
12
+ * preflights and errors included. Body parsing is mounted separately by
13
+ * setupParsers, after the rate limiter.
14
+ *
15
+ * @param app - Express application to configure
16
+ */
8
17
  export function setupCors(app) {
9
18
  app.set('trust proxy', env.TRUSTED_PROXIES ?? 1);
19
+ if (!env.TRUSTED_PROXIES && process.env.NODE_ENV !== 'test') {
20
+ console.warn('TRUSTED_PROXIES is unset: client addresses are read assuming exactly one reverse proxy in front of the API.');
21
+ }
22
+ app.use((_req, res, next) => {
23
+ res.setHeader('X-Content-Type-Options', 'nosniff');
24
+ res.setHeader('X-Frame-Options', 'DENY');
25
+ next();
26
+ });
10
27
  app.use(cors({
11
28
  methods: ['GET', 'POST', 'PATCH', 'DELETE', 'OPTIONS'],
12
29
  exposedHeaders: [
@@ -18,13 +35,15 @@ export function setupCors(app) {
18
35
  'Retry-After',
19
36
  ],
20
37
  }));
38
+ app.use('/robots.txt', express.static(join(__dirname, '..', '..', 'robots.txt')));
39
+ }
40
+ /**
41
+ * Mounts the URL-encoded and JSON body parsers, both capped at 10 KB.
42
+ *
43
+ * @param app - Express application to configure
44
+ */
45
+ export function setupParsers(app) {
21
46
  app.use(express.urlencoded({ extended: true, limit: '10kb' }));
22
47
  app.use(express.json({ limit: '10kb' }));
23
- app.use((_req, res, next) => {
24
- res.setHeader('X-Content-Type-Options', 'nosniff');
25
- res.setHeader('X-Frame-Options', 'DENY');
26
- next();
27
- });
28
- app.use('/robots.txt', express.static(join(__dirname, '..', '..', 'robots.txt')));
29
48
  }
30
49
  //# sourceMappingURL=cors.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"cors.js","sourceRoot":"","sources":["../../src/middleware/cors.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,OAAyB,MAAM,SAAS,CAAC;AAChD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AACrC,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AAEpC,OAAO,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAC;AAEvC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AAEtC,MAAM,UAAU,SAAS,CAAC,GAAY;IAClC,GAAG,CAAC,GAAG,CAAC,aAAa,EAAE,GAAG,CAAC,eAAe,IAAI,CAAC,CAAC,CAAC;IAEjD,GAAG,CAAC,GAAG,CACH,IAAI,CAAC;QACD,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,CAAC;QACtD,cAAc,EAAE;YACZ,gBAAgB;YAChB,iBAAiB;YACjB,mBAAmB;YACnB,uBAAuB;YACvB,mBAAmB;YACnB,aAAa;SAChB;KACJ,CAAC,CACL,CAAC;IACF,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;IAC/D,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;IAEzC,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QACxB,GAAG,CAAC,SAAS,CAAC,wBAAwB,EAAE,SAAS,CAAC,CAAC;QACnD,GAAG,CAAC,SAAS,CAAC,iBAAiB,EAAE,MAAM,CAAC,CAAC;QACzC,IAAI,EAAE,CAAC;IACX,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,GAAG,CAAC,aAAa,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC;AACtF,CAAC"}
1
+ {"version":3,"file":"cors.js","sourceRoot":"","sources":["../../src/middleware/cors.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,OAAyB,MAAM,SAAS,CAAC;AAChD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AACrC,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AAEpC,OAAO,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAC;AAEvC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AAEtC;;;;;;;;GAQG;AACH,MAAM,UAAU,SAAS,CAAC,GAAY;IAClC,GAAG,CAAC,GAAG,CAAC,aAAa,EAAE,GAAG,CAAC,eAAe,IAAI,CAAC,CAAC,CAAC;IACjD,IAAI,CAAC,GAAG,CAAC,eAAe,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC;QAC1D,OAAO,CAAC,IAAI,CACR,6GAA6G,CAChH,CAAC;IACN,CAAC;IAED,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QACxB,GAAG,CAAC,SAAS,CAAC,wBAAwB,EAAE,SAAS,CAAC,CAAC;QACnD,GAAG,CAAC,SAAS,CAAC,iBAAiB,EAAE,MAAM,CAAC,CAAC;QACzC,IAAI,EAAE,CAAC;IACX,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,GAAG,CACH,IAAI,CAAC;QACD,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,CAAC;QACtD,cAAc,EAAE;YACZ,gBAAgB;YAChB,iBAAiB;YACjB,mBAAmB;YACnB,uBAAuB;YACvB,mBAAmB;YACnB,aAAa;SAChB;KACJ,CAAC,CACL,CAAC;IAEF,GAAG,CAAC,GAAG,CAAC,aAAa,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC;AACtF,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,GAAY;IACrC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;IAC/D,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;AAC7C,CAAC"}
@@ -1,2 +1,54 @@
1
1
  import type { NextFunction, Request, Response } from 'express';
2
- export declare function rateLimitMiddleware(req: Request, res: Response, next: NextFunction): void;
2
+ import type { IpLimits } from '../types/storage.js';
3
+ export interface RateLimiterOptions {
4
+ now?: () => number;
5
+ burst?: boolean;
6
+ global?: number;
7
+ limits?: IpLimits;
8
+ }
9
+ /**
10
+ * Derives the key a client is rate limited under.
11
+ *
12
+ * An IPv4-mapped IPv6 address counts as its IPv4 form, so a dual-stack socket
13
+ * and a proxy header naming the same caller share one quota. Any other IPv6
14
+ * address counts as its /64 prefix, the block a single subscriber is usually
15
+ * handed, so rotating addresses inside it does not reset the quota.
16
+ *
17
+ * @param ip - Client address as resolved by Express
18
+ * @returns The IPv4 address, the IPv6 prefix, or the input unchanged when it is not an IP address
19
+ */
20
+ export declare function clientKey(ip: string): string;
21
+ /**
22
+ * Derives the IPv6 network a client belongs to, the largest block one subscriber is usually handed.
23
+ *
24
+ * @param ip - Client address as resolved by Express
25
+ * @returns The /48 prefix of an IPv6 address, or null for IPv4, IPv4-mapped and non-IP input
26
+ */
27
+ export declare function networkKey(ip: string): string | null;
28
+ /**
29
+ * Drops the hourly counters left from past hours and the burst timestamps outside the window.
30
+ *
31
+ * @param limits - Hourly counters, keyed by client
32
+ * @param bursts - Timestamps of recent requests, keyed by client
33
+ * @param now - Current time in milliseconds
34
+ * @param networks - Admitted requests per IPv6 network, with the epoch hour they were counted in
35
+ */
36
+ export declare function sweep(limits: IpLimits, bursts: Map<string, number[]>, now: number, networks?: Map<string, {
37
+ hour: number;
38
+ count: number;
39
+ }>): void;
40
+ /**
41
+ * Builds a rate limiting middleware with its own counters.
42
+ *
43
+ * A request is checked against the instance-wide hourly budget, then against
44
+ * the burst window and the hourly quota of its plan for its client key, and an
45
+ * IPv6 client also against a larger quota for its whole /48 network. Only a
46
+ * request that passes every check uses the instance-wide and network budgets,
47
+ * so a client being refused cannot exhaust them for everybody else. A forged
48
+ * proxy header that is not an IP address counts as the socket peer instead.
49
+ *
50
+ * @param options - Clock, burst switch, instance-wide budget and hourly store, each with a production default
51
+ * @returns An Express middleware enforcing the limits
52
+ */
53
+ export declare function createRateLimiter(options?: RateLimiterOptions): (req: Request, res: Response, next: NextFunction) => void;
54
+ export declare const rateLimitMiddleware: (req: Request, res: Response, next: NextFunction) => void;