@boopkit/cap-oauth-server 0.1.4 → 0.3.1

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 (91) hide show
  1. package/capability.json +14 -2
  2. package/dist/authorization-code-service.d.ts +40 -11
  3. package/dist/authorization-code-service.d.ts.map +1 -1
  4. package/dist/authorization-code-service.js +93 -41
  5. package/dist/authorization-code-service.js.map +1 -1
  6. package/dist/bearer.d.ts +27 -4
  7. package/dist/bearer.d.ts.map +1 -1
  8. package/dist/bearer.js +4 -4
  9. package/dist/bearer.js.map +1 -1
  10. package/dist/client-prune.d.ts +102 -0
  11. package/dist/client-prune.d.ts.map +1 -0
  12. package/dist/client-prune.js +51 -0
  13. package/dist/client-prune.js.map +1 -0
  14. package/dist/client-registry-service.d.ts +85 -8
  15. package/dist/client-registry-service.d.ts.map +1 -1
  16. package/dist/client-registry-service.js +267 -64
  17. package/dist/client-registry-service.js.map +1 -1
  18. package/dist/config.d.ts +6 -0
  19. package/dist/config.d.ts.map +1 -1
  20. package/dist/config.js +1 -0
  21. package/dist/config.js.map +1 -1
  22. package/dist/connections-controller.js +1 -1
  23. package/dist/connections-controller.js.map +1 -1
  24. package/dist/consent-controller.d.ts +80 -6
  25. package/dist/consent-controller.d.ts.map +1 -1
  26. package/dist/consent-controller.js +134 -18
  27. package/dist/consent-controller.js.map +1 -1
  28. package/dist/discovery-controller.d.ts +2 -1
  29. package/dist/discovery-controller.d.ts.map +1 -1
  30. package/dist/discovery-controller.js +14 -4
  31. package/dist/discovery-controller.js.map +1 -1
  32. package/dist/discovery.d.ts +26 -0
  33. package/dist/discovery.d.ts.map +1 -1
  34. package/dist/discovery.js +55 -1
  35. package/dist/discovery.js.map +1 -1
  36. package/dist/errors.d.ts +38 -0
  37. package/dist/errors.d.ts.map +1 -1
  38. package/dist/errors.js +59 -0
  39. package/dist/errors.js.map +1 -1
  40. package/dist/grant-service.d.ts +11 -4
  41. package/dist/grant-service.d.ts.map +1 -1
  42. package/dist/grant-service.js +6 -3
  43. package/dist/grant-service.js.map +1 -1
  44. package/dist/index.d.ts +10 -5
  45. package/dist/index.d.ts.map +1 -1
  46. package/dist/index.js +18 -3
  47. package/dist/index.js.map +1 -1
  48. package/dist/metadata-document.d.ts +22 -0
  49. package/dist/metadata-document.d.ts.map +1 -1
  50. package/dist/metadata-document.js +44 -2
  51. package/dist/metadata-document.js.map +1 -1
  52. package/dist/outbound-target.d.ts +48 -0
  53. package/dist/outbound-target.d.ts.map +1 -0
  54. package/dist/outbound-target.js +211 -0
  55. package/dist/outbound-target.js.map +1 -0
  56. package/dist/rate-limit.d.ts +53 -11
  57. package/dist/rate-limit.d.ts.map +1 -1
  58. package/dist/rate-limit.js +27 -4
  59. package/dist/rate-limit.js.map +1 -1
  60. package/dist/redirect-uri.d.ts +17 -9
  61. package/dist/redirect-uri.d.ts.map +1 -1
  62. package/dist/redirect-uri.js +26 -10
  63. package/dist/redirect-uri.js.map +1 -1
  64. package/dist/registration-controller.d.ts +10 -0
  65. package/dist/registration-controller.d.ts.map +1 -1
  66. package/dist/registration-controller.js +10 -0
  67. package/dist/registration-controller.js.map +1 -1
  68. package/dist/request-client.d.ts +7 -1
  69. package/dist/request-client.d.ts.map +1 -1
  70. package/dist/request-client.js +31 -13
  71. package/dist/request-client.js.map +1 -1
  72. package/dist/revocation-controller.d.ts +5 -0
  73. package/dist/revocation-controller.d.ts.map +1 -1
  74. package/dist/revocation-controller.js +5 -1
  75. package/dist/revocation-controller.js.map +1 -1
  76. package/dist/same-site.d.ts +54 -0
  77. package/dist/same-site.d.ts.map +1 -0
  78. package/dist/same-site.js +124 -0
  79. package/dist/same-site.js.map +1 -0
  80. package/dist/token-controller.d.ts +26 -0
  81. package/dist/token-controller.d.ts.map +1 -1
  82. package/dist/token-controller.js +44 -19
  83. package/dist/token-controller.js.map +1 -1
  84. package/dist/types.d.ts +4 -0
  85. package/dist/types.d.ts.map +1 -1
  86. package/package.json +2 -2
  87. package/scaffold/reference/oauth-server.ref.md +359 -11
  88. package/scaffold/src/middleware/oauth-server.ts +33 -17
  89. package/scaffold/src/scripts/prune-oauth-clients.ts +86 -0
  90. package/scaffold/src/services/oauth-server.service.ts +24 -0
  91. package/scaffold/views/oauth-consent-error.hbs +10 -3
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Where a caller-chosen URL may point.
3
+ *
4
+ * One place in this capability fetches a URL a stranger supplied: the Client ID
5
+ * Metadata Document path, reached from an unauthenticated `GET /oauth/authorize`
6
+ * whose `client_id` is an https URL. Without a guard, that is an SSRF primitive
7
+ * pointed at whatever network the application runs in — the document body is
8
+ * discarded on a failure, but *existence* and *latency* are both readable
9
+ * through the request's response time, and the outbound request happens whatever
10
+ * the answer (boop-jd4x).
11
+ *
12
+ * ## What this can and cannot promise
13
+ *
14
+ * The literal tables below are exact: an address in one of these ranges is never
15
+ * fetched. A *name* is harder, and is handled in two layers.
16
+ *
17
+ * 1. Names reserved by convention for a local network — `localhost`, `.local`,
18
+ * `.internal`, `.home.arpa` — are refused outright.
19
+ * 2. Everything else needs DNS, which this package will not do: it has no
20
+ * business importing `node:dns`, and a capability that did could not be
21
+ * tested without a resolver. So the resolver is injected
22
+ * (`metadataResolveHost`), and when an application supplies one, every
23
+ * address a name resolves to is run through the same table.
24
+ *
25
+ * Even with a resolver this is not airtight, and the gap has a name: between the
26
+ * lookup here and the connection the HTTP client makes, the name can be
27
+ * re-resolved to a different address (DNS rebinding). Closing that needs a
28
+ * transport that connects to an address this code chose, which `fetch` does not
29
+ * offer. What is here raises the cost of the probe from "free" to "needs a
30
+ * rebinding setup", and refuses the whole class of literal and by-name targets
31
+ * that a probe actually uses.
32
+ */
33
+ /**
34
+ * Is this string a literal address we refuse to connect to?
35
+ *
36
+ * `false` for anything that is not an address at all, including every hostname —
37
+ * a name is `blockedHostReason`'s business, because deciding it needs DNS.
38
+ */
39
+ export declare function isBlockedAddress(value: string): boolean;
40
+ /**
41
+ * Why this hostname may not be fetched, or `null` if it may.
42
+ *
43
+ * A sentence rather than a boolean, because the caller puts it in a refusal an
44
+ * operator has to read: "could not be fetched" tells them nothing, and a CIMD
45
+ * publisher who pointed at the wrong host needs to see which host.
46
+ */
47
+ export declare function blockedHostReason(hostname: string): string | null;
48
+ //# sourceMappingURL=outbound-target.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"outbound-target.d.ts","sourceRoot":"","sources":["../src/outbound-target.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AA+GH;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAWvD;AASD;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAkBjE"}
@@ -0,0 +1,211 @@
1
+ "use strict";
2
+ /**
3
+ * Where a caller-chosen URL may point.
4
+ *
5
+ * One place in this capability fetches a URL a stranger supplied: the Client ID
6
+ * Metadata Document path, reached from an unauthenticated `GET /oauth/authorize`
7
+ * whose `client_id` is an https URL. Without a guard, that is an SSRF primitive
8
+ * pointed at whatever network the application runs in — the document body is
9
+ * discarded on a failure, but *existence* and *latency* are both readable
10
+ * through the request's response time, and the outbound request happens whatever
11
+ * the answer (boop-jd4x).
12
+ *
13
+ * ## What this can and cannot promise
14
+ *
15
+ * The literal tables below are exact: an address in one of these ranges is never
16
+ * fetched. A *name* is harder, and is handled in two layers.
17
+ *
18
+ * 1. Names reserved by convention for a local network — `localhost`, `.local`,
19
+ * `.internal`, `.home.arpa` — are refused outright.
20
+ * 2. Everything else needs DNS, which this package will not do: it has no
21
+ * business importing `node:dns`, and a capability that did could not be
22
+ * tested without a resolver. So the resolver is injected
23
+ * (`metadataResolveHost`), and when an application supplies one, every
24
+ * address a name resolves to is run through the same table.
25
+ *
26
+ * Even with a resolver this is not airtight, and the gap has a name: between the
27
+ * lookup here and the connection the HTTP client makes, the name can be
28
+ * re-resolved to a different address (DNS rebinding). Closing that needs a
29
+ * transport that connects to an address this code chose, which `fetch` does not
30
+ * offer. What is here raises the cost of the probe from "free" to "needs a
31
+ * rebinding setup", and refuses the whole class of literal and by-name targets
32
+ * that a probe actually uses.
33
+ */
34
+ Object.defineProperty(exports, "__esModule", { value: true });
35
+ exports.isBlockedAddress = isBlockedAddress;
36
+ exports.blockedHostReason = blockedHostReason;
37
+ /** The four octets of a dotted-quad, or `null` if it is not one. */
38
+ function parseIpv4(value) {
39
+ const parts = value.split('.');
40
+ if (parts.length !== 4)
41
+ return null;
42
+ const octets = [];
43
+ for (const part of parts) {
44
+ // No octal, no hex, no leading zeros: `010.0.0.1` is a spelling of
45
+ // `8.0.0.1` in some resolvers and of `10.0.0.1` in others, and a table that
46
+ // has to guess which is a table with a hole in it. Anything ambiguous is
47
+ // not an address as far as this code is concerned, and a hostname that is
48
+ // not an address is decided by DNS instead.
49
+ if (!/^(0|[1-9]\d{0,2})$/.test(part))
50
+ return null;
51
+ const octet = Number(part);
52
+ if (octet > 255)
53
+ return null;
54
+ octets.push(octet);
55
+ }
56
+ return octets;
57
+ }
58
+ /** The sixteen bytes of an IPv6 address, or `null` if it is not one. */
59
+ function parseIpv6(value) {
60
+ // A zone index (`fe80::1%eth0`) names an interface, not a different address.
61
+ let text = value.toLowerCase().split('%')[0];
62
+ if (!text.includes(':'))
63
+ return null;
64
+ if (!/^[0-9a-f:.]*$/.test(text))
65
+ return null;
66
+ // A trailing dotted-quad (`::ffff:127.0.0.1`) is the same address as the two
67
+ // hextets it stands for, so rewrite it and carry on with one parser.
68
+ const lastColon = text.lastIndexOf(':');
69
+ const tail = text.slice(lastColon + 1);
70
+ if (tail.includes('.')) {
71
+ const quad = parseIpv4(tail);
72
+ if (!quad)
73
+ return null;
74
+ const high = ((quad[0] << 8) | quad[1]).toString(16);
75
+ const low = ((quad[2] << 8) | quad[3]).toString(16);
76
+ text = `${text.slice(0, lastColon + 1)}${high}:${low}`;
77
+ }
78
+ const halves = text.split('::');
79
+ if (halves.length > 2)
80
+ return null;
81
+ const head = halves[0] === '' ? [] : halves[0].split(':');
82
+ const rest = halves.length === 2 ? (halves[1] === '' ? [] : halves[1].split(':')) : [];
83
+ let groups;
84
+ if (halves.length === 2) {
85
+ const fill = 8 - head.length - rest.length;
86
+ if (fill < 1)
87
+ return null;
88
+ groups = [...head, ...Array(fill).fill('0'), ...rest];
89
+ }
90
+ else {
91
+ groups = head;
92
+ }
93
+ if (groups.length !== 8)
94
+ return null;
95
+ const bytes = [];
96
+ for (const group of groups) {
97
+ if (!/^[0-9a-f]{1,4}$/.test(group))
98
+ return null;
99
+ const hextet = Number.parseInt(group, 16);
100
+ bytes.push(hextet >>> 8, hextet & 0xff);
101
+ }
102
+ return bytes;
103
+ }
104
+ /**
105
+ * Is this IPv4 address somewhere other than the public internet?
106
+ *
107
+ * The list is IANA's special-purpose registry, narrowed to the entries a probe
108
+ * would actually aim at. `169.254.0.0/16` is the one to notice: every major
109
+ * cloud puts its instance metadata service at `169.254.169.254`, and that
110
+ * endpoint hands out credentials.
111
+ */
112
+ function isBlockedIpv4(octets) {
113
+ const [a, b] = octets;
114
+ if (a === 0)
115
+ return true; // "this network"
116
+ if (a === 10)
117
+ return true; // RFC 1918
118
+ if (a === 127)
119
+ return true; // loopback
120
+ if (a === 100 && b >= 64 && b <= 127)
121
+ return true; // RFC 6598 carrier-grade NAT
122
+ if (a === 169 && b === 254)
123
+ return true; // link-local, incl. cloud metadata
124
+ if (a === 172 && b >= 16 && b <= 31)
125
+ return true; // RFC 1918
126
+ if (a === 192 && b === 0)
127
+ return true; // IETF protocol assignments
128
+ if (a === 192 && b === 168)
129
+ return true; // RFC 1918
130
+ if (a === 198 && (b === 18 || b === 19))
131
+ return true; // RFC 2544 benchmarking
132
+ if (a >= 224)
133
+ return true; // multicast, reserved, and 255.255.255.255
134
+ return false;
135
+ }
136
+ /** The same question for IPv6, including addresses wearing an IPv4 coat. */
137
+ function isBlockedIpv6(bytes) {
138
+ const isZero = (from, to) => bytes.slice(from, to).every((byte) => byte === 0);
139
+ // `::ffff:0:0/96` — an IPv4 address in IPv6 clothing. Judged as the IPv4
140
+ // address it is, or `::ffff:127.0.0.1` would walk straight past the table.
141
+ if (isZero(0, 10) && bytes[10] === 0xff && bytes[11] === 0xff) {
142
+ return isBlockedIpv4(bytes.slice(12));
143
+ }
144
+ // `64:ff9b::/96` — the well-known NAT64 prefix, which is another way to spell
145
+ // an IPv4 destination for a network that has a translator. Same treatment.
146
+ if (bytes[0] === 0x00 && bytes[1] === 0x64 && bytes[2] === 0xff && bytes[3] === 0x9b &&
147
+ isZero(4, 12)) {
148
+ return isBlockedIpv4(bytes.slice(12));
149
+ }
150
+ // `::` (unspecified) and `::1` (loopback), and the rest of `::/64` with them:
151
+ // nothing in that range is a host on the public internet.
152
+ if (isZero(0, 8))
153
+ return true;
154
+ if ((bytes[0] & 0xfe) === 0xfc)
155
+ return true; // fc00::/7 unique local
156
+ if (bytes[0] === 0xfe && (bytes[1] & 0xc0) === 0x80)
157
+ return true; // fe80::/10 link-local
158
+ if (bytes[0] === 0xff)
159
+ return true; // ff00::/8 multicast
160
+ return false;
161
+ }
162
+ /**
163
+ * Is this string a literal address we refuse to connect to?
164
+ *
165
+ * `false` for anything that is not an address at all, including every hostname —
166
+ * a name is `blockedHostReason`'s business, because deciding it needs DNS.
167
+ */
168
+ function isBlockedAddress(value) {
169
+ const text = value.trim();
170
+ if (text === '')
171
+ return false;
172
+ const ipv4 = parseIpv4(text);
173
+ if (ipv4)
174
+ return isBlockedIpv4(ipv4);
175
+ const ipv6 = parseIpv6(text);
176
+ if (ipv6)
177
+ return isBlockedIpv6(ipv6);
178
+ return false;
179
+ }
180
+ /**
181
+ * Names reserved for a local network. RFC 6761 (`localhost`), RFC 6762
182
+ * (`.local`), RFC 8375 (`.home.arpa`), and `.internal`, which is what cloud
183
+ * providers hand out for private zones and which ICANN has now reserved.
184
+ */
185
+ const BLOCKED_SUFFIXES = ['.localhost', '.local', '.internal', '.home.arpa'];
186
+ /**
187
+ * Why this hostname may not be fetched, or `null` if it may.
188
+ *
189
+ * A sentence rather than a boolean, because the caller puts it in a refusal an
190
+ * operator has to read: "could not be fetched" tells them nothing, and a CIMD
191
+ * publisher who pointed at the wrong host needs to see which host.
192
+ */
193
+ function blockedHostReason(hostname) {
194
+ // A URL spells an IPv6 literal in brackets; the address inside is what the
195
+ // table knows about.
196
+ const host = hostname.trim().toLowerCase().replace(/^\[|\]$/g, '');
197
+ if (host === '')
198
+ return 'the URL names no host';
199
+ if (isBlockedAddress(host)) {
200
+ return `${hostname} is a private, loopback, link-local or otherwise non-public address`;
201
+ }
202
+ // A trailing dot is a fully-qualified spelling of the same name.
203
+ const name = host.endsWith('.') ? host.slice(0, -1) : host;
204
+ if (name === 'localhost')
205
+ return `${hostname} names this machine`;
206
+ if (BLOCKED_SUFFIXES.some((suffix) => name.endsWith(suffix))) {
207
+ return `${hostname} is a name reserved for a local network`;
208
+ }
209
+ return null;
210
+ }
211
+ //# sourceMappingURL=outbound-target.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"outbound-target.js","sourceRoot":"","sources":["../src/outbound-target.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;;AAqHH,4CAWC;AAgBD,8CAkBC;AAhKD,oEAAoE;AACpE,SAAS,SAAS,CAAC,KAAa;IAC9B,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC/B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACpC,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,mEAAmE;QACnE,4EAA4E;QAC5E,yEAAyE;QACzE,0EAA0E;QAC1E,4CAA4C;QAC5C,IAAI,CAAC,oBAAoB,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;QAClD,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;QAC3B,IAAI,KAAK,GAAG,GAAG;YAAE,OAAO,IAAI,CAAC;QAC7B,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACrB,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,wEAAwE;AACxE,SAAS,SAAS,CAAC,KAAa;IAC9B,6EAA6E;IAC7E,IAAI,IAAI,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7C,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IACrC,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAE7C,6EAA6E;IAC7E,qEAAqE;IACrE,MAAM,SAAS,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IACxC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC;IACvC,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;QAC7B,IAAI,CAAC,IAAI;YAAE,OAAO,IAAI,CAAC;QACvB,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QACrD,MAAM,GAAG,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QACpD,IAAI,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,GAAG,CAAC,CAAC,GAAG,IAAI,IAAI,GAAG,EAAE,CAAC;IACzD,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAChC,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IACnC,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC1D,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAEvF,IAAI,MAAgB,CAAC;IACrB,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAC3C,IAAI,IAAI,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC;QAC1B,MAAM,GAAG,CAAC,GAAG,IAAI,EAAE,GAAG,KAAK,CAAS,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC;IAChE,CAAC;SAAM,CAAC;QACN,MAAM,GAAG,IAAI,CAAC;IAChB,CAAC;IACD,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAErC,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QAChD,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAC1C,KAAK,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC;IAC1C,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,aAAa,CAAC,MAAgB;IACrC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,MAAM,CAAC;IACtB,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC,CAAC,iBAAiB;IAC3C,IAAI,CAAC,KAAK,EAAE;QAAE,OAAO,IAAI,CAAC,CAAC,WAAW;IACtC,IAAI,CAAC,KAAK,GAAG;QAAE,OAAO,IAAI,CAAC,CAAC,WAAW;IACvC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,GAAG;QAAE,OAAO,IAAI,CAAC,CAAC,6BAA6B;IAChF,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG;QAAE,OAAO,IAAI,CAAC,CAAC,mCAAmC;IAC5E,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE;QAAE,OAAO,IAAI,CAAC,CAAC,WAAW;IAC7D,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC,CAAC,4BAA4B;IACnE,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG;QAAE,OAAO,IAAI,CAAC,CAAC,WAAW;IACpD,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC;QAAE,OAAO,IAAI,CAAC,CAAC,wBAAwB;IAC9E,IAAI,CAAC,IAAI,GAAG;QAAE,OAAO,IAAI,CAAC,CAAC,2CAA2C;IACtE,OAAO,KAAK,CAAC;AACf,CAAC;AAED,4EAA4E;AAC5E,SAAS,aAAa,CAAC,KAAe;IACpC,MAAM,MAAM,GAAG,CAAC,IAAY,EAAE,EAAU,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC;IAE/F,yEAAyE;IACzE,2EAA2E;IAC3E,IAAI,MAAM,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC,KAAK,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC;QAC9D,OAAO,aAAa,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;IACxC,CAAC;IACD,8EAA8E;IAC9E,2EAA2E;IAC3E,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI;QAChF,MAAM,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;QAClB,OAAO,aAAa,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;IACxC,CAAC;IACD,8EAA8E;IAC9E,0DAA0D;IAC1D,IAAI,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAC9B,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC,CAAC,wBAAwB;IACrE,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC,CAAC,uBAAuB;IACzF,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC,CAAC,qBAAqB;IACzD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;GAKG;AACH,SAAgB,gBAAgB,CAAC,KAAa;IAC5C,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAC1B,IAAI,IAAI,KAAK,EAAE;QAAE,OAAO,KAAK,CAAC;IAE9B,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAC7B,IAAI,IAAI;QAAE,OAAO,aAAa,CAAC,IAAI,CAAC,CAAC;IAErC,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAC7B,IAAI,IAAI;QAAE,OAAO,aAAa,CAAC,IAAI,CAAC,CAAC;IAErC,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;GAIG;AACH,MAAM,gBAAgB,GAAG,CAAC,YAAY,EAAE,QAAQ,EAAE,WAAW,EAAE,YAAY,CAAC,CAAC;AAE7E;;;;;;GAMG;AACH,SAAgB,iBAAiB,CAAC,QAAgB;IAChD,2EAA2E;IAC3E,qBAAqB;IACrB,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IACnE,IAAI,IAAI,KAAK,EAAE;QAAE,OAAO,uBAAuB,CAAC;IAEhD,IAAI,gBAAgB,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3B,OAAO,GAAG,QAAQ,qEAAqE,CAAC;IAC1F,CAAC;IAED,iEAAiE;IACjE,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAC3D,IAAI,IAAI,KAAK,WAAW;QAAE,OAAO,GAAG,QAAQ,qBAAqB,CAAC;IAClE,IAAI,gBAAgB,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC;QAC7D,OAAO,GAAG,QAAQ,yCAAyC,CAAC;IAC9D,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -1,13 +1,20 @@
1
- import type { RequestHandler } from 'express';
1
+ import type { Request, RequestHandler } from 'express';
2
2
  /**
3
- * Per-IP rate limiting for the one endpoint that lets a stranger write a row.
3
+ * Per-IP rate limiting for the paths that let a stranger write a row.
4
4
  *
5
- * `POST /oauth/register` is unauthenticated by design — RFC 7591 open
6
- * registration has no caller to authenticate — so there is no account to hang a
7
- * quota on and the source address is the only thing a limiter has to go on.
8
- * Neither donor has anything like this: paywalls' registration endpoint
9
- * required an authenticated `service-user`, which is a gate this endpoint
10
- * cannot have.
5
+ * There are two, and for a long time only one of them had this. `POST
6
+ * /oauth/register` is unauthenticated by design — RFC 7591 open registration has
7
+ * no caller to authenticate — so there is no account to hang a quota on and the
8
+ * source address is the only thing a limiter has to go on. Neither donor has
9
+ * anything like this: paywalls' registration endpoint required an authenticated
10
+ * `service-user`, which is a gate this endpoint cannot have.
11
+ *
12
+ * The second is **first-sight metadata-document resolution** at `GET
13
+ * /oauth/authorize`. It is equally unauthenticated, it writes a row per distinct
14
+ * URL, and it makes an outbound request besides — so it is limited by the same
15
+ * counter, mounted by the consent handlers rather than by a router, because only
16
+ * the handler knows whether a given request is about to resolve a new client or
17
+ * serve one that already has a row (boop-jd4x).
11
18
  *
12
19
  * ## What this is, and what it is not
13
20
  *
@@ -27,6 +34,14 @@ import type { RequestHandler } from 'express';
27
34
  * boundary. Named here rather than fixed, because the mitigation (a sliding
28
35
  * window) buys precision this does not need against a ceiling that is already
29
36
  * the real bound.
37
+ *
38
+ * ## The address has to be the caller's
39
+ *
40
+ * Both limiters key on `req.ip`, which behind a proxy is the proxy unless the
41
+ * application has set `trust proxy`. Left unset, every caller shares one bucket:
42
+ * one abuser exhausts it for everybody, and no individual abuser is ever
43
+ * stopped. That is worth checking in a deployment — it is the difference between
44
+ * a limiter and a decoration.
30
45
  */
31
46
  export interface RateLimiterOptions {
32
47
  /** Requests allowed per window, per address. */
@@ -43,14 +58,41 @@ export interface RateLimiterOptions {
43
58
  }
44
59
  export declare const DEFAULT_REGISTRATION_RATE_LIMIT = 10;
45
60
  export declare const DEFAULT_REGISTRATION_RATE_WINDOW_MS: number;
46
- export interface RegistrationRateLimiter {
61
+ /**
62
+ * First-sight metadata-document resolutions allowed per address per window.
63
+ *
64
+ * The same number as registration, and for the same reason: reaching it is not
65
+ * something an honest browser does. A resolution is charged only when the
66
+ * `client_id` is an https URL with **no row yet** — every later visit to the
67
+ * same client is served from the row and costs nothing — so ten distinct,
68
+ * never-before-seen connectors an hour from one address is already generous.
69
+ */
70
+ export declare const DEFAULT_METADATA_RESOLUTION_RATE_LIMIT = 10;
71
+ export interface FixedWindowRateLimiter {
72
+ /** The `POST /oauth/register` mount. */
47
73
  middleware: RequestHandler;
48
- /** Exposed for tests and for an operator script; not part of the route. */
74
+ /**
75
+ * The counter itself, for a caller that decides *whether* a request counts —
76
+ * the consent handlers charge only a first-sight resolution — and for tests
77
+ * and operator scripts.
78
+ */
49
79
  check(address: string): {
50
80
  allowed: boolean;
51
81
  retryAfterSeconds: number;
52
82
  };
53
83
  reset(): void;
54
84
  }
55
- export declare function createRegistrationRateLimiter(options?: RateLimiterOptions): RegistrationRateLimiter;
85
+ /** The old name, kept so an application that imported it still compiles. */
86
+ export type RegistrationRateLimiter = FixedWindowRateLimiter;
87
+ /**
88
+ * The address a limiter counts against.
89
+ *
90
+ * Exported so the middleware and the consent handlers cannot pick different
91
+ * answers — two limiters keyed differently are two quotas, and the one an
92
+ * attacker would find is whichever is keyed more loosely.
93
+ */
94
+ export declare function rateLimitAddress(req: Request): string;
95
+ export declare function createFixedWindowRateLimiter(options?: RateLimiterOptions): FixedWindowRateLimiter;
96
+ /** The registration endpoint's name for the same factory. */
97
+ export declare const createRegistrationRateLimiter: typeof createFixedWindowRateLimiter;
56
98
  //# sourceMappingURL=rate-limit.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"rate-limit.d.ts","sourceRoot":"","sources":["../src/rate-limit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAyB,cAAc,EAAY,MAAM,SAAS,CAAC;AAE/E;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,MAAM,WAAW,kBAAkB;IACjC,gDAAgD;IAChD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qCAAqC;IACrC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,4EAA4E;IAC5E,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB;;;OAGG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,eAAO,MAAM,+BAA+B,KAAK,CAAC;AAClD,eAAO,MAAM,mCAAmC,QAAiB,CAAC;AAQlE,MAAM,WAAW,uBAAuB;IACtC,UAAU,EAAE,cAAc,CAAC;IAC3B,2EAA2E;IAC3E,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,iBAAiB,EAAE,MAAM,CAAA;KAAE,CAAC;IACxE,KAAK,IAAI,IAAI,CAAC;CACf;AAED,wBAAgB,6BAA6B,CAC3C,OAAO,GAAE,kBAAuB,GAC/B,uBAAuB,CAmDzB"}
1
+ {"version":3,"file":"rate-limit.d.ts","sourceRoot":"","sources":["../src/rate-limit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAgB,OAAO,EAAE,cAAc,EAAY,MAAM,SAAS,CAAC;AAE/E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAEH,MAAM,WAAW,kBAAkB;IACjC,gDAAgD;IAChD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qCAAqC;IACrC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,4EAA4E;IAC5E,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB;;;OAGG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,eAAO,MAAM,+BAA+B,KAAK,CAAC;AAClD,eAAO,MAAM,mCAAmC,QAAiB,CAAC;AAElE;;;;;;;;GAQG;AACH,eAAO,MAAM,sCAAsC,KAAK,CAAC;AAQzD,MAAM,WAAW,sBAAsB;IACrC,wCAAwC;IACxC,UAAU,EAAE,cAAc,CAAC;IAC3B;;;;OAIG;IACH,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,iBAAiB,EAAE,MAAM,CAAA;KAAE,CAAC;IACxE,KAAK,IAAI,IAAI,CAAC;CACf;AAED,4EAA4E;AAC5E,MAAM,MAAM,uBAAuB,GAAG,sBAAsB,CAAC;AAE7D;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAErD;AAED,wBAAgB,4BAA4B,CAC1C,OAAO,GAAE,kBAAuB,GAC/B,sBAAsB,CAmDxB;AAED,6DAA6D;AAC7D,eAAO,MAAM,6BAA6B,qCAA+B,CAAC"}
@@ -1,11 +1,32 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DEFAULT_REGISTRATION_RATE_WINDOW_MS = exports.DEFAULT_REGISTRATION_RATE_LIMIT = void 0;
4
- exports.createRegistrationRateLimiter = createRegistrationRateLimiter;
3
+ exports.createRegistrationRateLimiter = exports.DEFAULT_METADATA_RESOLUTION_RATE_LIMIT = exports.DEFAULT_REGISTRATION_RATE_WINDOW_MS = exports.DEFAULT_REGISTRATION_RATE_LIMIT = void 0;
4
+ exports.rateLimitAddress = rateLimitAddress;
5
+ exports.createFixedWindowRateLimiter = createFixedWindowRateLimiter;
5
6
  exports.DEFAULT_REGISTRATION_RATE_LIMIT = 10;
6
7
  exports.DEFAULT_REGISTRATION_RATE_WINDOW_MS = 60 * 60 * 1000;
8
+ /**
9
+ * First-sight metadata-document resolutions allowed per address per window.
10
+ *
11
+ * The same number as registration, and for the same reason: reaching it is not
12
+ * something an honest browser does. A resolution is charged only when the
13
+ * `client_id` is an https URL with **no row yet** — every later visit to the
14
+ * same client is served from the row and costs nothing — so ten distinct,
15
+ * never-before-seen connectors an hour from one address is already generous.
16
+ */
17
+ exports.DEFAULT_METADATA_RESOLUTION_RATE_LIMIT = 10;
7
18
  const DEFAULT_MAX_TRACKED_ADDRESSES = 10000;
8
- function createRegistrationRateLimiter(options = {}) {
19
+ /**
20
+ * The address a limiter counts against.
21
+ *
22
+ * Exported so the middleware and the consent handlers cannot pick different
23
+ * answers — two limiters keyed differently are two quotas, and the one an
24
+ * attacker would find is whichever is keyed more loosely.
25
+ */
26
+ function rateLimitAddress(req) {
27
+ return req.ip ?? req.socket?.remoteAddress ?? 'unknown';
28
+ }
29
+ function createFixedWindowRateLimiter(options = {}) {
9
30
  const limit = options.limit ?? exports.DEFAULT_REGISTRATION_RATE_LIMIT;
10
31
  const windowMs = options.windowMs ?? exports.DEFAULT_REGISTRATION_RATE_WINDOW_MS;
11
32
  const now = options.now ?? (() => Date.now());
@@ -36,7 +57,7 @@ function createRegistrationRateLimiter(options = {}) {
36
57
  return { allowed: true, retryAfterSeconds: 0 };
37
58
  }
38
59
  const middleware = (req, res, next) => {
39
- const address = req.ip ?? req.socket?.remoteAddress ?? 'unknown';
60
+ const address = rateLimitAddress(req);
40
61
  const verdict = check(address);
41
62
  if (verdict.allowed)
42
63
  return next();
@@ -52,4 +73,6 @@ function createRegistrationRateLimiter(options = {}) {
52
73
  reset: () => windows.clear(),
53
74
  };
54
75
  }
76
+ /** The registration endpoint's name for the same factory. */
77
+ exports.createRegistrationRateLimiter = createFixedWindowRateLimiter;
55
78
  //# sourceMappingURL=rate-limit.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"rate-limit.js","sourceRoot":"","sources":["../src/rate-limit.ts"],"names":[],"mappings":";;;AA8DA,sEAqDC;AArEY,QAAA,+BAA+B,GAAG,EAAE,CAAC;AACrC,QAAA,mCAAmC,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAClE,MAAM,6BAA6B,GAAG,KAAM,CAAC;AAc7C,SAAgB,6BAA6B,CAC3C,UAA8B,EAAE;IAEhC,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,uCAA+B,CAAC;IAC/D,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,2CAAmC,CAAC;IACzE,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IAC9C,MAAM,UAAU,GAAG,OAAO,CAAC,mBAAmB,IAAI,6BAA6B,CAAC;IAEhF,MAAM,OAAO,GAAG,IAAI,GAAG,EAAkB,CAAC;IAE1C,SAAS,KAAK,CAAC,OAAe;QAC5B,MAAM,EAAE,GAAG,GAAG,EAAE,CAAC;QACjB,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAEtC,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,OAAO,IAAI,EAAE,EAAE,CAAC;YACxC,wEAAwE;YACxE,yEAAyE;YACzE,sBAAsB;YACtB,IAAI,OAAO,CAAC,IAAI,IAAI,UAAU,EAAE,CAAC;gBAC/B,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC;gBACrC,IAAI,CAAC,MAAM,CAAC,IAAI;oBAAE,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACjD,CAAC;YACD,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,GAAG,QAAQ,EAAE,CAAC,CAAC;YAC3D,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,iBAAiB,EAAE,CAAC,EAAE,CAAC;QACjD,CAAC;QAED,QAAQ,CAAC,KAAK,IAAI,CAAC,CAAC;QACpB,IAAI,QAAQ,CAAC,KAAK,GAAG,KAAK,EAAE,CAAC;YAC3B,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,iBAAiB,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,OAAO,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC;aAC1E,CAAC;QACJ,CAAC;QACD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,iBAAiB,EAAE,CAAC,EAAE,CAAC;IACjD,CAAC;IAED,MAAM,UAAU,GAAmB,CAAC,GAAY,EAAE,GAAa,EAAE,IAAkB,EAAE,EAAE;QACrF,MAAM,OAAO,GAAG,GAAG,CAAC,EAAE,IAAI,GAAG,CAAC,MAAM,EAAE,aAAa,IAAI,SAAS,CAAC;QACjE,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC;QAC/B,IAAI,OAAO,CAAC,OAAO;YAAE,OAAO,IAAI,EAAE,CAAC;QAEnC,GAAG,CAAC,SAAS,CAAC,aAAa,EAAE,MAAM,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC;QAChE,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;YACnB,KAAK,EAAE,yBAAyB;YAChC,iBAAiB,EAAE,mEAAmE;SACvF,CAAC,CAAC;IACL,CAAC,CAAC;IAEF,OAAO;QACL,UAAU;QACV,KAAK;QACL,KAAK,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE;KAC7B,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"rate-limit.js","sourceRoot":"","sources":["../src/rate-limit.ts"],"names":[],"mappings":"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"}
@@ -25,16 +25,24 @@
25
25
  *
26
26
  * ## The matching rule
27
27
  *
28
- * **Exact string match**, with exactly one exception: a registered
29
- * `loopback-http` entry matches a presented URI that differs only in port. That
30
- * is RFC 8252 §7.3, and it is what Claude Code's published Client ID Metadata
31
- * Document requires — it binds an ephemeral loopback port at connect time, so
32
- * the port it will present is not knowable at registration.
28
+ * **Exact string match**, with exactly one exception: a registered entry whose
29
+ * *host* is `localhost` or `127.0.0.1` matches a presented URI that differs only
30
+ * in port. That is RFC 8252 §7.3, and it is what Claude Code's published Client
31
+ * ID Metadata Document requires — it binds an ephemeral loopback port at connect
32
+ * time, so the port it will present is not knowable at registration.
33
33
  *
34
- * The exception is scoped to `loopback-http` and not merely to a loopback
35
- * *host*. A private-use scheme has no TCP port to be ephemeral: the operating
36
- * system routes it by scheme name, so `myapp://localhost/cb` gets the plain
37
- * exact rule even though its host happens to read as loopback.
34
+ * The key is the host and not the `loopback-http` shape, so an
35
+ * `https://localhost/cb` registration gets its port relaxed too. §7.3 is about
36
+ * loopback **http**, so an argument exists for narrowing the exception to `http`
37
+ * alone — but a port on the loopback interface is ephemeral whichever scheme
38
+ * terminates it, and narrowing would break an operator running a local client
39
+ * over TLS for no security gain. That is a decision, not an oversight, and the
40
+ * test table pins it.
41
+ *
42
+ * A private-use scheme is refused the exception even so, because it has no TCP
43
+ * port to be ephemeral: the operating system routes it by scheme name, so
44
+ * `myapp://localhost/cb` gets the plain exact rule even though its host happens
45
+ * to read as loopback.
38
46
  *
39
47
  * The exception lives here, in one function with its own test table, rather
40
48
  * than being threaded through the authorization controller as a special case.
@@ -1 +1 @@
1
- {"version":3,"file":"redirect-uri.d.ts","sourceRoot":"","sources":["../src/redirect-uri.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AAsDH,4DAA4D;AAC5D,MAAM,MAAM,gBAAgB,GAAG,OAAO,GAAG,eAAe,GAAG,aAAa,CAAC;AAEzE;;;;;;GAMG;AACH,MAAM,MAAM,yBAAyB,GACjC;IAAE,QAAQ,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,gBAAgB,CAAC;IAAC,GAAG,EAAE,GAAG,CAAA;CAAE,GACrD;IAAE,QAAQ,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AA6BxC;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,yBAAyB,CAsC5E;AAiBD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CA+C/E;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAE/F;AAED,0DAA0D;AAC1D,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEpD"}
1
+ {"version":3,"file":"redirect-uri.d.ts","sourceRoot":"","sources":["../src/redirect-uri.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AA8DH,4DAA4D;AAC5D,MAAM,MAAM,gBAAgB,GAAG,OAAO,GAAG,eAAe,GAAG,aAAa,CAAC;AAEzE;;;;;;GAMG;AACH,MAAM,MAAM,yBAAyB,GACjC;IAAE,QAAQ,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,gBAAgB,CAAC;IAAC,GAAG,EAAE,GAAG,CAAA;CAAE,GACrD;IAAE,QAAQ,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AA6BxC;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,yBAAyB,CAsC5E;AAiBD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CA+C/E;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAE/F;AAED,0DAA0D;AAC1D,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEpD"}
@@ -26,16 +26,24 @@
26
26
  *
27
27
  * ## The matching rule
28
28
  *
29
- * **Exact string match**, with exactly one exception: a registered
30
- * `loopback-http` entry matches a presented URI that differs only in port. That
31
- * is RFC 8252 §7.3, and it is what Claude Code's published Client ID Metadata
32
- * Document requires — it binds an ephemeral loopback port at connect time, so
33
- * the port it will present is not knowable at registration.
29
+ * **Exact string match**, with exactly one exception: a registered entry whose
30
+ * *host* is `localhost` or `127.0.0.1` matches a presented URI that differs only
31
+ * in port. That is RFC 8252 §7.3, and it is what Claude Code's published Client
32
+ * ID Metadata Document requires — it binds an ephemeral loopback port at connect
33
+ * time, so the port it will present is not knowable at registration.
34
34
  *
35
- * The exception is scoped to `loopback-http` and not merely to a loopback
36
- * *host*. A private-use scheme has no TCP port to be ephemeral: the operating
37
- * system routes it by scheme name, so `myapp://localhost/cb` gets the plain
38
- * exact rule even though its host happens to read as loopback.
35
+ * The key is the host and not the `loopback-http` shape, so an
36
+ * `https://localhost/cb` registration gets its port relaxed too. §7.3 is about
37
+ * loopback **http**, so an argument exists for narrowing the exception to `http`
38
+ * alone — but a port on the loopback interface is ephemeral whichever scheme
39
+ * terminates it, and narrowing would break an operator running a local client
40
+ * over TLS for no security gain. That is a decision, not an oversight, and the
41
+ * test table pins it.
42
+ *
43
+ * A private-use scheme is refused the exception even so, because it has no TCP
44
+ * port to be ephemeral: the operating system routes it by scheme name, so
45
+ * `myapp://localhost/cb` gets the plain exact rule even though its host happens
46
+ * to read as loopback.
39
47
  *
40
48
  * The exception lives here, in one function with its own test table, rather
41
49
  * than being threaded through the authorization controller as a special case.
@@ -50,7 +58,15 @@ exports.classifyRedirectUri = classifyRedirectUri;
50
58
  exports.matchRedirectUri = matchRedirectUri;
51
59
  exports.matchesAnyRedirectUri = matchesAnyRedirectUri;
52
60
  exports.isLoopbackHost = isLoopbackHost;
53
- /** Hosts RFC 8252 §7.3 lets a native app bind an ephemeral port on. */
61
+ /**
62
+ * Hosts a native app may bind an ephemeral port on (RFC 8252 §7.3).
63
+ *
64
+ * The IPv6 loopback `[::1]` is deliberately absent. §7.3 contemplates it, so
65
+ * this refuses a real client — but it refuses it at *registration*, where
66
+ * `validateRedirectUris` calls `http://[::1]:52731/cb` http on a non-loopback
67
+ * host, rather than silently at match time. The reference page says so under
68
+ * "Redirect URIs".
69
+ */
54
70
  const LOOPBACK_HOSTS = new Set(['localhost', '127.0.0.1']);
55
71
  /**
56
72
  * Schemes a private-use redirect may not claim, on three separate grounds.
@@ -1 +1 @@
1
- {"version":3,"file":"redirect-uri.js","sourceRoot":"","sources":["../src/redirect-uri.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"redirect-uri.js","sourceRoot":"","sources":["../src/redirect-uri.ts"],"names":[],"mappings":"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"}
@@ -33,6 +33,16 @@ export interface RegistrationHandlerDeps {
33
33
  *
34
34
  * `client_secret` is deliberately absent rather than null: this server issues
35
35
  * only public clients, and a client that found the field would try to use it.
36
+ *
37
+ * `registration_access_token` and `registration_client_uri` are absent for the
38
+ * same reason one step further out. They are RFC 7592's credential and address
39
+ * for managing a registration afterwards, and this server implements no such
40
+ * surface — `PUT`/`DELETE /oauth/register/:client_id` are unmounted by decision,
41
+ * not by omission. Emitting either field would hand a client a credential and a
42
+ * URL that resolve to a 404, which is worse than saying nothing: a client that
43
+ * reads them plans to re-register on failure rather than to re-register at all.
44
+ * If that decision is ever reversed, these two fields and the routes ship
45
+ * together or neither ships.
36
46
  */
37
47
  export declare function toRegistrationResponse(client: OauthClient): Record<string, unknown>;
38
48
  export declare function createRegistrationHandlers(deps: RegistrationHandlerDeps): {
@@ -1 +1 @@
1
- {"version":3,"file":"registration-controller.d.ts","sourceRoot":"","sources":["../src/registration-controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAQ,KAAK,cAAc,EAAE,MAAM,SAAS,CAAC;AAE5D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAE1E,OAAO,EAAiC,KAAK,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACzF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,MAAM,WAAW,uBAAuB;IACtC,cAAc,EAAE,qBAAqB,CAAC;CACvC;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAkBnF;AAED,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,uBAAuB,GAAG;IACzE,QAAQ,EAAE,cAAc,CAAC;CAC1B,CA6BA;AAED,MAAM,WAAW,yBAA0B,SAAQ,uBAAuB;IACxE;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,kBAAkB,GAAG,KAAK,CAAC;IACvC,oEAAoE;IACpE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,yBAAyB,GAAG,MAAM,CAYnF"}
1
+ {"version":3,"file":"registration-controller.d.ts","sourceRoot":"","sources":["../src/registration-controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAQ,KAAK,cAAc,EAAE,MAAM,SAAS,CAAC;AAE5D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAE1E,OAAO,EAAiC,KAAK,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACzF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,MAAM,WAAW,uBAAuB;IACtC,cAAc,EAAE,qBAAqB,CAAC;CACvC;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAkBnF;AAED,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,uBAAuB,GAAG;IACzE,QAAQ,EAAE,cAAc,CAAC;CAC1B,CA6BA;AAED,MAAM,WAAW,yBAA0B,SAAQ,uBAAuB;IACxE;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,kBAAkB,GAAG,KAAK,CAAC;IACvC,oEAAoE;IACpE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,yBAAyB,GAAG,MAAM,CAYnF"}
@@ -11,6 +11,16 @@ const rate_limit_js_1 = require("./rate-limit.js");
11
11
  *
12
12
  * `client_secret` is deliberately absent rather than null: this server issues
13
13
  * only public clients, and a client that found the field would try to use it.
14
+ *
15
+ * `registration_access_token` and `registration_client_uri` are absent for the
16
+ * same reason one step further out. They are RFC 7592's credential and address
17
+ * for managing a registration afterwards, and this server implements no such
18
+ * surface — `PUT`/`DELETE /oauth/register/:client_id` are unmounted by decision,
19
+ * not by omission. Emitting either field would hand a client a credential and a
20
+ * URL that resolve to a 404, which is worse than saying nothing: a client that
21
+ * reads them plans to re-register on failure rather than to re-register at all.
22
+ * If that decision is ever reversed, these two fields and the routes ship
23
+ * together or neither ships.
14
24
  */
15
25
  function toRegistrationResponse(client) {
16
26
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"registration-controller.js","sourceRoot":"","sources":["../src/registration-controller.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"registration-controller.js","sourceRoot":"","sources":["../src/registration-controller.ts"],"names":[],"mappings":"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"}
@@ -15,5 +15,11 @@ import type { OauthClient } from './types.js';
15
15
  * copy of the check is the one that would forget suspension, and then a retired
16
16
  * client could still reach one of the two endpoints.
17
17
  */
18
- export declare function resolveRequestClient(clientRegistry: ClientRegistryService, body: unknown): Promise<OauthClient>;
18
+ /** Where a refusal to identify the client is reported, and under which name. */
19
+ export interface RequestClientReport {
20
+ /** The endpoint as an operator would search for it: `POST /oauth/token`. */
21
+ endpoint: string;
22
+ warn(message: string): void;
23
+ }
24
+ export declare function resolveRequestClient(clientRegistry: ClientRegistryService, body: unknown, report: RequestClientReport): Promise<OauthClient>;
19
25
  //# sourceMappingURL=request-client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"request-client.d.ts","sourceRoot":"","sources":["../src/request-client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAE1E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,oBAAoB,CACxC,cAAc,EAAE,qBAAqB,EACrC,IAAI,EAAE,OAAO,GACZ,OAAO,CAAC,WAAW,CAAC,CAUtB"}
1
+ {"version":3,"file":"request-client.d.ts","sourceRoot":"","sources":["../src/request-client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAE1E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C;;;;;;;;;;;;;;GAcG;AAEH,gFAAgF;AAChF,MAAM,WAAW,mBAAmB;IAClC,4EAA4E;IAC5E,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAkCD,wBAAsB,oBAAoB,CACxC,cAAc,EAAE,qBAAqB,EACrC,IAAI,EAAE,OAAO,EACb,MAAM,EAAE,mBAAmB,GAC1B,OAAO,CAAC,WAAW,CAAC,CAetB"}