@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.
- package/capability.json +14 -2
- package/dist/authorization-code-service.d.ts +40 -11
- package/dist/authorization-code-service.d.ts.map +1 -1
- package/dist/authorization-code-service.js +93 -41
- package/dist/authorization-code-service.js.map +1 -1
- package/dist/bearer.d.ts +27 -4
- package/dist/bearer.d.ts.map +1 -1
- package/dist/bearer.js +4 -4
- package/dist/bearer.js.map +1 -1
- package/dist/client-prune.d.ts +102 -0
- package/dist/client-prune.d.ts.map +1 -0
- package/dist/client-prune.js +51 -0
- package/dist/client-prune.js.map +1 -0
- package/dist/client-registry-service.d.ts +85 -8
- package/dist/client-registry-service.d.ts.map +1 -1
- package/dist/client-registry-service.js +267 -64
- package/dist/client-registry-service.js.map +1 -1
- package/dist/config.d.ts +6 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +1 -0
- package/dist/config.js.map +1 -1
- package/dist/connections-controller.js +1 -1
- package/dist/connections-controller.js.map +1 -1
- package/dist/consent-controller.d.ts +80 -6
- package/dist/consent-controller.d.ts.map +1 -1
- package/dist/consent-controller.js +134 -18
- package/dist/consent-controller.js.map +1 -1
- package/dist/discovery-controller.d.ts +2 -1
- package/dist/discovery-controller.d.ts.map +1 -1
- package/dist/discovery-controller.js +14 -4
- package/dist/discovery-controller.js.map +1 -1
- package/dist/discovery.d.ts +26 -0
- package/dist/discovery.d.ts.map +1 -1
- package/dist/discovery.js +55 -1
- package/dist/discovery.js.map +1 -1
- package/dist/errors.d.ts +38 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +59 -0
- package/dist/errors.js.map +1 -1
- package/dist/grant-service.d.ts +11 -4
- package/dist/grant-service.d.ts.map +1 -1
- package/dist/grant-service.js +6 -3
- package/dist/grant-service.js.map +1 -1
- package/dist/index.d.ts +10 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -3
- package/dist/index.js.map +1 -1
- package/dist/metadata-document.d.ts +22 -0
- package/dist/metadata-document.d.ts.map +1 -1
- package/dist/metadata-document.js +44 -2
- package/dist/metadata-document.js.map +1 -1
- package/dist/outbound-target.d.ts +48 -0
- package/dist/outbound-target.d.ts.map +1 -0
- package/dist/outbound-target.js +211 -0
- package/dist/outbound-target.js.map +1 -0
- package/dist/rate-limit.d.ts +53 -11
- package/dist/rate-limit.d.ts.map +1 -1
- package/dist/rate-limit.js +27 -4
- package/dist/rate-limit.js.map +1 -1
- package/dist/redirect-uri.d.ts +17 -9
- package/dist/redirect-uri.d.ts.map +1 -1
- package/dist/redirect-uri.js +26 -10
- package/dist/redirect-uri.js.map +1 -1
- package/dist/registration-controller.d.ts +10 -0
- package/dist/registration-controller.d.ts.map +1 -1
- package/dist/registration-controller.js +10 -0
- package/dist/registration-controller.js.map +1 -1
- package/dist/request-client.d.ts +7 -1
- package/dist/request-client.d.ts.map +1 -1
- package/dist/request-client.js +31 -13
- package/dist/request-client.js.map +1 -1
- package/dist/revocation-controller.d.ts +5 -0
- package/dist/revocation-controller.d.ts.map +1 -1
- package/dist/revocation-controller.js +5 -1
- package/dist/revocation-controller.js.map +1 -1
- package/dist/same-site.d.ts +54 -0
- package/dist/same-site.d.ts.map +1 -0
- package/dist/same-site.js +124 -0
- package/dist/same-site.js.map +1 -0
- package/dist/token-controller.d.ts +26 -0
- package/dist/token-controller.d.ts.map +1 -1
- package/dist/token-controller.js +44 -19
- package/dist/token-controller.js.map +1 -1
- package/dist/types.d.ts +4 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -2
- package/scaffold/reference/oauth-server.ref.md +359 -11
- package/scaffold/src/middleware/oauth-server.ts +33 -17
- package/scaffold/src/scripts/prune-oauth-clients.ts +86 -0
- package/scaffold/src/services/oauth-server.service.ts +24 -0
- package/scaffold/views/oauth-consent-error.hbs +10 -3
package/dist/request-client.js
CHANGED
|
@@ -4,24 +4,42 @@ exports.resolveRequestClient = resolveRequestClient;
|
|
|
4
4
|
const body_field_js_1 = require("./body-field.js");
|
|
5
5
|
const oauth_error_js_1 = require("./oauth-error.js");
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
7
|
+
* The fields a client can authenticate itself with in a request body.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
*
|
|
9
|
+
* `client_id` is the only one read. The other two are RFC 7523's signed
|
|
10
|
+
* assertion, which a client whose document declared `private_key_jwt` may send
|
|
11
|
+
* and may send *in place of* `client_id`.
|
|
12
|
+
*/
|
|
13
|
+
const CLIENT_AUTH_FIELDS = ['client_id', 'client_assertion', 'client_assertion_type'];
|
|
14
|
+
/**
|
|
15
|
+
* Say, to the operator, which of those fields a refused request carried.
|
|
16
16
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
17
|
+
* Names only, never values. A client registered from a `private_key_jwt`
|
|
18
|
+
* document is stored as a public client (see `parseAuthMethod`), and whether it
|
|
19
|
+
* then sends `client_id` at all is a fact about that client which nobody can
|
|
20
|
+
* read off this code. When it does not, the caller is told `client_id is
|
|
21
|
+
* required` and the person connecting sees a failure with no cause; this line
|
|
22
|
+
* is what lets the operator tell "sent an assertion instead" from "sent
|
|
23
|
+
* nothing". The assertion is a signed credential and a `client_id` may be a
|
|
24
|
+
* URL somebody else chose, so neither is repeated here.
|
|
20
25
|
*/
|
|
21
|
-
|
|
22
|
-
const
|
|
26
|
+
function reportUnidentified(report, body, why) {
|
|
27
|
+
const carried = CLIENT_AUTH_FIELDS.filter((name) => (0, body_field_js_1.field)(body, name) !== undefined);
|
|
28
|
+
report.warn(`${report.endpoint} refused: ${why}. The request ` +
|
|
29
|
+
(carried.length > 0
|
|
30
|
+
? `carried ${carried.join(', ')}`
|
|
31
|
+
: `carried none of ${CLIENT_AUTH_FIELDS.join(', ')}`) +
|
|
32
|
+
`.`);
|
|
33
|
+
}
|
|
34
|
+
async function resolveRequestClient(clientRegistry, body, report) {
|
|
35
|
+
const clientId = (0, body_field_js_1.field)(body, 'client_id');
|
|
36
|
+
if (clientId === undefined) {
|
|
37
|
+
reportUnidentified(report, body, 'no client_id in the request');
|
|
38
|
+
throw new oauth_error_js_1.OAuthError('invalid_request', 'client_id is required');
|
|
39
|
+
}
|
|
23
40
|
const client = await clientRegistry.findByClientId(clientId);
|
|
24
41
|
if (!client) {
|
|
42
|
+
reportUnidentified(report, body, 'client_id names no registered client');
|
|
25
43
|
throw new oauth_error_js_1.OAuthError('invalid_client', 'unknown client_id');
|
|
26
44
|
}
|
|
27
45
|
if (client.status !== 'enabled') {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request-client.js","sourceRoot":"","sources":["../src/request-client.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"request-client.js","sourceRoot":"","sources":["../src/request-client.ts"],"names":[],"mappings":";;AA4DA,oDAmBC;AA/ED,mDAAwC;AAExC,qDAA8C;AA0B9C;;;;;;GAMG;AACH,MAAM,kBAAkB,GAAG,CAAC,WAAW,EAAE,kBAAkB,EAAE,uBAAuB,CAAU,CAAC;AAE/F;;;;;;;;;;;GAWG;AACH,SAAS,kBAAkB,CAAC,MAA2B,EAAE,IAAa,EAAE,GAAW;IACjF,MAAM,OAAO,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAA,qBAAK,EAAC,IAAI,EAAE,IAAI,CAAC,KAAK,SAAS,CAAC,CAAC;IACrF,MAAM,CAAC,IAAI,CACT,GAAG,MAAM,CAAC,QAAQ,aAAa,GAAG,gBAAgB;QAChD,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC;YACjB,CAAC,CAAC,WAAW,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;YACjC,CAAC,CAAC,mBAAmB,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACvD,GAAG,CACN,CAAC;AACJ,CAAC;AAEM,KAAK,UAAU,oBAAoB,CACxC,cAAqC,EACrC,IAAa,EACb,MAA2B;IAE3B,MAAM,QAAQ,GAAG,IAAA,qBAAK,EAAC,IAAI,EAAE,WAAW,CAAC,CAAC;IAC1C,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,kBAAkB,CAAC,MAAM,EAAE,IAAI,EAAE,6BAA6B,CAAC,CAAC;QAChE,MAAM,IAAI,2BAAU,CAAC,iBAAiB,EAAE,uBAAuB,CAAC,CAAC;IACnE,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;IAC7D,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,kBAAkB,CAAC,MAAM,EAAE,IAAI,EAAE,sCAAsC,CAAC,CAAC;QACzE,MAAM,IAAI,2BAAU,CAAC,gBAAgB,EAAE,mBAAmB,CAAC,CAAC;IAC9D,CAAC;IACD,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QAChC,MAAM,IAAI,2BAAU,CAAC,gBAAgB,EAAE,0BAA0B,CAAC,CAAC;IACrE,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -6,6 +6,11 @@ export interface RevocationHandlerDeps {
|
|
|
6
6
|
clientRegistry: ClientRegistryService;
|
|
7
7
|
tokenService: TokenService;
|
|
8
8
|
revocationService: RevocationService;
|
|
9
|
+
/**
|
|
10
|
+
* Where a request refused for an unidentifiable client is reported. Defaults
|
|
11
|
+
* to `console.warn`. See `resolveRequestClient` for what the line says.
|
|
12
|
+
*/
|
|
13
|
+
warn?(message: string): void;
|
|
9
14
|
}
|
|
10
15
|
export interface RevocationHandlers {
|
|
11
16
|
revoke: RequestHandler;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"revocation-controller.d.ts","sourceRoot":"","sources":["../src/revocation-controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAkC,KAAK,cAAc,EAAiB,MAAM,SAAS,CAAC;AAGrG,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAG1E,OAAO,EAAqB,KAAK,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AACpF,OAAO,EAIL,KAAK,YAAY,EAClB,MAAM,oBAAoB,CAAC;AAwF5B,MAAM,WAAW,qBAAqB;IACpC,cAAc,EAAE,qBAAqB,CAAC;IACtC,YAAY,EAAE,YAAY,CAAC;IAC3B,iBAAiB,EAAE,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"revocation-controller.d.ts","sourceRoot":"","sources":["../src/revocation-controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAkC,KAAK,cAAc,EAAiB,MAAM,SAAS,CAAC;AAGrG,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAG1E,OAAO,EAAqB,KAAK,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AACpF,OAAO,EAIL,KAAK,YAAY,EAClB,MAAM,oBAAoB,CAAC;AAwF5B,MAAM,WAAW,qBAAqB;IACpC,cAAc,EAAE,qBAAqB,CAAC;IACtC,YAAY,EAAE,YAAY,CAAC;IAC3B,iBAAiB,EAAE,iBAAiB,CAAC;IACrC;;;OAGG;IACH,IAAI,CAAC,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,cAAc,CAAC;CACxB;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,qBAAqB,GAAG,kBAAkB,CAqFxF;AAED,MAAM,WAAW,uBAAwB,SAAQ,qBAAqB;IACpE,wEAAwE;IACxE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,uBAAuB,GAAG,MAAM,CAa/E"}
|
|
@@ -94,6 +94,7 @@ const DOMAIN_BY_HINT = new Map([
|
|
|
94
94
|
]);
|
|
95
95
|
function createRevocationHandlers(deps) {
|
|
96
96
|
const { clientRegistry, tokenService, revocationService } = deps;
|
|
97
|
+
const warn = deps.warn ?? ((message) => console.warn(`[cap-oauth-server] ${message}`));
|
|
97
98
|
/** The hint's domain first, then the other. See the header: advisory only. */
|
|
98
99
|
function searchOrder(hint) {
|
|
99
100
|
const hinted = hint === undefined ? undefined : DOMAIN_BY_HINT.get(hint);
|
|
@@ -127,7 +128,10 @@ function createRevocationHandlers(deps) {
|
|
|
127
128
|
try {
|
|
128
129
|
const presented = (0, body_field_js_1.required)(req.body, 'token');
|
|
129
130
|
const order = searchOrder((0, body_field_js_1.field)(req.body, 'token_type_hint'));
|
|
130
|
-
const client = await (0, request_client_js_1.resolveRequestClient)(clientRegistry, req.body
|
|
131
|
+
const client = await (0, request_client_js_1.resolveRequestClient)(clientRegistry, req.body, {
|
|
132
|
+
endpoint: 'POST /oauth/revoke',
|
|
133
|
+
warn,
|
|
134
|
+
});
|
|
131
135
|
// The client prefix is readable off the token before any lookup, so a
|
|
132
136
|
// token belonging to somebody else is dropped without touching the
|
|
133
137
|
// database — and, per §2.2, without being distinguishable from success.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"revocation-controller.js","sourceRoot":"","sources":["../src/revocation-controller.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"revocation-controller.js","sourceRoot":"","sources":["../src/revocation-controller.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Did this request come from a page this server served?
|
|
3
|
+
*
|
|
4
|
+
* ## Why the consent form needs its own answer
|
|
5
|
+
*
|
|
6
|
+
* `POST /oauth/authorize` mints an authorization code, and the only credential
|
|
7
|
+
* it needs is the session cookie the browser attaches by itself. That is the
|
|
8
|
+
* exact shape cross-site request forgery exploits: an attacker's page
|
|
9
|
+
* auto-submits the form, the victim's browser attaches the cookie, and a code
|
|
10
|
+
* for the victim's account is redirected to a `redirect_uri` the attacker
|
|
11
|
+
* registered.
|
|
12
|
+
*
|
|
13
|
+
* PKCE does not help. It binds a code to whoever *asked* for it, and here the
|
|
14
|
+
* attacker is the client — they generate the challenge and hold the verifier.
|
|
15
|
+
* `state` does not help either: it is the client's CSRF token, echoed back
|
|
16
|
+
* untouched, and on this attack the attacker is the one who chose it. Neither
|
|
17
|
+
* mechanism was ever pointed at this direction.
|
|
18
|
+
*
|
|
19
|
+
* What was holding the line was a browser default — an unlabelled cookie is
|
|
20
|
+
* treated as `SameSite=Lax`, and Lax is not sent on a cross-site POST. The
|
|
21
|
+
* cookie is now labelled explicitly (see `createConsentHandlers`), but a
|
|
22
|
+
* defence that lives entirely in the user agent is one this server cannot
|
|
23
|
+
* assert, cannot test, and does not own. This is the server's own answer.
|
|
24
|
+
*
|
|
25
|
+
* ## What it reads, and why that is enough
|
|
26
|
+
*
|
|
27
|
+
* `Origin` and `Sec-Fetch-Site` are both **forbidden header names**: page
|
|
28
|
+
* script cannot set or remove either one, so on a form post from a hostile
|
|
29
|
+
* page the browser attaches them truthfully. An attacker can no more suppress
|
|
30
|
+
* them than they can read the cookie.
|
|
31
|
+
*
|
|
32
|
+
* A request carrying neither is accepted. It is not a browser, or it is one
|
|
33
|
+
* too old to label anything — and a forgery needs a browser, because a browser
|
|
34
|
+
* is the only thing that will attach somebody else's cookie. Refusing here
|
|
35
|
+
* would break every non-browser caller and buy nothing.
|
|
36
|
+
*/
|
|
37
|
+
/** The parts of a request this check reads. `express.Request` satisfies it. */
|
|
38
|
+
export interface SameSiteRequest {
|
|
39
|
+
headers: Record<string, string | string[] | undefined>;
|
|
40
|
+
/** Express's resolved hostname — `X-Forwarded-Host` under `trust proxy`. */
|
|
41
|
+
hostname?: string;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Whether this request may be treated as originating from this site.
|
|
45
|
+
*
|
|
46
|
+
* `allowedOrigins` are origins the application declares as its own, matched
|
|
47
|
+
* exactly and before anything else. They exist for a deployment this function
|
|
48
|
+
* cannot work out on its own — a proxy that rewrites `Host` without setting
|
|
49
|
+
* `X-Forwarded-Host`, or a consent page deliberately served from a sibling
|
|
50
|
+
* host. Naming one is a decision about what counts as this application, so it
|
|
51
|
+
* is the application's to make and nothing here guesses at it.
|
|
52
|
+
*/
|
|
53
|
+
export declare function isSameSiteRequest(req: SameSiteRequest, allowedOrigins?: readonly string[]): boolean;
|
|
54
|
+
//# sourceMappingURL=same-site.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"same-site.d.ts","sourceRoot":"","sources":["../src/same-site.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH,+EAA+E;AAC/E,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC;IACvD,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AA6DD;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,eAAe,EACpB,cAAc,GAAE,SAAS,MAAM,EAAO,GACrC,OAAO,CAcT"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Did this request come from a page this server served?
|
|
4
|
+
*
|
|
5
|
+
* ## Why the consent form needs its own answer
|
|
6
|
+
*
|
|
7
|
+
* `POST /oauth/authorize` mints an authorization code, and the only credential
|
|
8
|
+
* it needs is the session cookie the browser attaches by itself. That is the
|
|
9
|
+
* exact shape cross-site request forgery exploits: an attacker's page
|
|
10
|
+
* auto-submits the form, the victim's browser attaches the cookie, and a code
|
|
11
|
+
* for the victim's account is redirected to a `redirect_uri` the attacker
|
|
12
|
+
* registered.
|
|
13
|
+
*
|
|
14
|
+
* PKCE does not help. It binds a code to whoever *asked* for it, and here the
|
|
15
|
+
* attacker is the client — they generate the challenge and hold the verifier.
|
|
16
|
+
* `state` does not help either: it is the client's CSRF token, echoed back
|
|
17
|
+
* untouched, and on this attack the attacker is the one who chose it. Neither
|
|
18
|
+
* mechanism was ever pointed at this direction.
|
|
19
|
+
*
|
|
20
|
+
* What was holding the line was a browser default — an unlabelled cookie is
|
|
21
|
+
* treated as `SameSite=Lax`, and Lax is not sent on a cross-site POST. The
|
|
22
|
+
* cookie is now labelled explicitly (see `createConsentHandlers`), but a
|
|
23
|
+
* defence that lives entirely in the user agent is one this server cannot
|
|
24
|
+
* assert, cannot test, and does not own. This is the server's own answer.
|
|
25
|
+
*
|
|
26
|
+
* ## What it reads, and why that is enough
|
|
27
|
+
*
|
|
28
|
+
* `Origin` and `Sec-Fetch-Site` are both **forbidden header names**: page
|
|
29
|
+
* script cannot set or remove either one, so on a form post from a hostile
|
|
30
|
+
* page the browser attaches them truthfully. An attacker can no more suppress
|
|
31
|
+
* them than they can read the cookie.
|
|
32
|
+
*
|
|
33
|
+
* A request carrying neither is accepted. It is not a browser, or it is one
|
|
34
|
+
* too old to label anything — and a forgery needs a browser, because a browser
|
|
35
|
+
* is the only thing that will attach somebody else's cookie. Refusing here
|
|
36
|
+
* would break every non-browser caller and buy nothing.
|
|
37
|
+
*/
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.isSameSiteRequest = isSameSiteRequest;
|
|
40
|
+
function headerOf(req, name) {
|
|
41
|
+
const value = req.headers?.[name];
|
|
42
|
+
const first = Array.isArray(value) ? value[0] : value;
|
|
43
|
+
return typeof first === 'string' && first !== '' ? first : undefined;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Whether `origin` names the host this request arrived on.
|
|
47
|
+
*
|
|
48
|
+
* The comparison is on host, not on the whole origin: the scheme is the
|
|
49
|
+
* deployment's business — a boop application in development is served over
|
|
50
|
+
* http — and a wrong scheme on the right host means a network attacker, which
|
|
51
|
+
* is `Secure` on the cookie rather than this function.
|
|
52
|
+
*
|
|
53
|
+
* `Host` is checked first and including the port, because a different port is a
|
|
54
|
+
* different origin and on a shared development host it is a different
|
|
55
|
+
* application altogether.
|
|
56
|
+
*
|
|
57
|
+
* The fallback to `req.hostname` is for a deployment behind a proxy that
|
|
58
|
+
* rewrites `Host`: with `trust proxy` set, express resolves
|
|
59
|
+
* `X-Forwarded-Host` there, which is the public name the browser used. It
|
|
60
|
+
* compares hostnames only, because `X-Forwarded-Host` frequently carries no
|
|
61
|
+
* port — and it is reached **only when express resolved a different name than
|
|
62
|
+
* `Host` carried**, i.e. when a proxy really did rewrite something. Otherwise
|
|
63
|
+
* an unproxied request whose port did not match would be rescued by a
|
|
64
|
+
* comparison that ignores the port, and the check above would mean nothing.
|
|
65
|
+
*/
|
|
66
|
+
function matchesOwnHost(origin, req) {
|
|
67
|
+
let url;
|
|
68
|
+
try {
|
|
69
|
+
url = new URL(origin);
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
// `null`, an empty string, anything malformed. Not our host.
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
const host = headerOf(req, 'host');
|
|
76
|
+
const hostname = typeof req.hostname === 'string' ? req.hostname : undefined;
|
|
77
|
+
if (host !== undefined) {
|
|
78
|
+
if (url.host.toLowerCase() === host.toLowerCase())
|
|
79
|
+
return true;
|
|
80
|
+
if (hostname === undefined || hostname === '')
|
|
81
|
+
return false;
|
|
82
|
+
// Nothing was rewritten — the mismatch is real, and it is the port.
|
|
83
|
+
if (hostname.toLowerCase() === hostnameOf(host))
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
if (hostname === undefined || hostname === '')
|
|
87
|
+
return false;
|
|
88
|
+
return url.hostname.toLowerCase() === hostname.toLowerCase();
|
|
89
|
+
}
|
|
90
|
+
/** The host-header's name without its port. `undefined` if it will not parse. */
|
|
91
|
+
function hostnameOf(host) {
|
|
92
|
+
try {
|
|
93
|
+
return new URL(`http://${host}`).hostname.toLowerCase();
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
return undefined;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Whether this request may be treated as originating from this site.
|
|
101
|
+
*
|
|
102
|
+
* `allowedOrigins` are origins the application declares as its own, matched
|
|
103
|
+
* exactly and before anything else. They exist for a deployment this function
|
|
104
|
+
* cannot work out on its own — a proxy that rewrites `Host` without setting
|
|
105
|
+
* `X-Forwarded-Host`, or a consent page deliberately served from a sibling
|
|
106
|
+
* host. Naming one is a decision about what counts as this application, so it
|
|
107
|
+
* is the application's to make and nothing here guesses at it.
|
|
108
|
+
*/
|
|
109
|
+
function isSameSiteRequest(req, allowedOrigins = []) {
|
|
110
|
+
const origin = headerOf(req, 'origin');
|
|
111
|
+
if (origin !== undefined && allowedOrigins.includes(origin))
|
|
112
|
+
return true;
|
|
113
|
+
// Refuse on any label that says this did not come from us, whether or not an
|
|
114
|
+
// Origin is present. `same-site` is refused alongside `cross-site`: this form
|
|
115
|
+
// only ever posts to the page that rendered it, so a sibling subdomain is as
|
|
116
|
+
// much a stranger here as anywhere else.
|
|
117
|
+
const site = headerOf(req, 'sec-fetch-site');
|
|
118
|
+
if (site !== undefined && site !== 'same-origin' && site !== 'none')
|
|
119
|
+
return false;
|
|
120
|
+
if (origin !== undefined)
|
|
121
|
+
return matchesOwnHost(origin, req);
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=same-site.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"same-site.js","sourceRoot":"","sources":["../src/same-site.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;;AA8EH,8CAiBC;AAtFD,SAAS,QAAQ,CAAC,GAAoB,EAAE,IAAY;IAClD,MAAM,KAAK,GAAG,GAAG,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,CAAC;IAClC,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IACtD,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AACvE,CAAC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,SAAS,cAAc,CAAC,MAAc,EAAE,GAAoB;IAC1D,IAAI,GAAQ,CAAC;IACb,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC;IACxB,CAAC;IAAC,MAAM,CAAC;QACP,6DAA6D;QAC7D,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IACnC,MAAM,QAAQ,GAAG,OAAO,GAAG,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC;IAE7E,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,IAAI,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,IAAI,CAAC,WAAW,EAAE;YAAE,OAAO,IAAI,CAAC;QAC/D,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,EAAE;YAAE,OAAO,KAAK,CAAC;QAC5D,oEAAoE;QACpE,IAAI,QAAQ,CAAC,WAAW,EAAE,KAAK,UAAU,CAAC,IAAI,CAAC;YAAE,OAAO,KAAK,CAAC;IAChE,CAAC;IAED,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,EAAE;QAAE,OAAO,KAAK,CAAC;IAC5D,OAAO,GAAG,CAAC,QAAQ,CAAC,WAAW,EAAE,KAAK,QAAQ,CAAC,WAAW,EAAE,CAAC;AAC/D,CAAC;AAED,iFAAiF;AACjF,SAAS,UAAU,CAAC,IAAY;IAC9B,IAAI,CAAC;QACH,OAAO,IAAI,GAAG,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC;IAC1D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED;;;;;;;;;GASG;AACH,SAAgB,iBAAiB,CAC/B,GAAoB,EACpB,iBAAoC,EAAE;IAEtC,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;IACvC,IAAI,MAAM,KAAK,SAAS,IAAI,cAAc,CAAC,QAAQ,CAAC,MAAM,CAAC;QAAE,OAAO,IAAI,CAAC;IAEzE,6EAA6E;IAC7E,8EAA8E;IAC9E,6EAA6E;IAC7E,yCAAyC;IACzC,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAC;IAC7C,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,aAAa,IAAI,IAAI,KAAK,MAAM;QAAE,OAAO,KAAK,CAAC;IAElF,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,cAAc,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAE7D,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -41,6 +41,27 @@ import { type TokenService } from './token-service.js';
|
|
|
41
41
|
* Superseded rows are bounded: they age out under the same
|
|
42
42
|
* `createdAt + refresh ttl` rule as any other token, and revoking the grant
|
|
43
43
|
* end-dates all of them at once.
|
|
44
|
+
*
|
|
45
|
+
* ## And so does replay of an authorization code, for the same reason
|
|
46
|
+
*
|
|
47
|
+
* RFC 6749 §4.1.2 and §10.5 ask for both halves: deny the replayed code, AND
|
|
48
|
+
* revoke the tokens already issued from it. Denying alone is the worse of the
|
|
49
|
+
* two failures, because the redemption that succeeded was the ATTACKER'S. A
|
|
50
|
+
* code stolen off a loopback callback and raced to this endpoint leaves the
|
|
51
|
+
* attacker holding a working token pair, while the legitimate client's
|
|
52
|
+
* redemption comes back as a generic `invalid_grant` that reads exactly like an
|
|
53
|
+
* ordinary expiry — nobody is told anything, and nothing is undone.
|
|
54
|
+
*
|
|
55
|
+
* So a second redemption of one code ends the grant with `reason:
|
|
56
|
+
* "code_replay"` and sweeps its tokens, the same write `refresh_reuse` makes.
|
|
57
|
+
* The grant ended is the one belonging to the client the CODE was issued to,
|
|
58
|
+
* which `redeem` reports back — never the `client_id` the replay happened to
|
|
59
|
+
* carry, or a stolen code would be a way to disconnect a bystander.
|
|
60
|
+
*
|
|
61
|
+
* The one honest limit: a replay arriving after the code's own 120 seconds
|
|
62
|
+
* resolves to nobody, so there is no grant to reach and the answer is a bare
|
|
63
|
+
* `invalid_grant`. Every replay that is a race — which is every replay that
|
|
64
|
+
* matters — arrives well inside that window.
|
|
44
65
|
*/
|
|
45
66
|
/** RFC 6749 §5.1's success body. */
|
|
46
67
|
export interface TokenResponse {
|
|
@@ -55,6 +76,11 @@ export interface TokenHandlerDeps {
|
|
|
55
76
|
tokenService: TokenService;
|
|
56
77
|
grantService: GrantService;
|
|
57
78
|
authorizationCodeService: AuthorizationCodeService;
|
|
79
|
+
/**
|
|
80
|
+
* Where a request refused for an unidentifiable client is reported. Defaults
|
|
81
|
+
* to `console.warn`. See `resolveRequestClient` for what the line says.
|
|
82
|
+
*/
|
|
83
|
+
warn?(message: string): void;
|
|
58
84
|
}
|
|
59
85
|
/** The scope that earns a refresh token, per the discovery document. */
|
|
60
86
|
export declare const OFFLINE_ACCESS_SCOPE = "offline_access";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"token-controller.d.ts","sourceRoot":"","sources":["../src/token-controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAkC,KAAK,cAAc,EAAiB,MAAM,SAAS,CAAC;AAErG,OAAO,KAAK,EAAE,wBAAwB,EAAiB,MAAM,iCAAiC,CAAC;AAE/F,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAC1E,OAAO,KAAK,EAAE,YAAY,EAAoB,MAAM,oBAAoB,CAAC;AAIzE,OAAO,EAGL,KAAK,YAAY,EAClB,MAAM,oBAAoB,CAAC;AAI5B
|
|
1
|
+
{"version":3,"file":"token-controller.d.ts","sourceRoot":"","sources":["../src/token-controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAkC,KAAK,cAAc,EAAiB,MAAM,SAAS,CAAC;AAErG,OAAO,KAAK,EAAE,wBAAwB,EAAiB,MAAM,iCAAiC,CAAC;AAE/F,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAC1E,OAAO,KAAK,EAAE,YAAY,EAAoB,MAAM,oBAAoB,CAAC;AAIzE,OAAO,EAGL,KAAK,YAAY,EAClB,MAAM,oBAAoB,CAAC;AAI5B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2DG;AAEH,oCAAoC;AACpC,MAAM,WAAW,aAAa;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,QAAQ,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,gBAAgB;IAC/B,cAAc,EAAE,qBAAqB,CAAC;IACtC,YAAY,EAAE,YAAY,CAAC;IAC3B,YAAY,EAAE,YAAY,CAAC;IAC3B,wBAAwB,EAAE,wBAAwB,CAAC;IACnD;;;OAGG;IACH,IAAI,CAAC,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED,wEAAwE;AACxE,eAAO,MAAM,oBAAoB,mBAAmB,CAAC;AAYrD,iFAAiF;AACjF,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,EAAE,CAG7D;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,gBAAgB,GAAG;IAAE,KAAK,EAAE,cAAc,CAAA;CAAE,CA4NrF;AAED,MAAM,WAAW,kBAAmB,SAAQ,gBAAgB;IAC1D,0EAA0E;IAC1E,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,kBAAkB,GAAG,MAAM,CAarE"}
|
package/dist/token-controller.js
CHANGED
|
@@ -16,7 +16,7 @@ exports.OFFLINE_ACCESS_SCOPE = 'offline_access';
|
|
|
16
16
|
/** Redemption failures, mapped to the wire. */
|
|
17
17
|
const REDEEM_ERROR = {
|
|
18
18
|
unknown_code: 'the authorization code is unknown, expired or already used',
|
|
19
|
-
already_redeemed: '
|
|
19
|
+
already_redeemed: 'this authorization code has already been redeemed; anything it granted has been revoked',
|
|
20
20
|
expired: 'the authorization code has expired',
|
|
21
21
|
client_mismatch: 'the authorization code was issued to a different client',
|
|
22
22
|
redirect_uri_mismatch: 'redirect_uri does not match the one the code was issued for',
|
|
@@ -30,7 +30,8 @@ function parseScopes(raw) {
|
|
|
30
30
|
function createTokenHandlers(deps) {
|
|
31
31
|
const { clientRegistry, tokenService, grantService, authorizationCodeService } = deps;
|
|
32
32
|
/** Shared with `/oauth/revoke`, so the two doors cannot disagree. */
|
|
33
|
-
const
|
|
33
|
+
const warn = deps.warn ?? ((message) => console.warn(`[cap-oauth-server] ${message}`));
|
|
34
|
+
const resolveClient = (body) => (0, request_client_js_1.resolveRequestClient)(clientRegistry, body, { endpoint: 'POST /oauth/token', warn });
|
|
34
35
|
/**
|
|
35
36
|
* End-date every token the grant holds, then the grant itself.
|
|
36
37
|
*
|
|
@@ -43,6 +44,36 @@ function createTokenHandlers(deps) {
|
|
|
43
44
|
await tokenService.revokeTokensForClient(userId, grant.client_public_id);
|
|
44
45
|
await grantService.end(userId, grant.grant_id, reason);
|
|
45
46
|
}
|
|
47
|
+
/**
|
|
48
|
+
* A code was presented twice: end the grant the first redemption created.
|
|
49
|
+
*
|
|
50
|
+
* Idempotent and quiet by design. `findActive` answers `null` when the first
|
|
51
|
+
* redemption never got as far as a grant — a replay of a code whose original
|
|
52
|
+
* redemption failed PKCE, or a third presentation after the second already
|
|
53
|
+
* revoked — and there is nothing to do in either case. The refusal below is
|
|
54
|
+
* the same either way, so the caller learns nothing from which happened.
|
|
55
|
+
*
|
|
56
|
+
* A lost revision race is swallowed for the same reason. Something else wrote
|
|
57
|
+
* `oauth-grants` between the read and the write — a person disconnecting, or a
|
|
58
|
+
* second replay a millisecond behind this one — and in every version of that
|
|
59
|
+
* the grant is being ended anyway. Turning it into a 500 would answer a
|
|
60
|
+
* REPLAY with a server error, which is the one answer that tells an attacker
|
|
61
|
+
* something. The tokens are already swept by then regardless.
|
|
62
|
+
*/
|
|
63
|
+
async function revokeForCodeReplay(userId, clientPublicId) {
|
|
64
|
+
if (userId === undefined || clientPublicId === undefined)
|
|
65
|
+
return;
|
|
66
|
+
const grant = await grantService.findActive(userId, clientPublicId);
|
|
67
|
+
if (!grant)
|
|
68
|
+
return;
|
|
69
|
+
try {
|
|
70
|
+
await revokeGrant(userId, grant, 'code_replay');
|
|
71
|
+
}
|
|
72
|
+
catch (err) {
|
|
73
|
+
if (!(0, user_store_js_1.isStaleWriteError)(err))
|
|
74
|
+
throw err;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
46
77
|
/** Mint the pair and answer. One place, so the two grants cannot drift. */
|
|
47
78
|
async function issueTokens(userId, client, grant) {
|
|
48
79
|
const access = await tokenService.mint(userId, token_service_js_1.OAUTH_ACCESS_DOMAIN, client.publicId);
|
|
@@ -71,24 +102,18 @@ function createTokenHandlers(deps) {
|
|
|
71
102
|
// PKCE is required, not optional: OAuth 2.1 requires it for public clients
|
|
72
103
|
// and every client here is public.
|
|
73
104
|
const verifier = (0, body_field_js_1.required)(body, 'code_verifier');
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
redirectUri,
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
catch (err) {
|
|
84
|
-
// The single-use claim is the property write, so losing its revision
|
|
85
|
-
// check means another request redeemed this code first.
|
|
86
|
-
if ((0, user_store_js_1.isStaleWriteError)(err)) {
|
|
87
|
-
throw new oauth_error_js_1.OAuthError('invalid_grant', 'the authorization code has already been redeemed');
|
|
88
|
-
}
|
|
89
|
-
throw err;
|
|
90
|
-
}
|
|
105
|
+
const redeemed = await authorizationCodeService.redeem({
|
|
106
|
+
code,
|
|
107
|
+
clientId: client.clientId,
|
|
108
|
+
clientPublicId: client.publicId,
|
|
109
|
+
redirectUri,
|
|
110
|
+
});
|
|
91
111
|
if (!redeemed.ok) {
|
|
112
|
+
if (redeemed.reason === 'already_redeemed') {
|
|
113
|
+
// The replay. See the header for why denying it is not enough, and why
|
|
114
|
+
// the client revoked is the code's own rather than this request's.
|
|
115
|
+
await revokeForCodeReplay(redeemed.userId, redeemed.clientPublicId);
|
|
116
|
+
}
|
|
92
117
|
throw new oauth_error_js_1.OAuthError('invalid_grant', REDEEM_ERROR[redeemed.reason]);
|
|
93
118
|
}
|
|
94
119
|
const { record, userId } = redeemed;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"token-controller.js","sourceRoot":"","sources":["../src/token-controller.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"token-controller.js","sourceRoot":"","sources":["../src/token-controller.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -59,6 +59,8 @@ export interface ClientMetadataInput {
|
|
|
59
59
|
response_types?: unknown;
|
|
60
60
|
scope?: unknown;
|
|
61
61
|
token_endpoint_auth_method?: unknown;
|
|
62
|
+
/** Read only to decide whether a non-`none` method may be stored as `none`. */
|
|
63
|
+
token_endpoint_auth_methods_supported?: unknown;
|
|
62
64
|
[key: string]: unknown;
|
|
63
65
|
}
|
|
64
66
|
/** What an operator hands `registerStaticClient`. Typed, because it is code. */
|
|
@@ -98,6 +100,8 @@ export interface ClientIdMetadataDocument {
|
|
|
98
100
|
response_types?: unknown;
|
|
99
101
|
scope?: unknown;
|
|
100
102
|
token_endpoint_auth_method?: unknown;
|
|
103
|
+
/** Read only to decide whether a non-`none` method may be stored as `none`. */
|
|
104
|
+
token_endpoint_auth_methods_supported?: unknown;
|
|
101
105
|
[key: string]: unknown;
|
|
102
106
|
}
|
|
103
107
|
/**
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@boopkit/cap-oauth-server",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Make a boop app an OAuth 2.1 authorization server and resource server, so an MCP client can act on behalf of one of its users",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -20,10 +20,10 @@
|
|
|
20
20
|
"build": "tsc -p tsconfig.json"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@boopkit/cap-users": "^0.8.0",
|
|
24
23
|
"@boopkit/logger": "^0.4.0"
|
|
25
24
|
},
|
|
26
25
|
"peerDependencies": {
|
|
26
|
+
"@boopkit/cap-users": ">=0.9.0 <1",
|
|
27
27
|
"express": ">=4.0.0"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|