hono 4.6.20 → 4.7.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.
- package/dist/cjs/helper/accepts/accepts.js +4 -26
- package/dist/cjs/helper/factory/index.js +6 -2
- package/dist/cjs/helper/proxy/index.js +75 -0
- package/dist/cjs/middleware/etag/digest.js +2 -7
- package/dist/cjs/middleware/etag/index.js +7 -2
- package/dist/cjs/middleware/jwk/index.js +28 -0
- package/dist/cjs/middleware/jwk/jwk.js +124 -0
- package/dist/cjs/middleware/language/index.js +36 -0
- package/dist/cjs/middleware/language/language.js +210 -0
- package/dist/cjs/middleware/logger/index.js +2 -3
- package/dist/cjs/request.js +1 -1
- package/dist/cjs/router/linear-router/router.js +3 -1
- package/dist/cjs/router/trie-router/node.js +24 -11
- package/dist/cjs/utils/accept.js +86 -0
- package/dist/cjs/utils/jwt/index.js +1 -1
- package/dist/cjs/utils/jwt/jwt.js +56 -3
- package/dist/cjs/utils/jwt/types.js +8 -0
- package/dist/cjs/utils/url.js +6 -5
- package/dist/helper/accepts/accepts.js +2 -23
- package/dist/helper/factory/index.js +6 -2
- package/dist/helper/proxy/index.js +52 -0
- package/dist/middleware/etag/digest.js +2 -7
- package/dist/middleware/etag/index.js +7 -2
- package/dist/middleware/jwk/index.js +5 -0
- package/dist/middleware/jwk/jwk.js +101 -0
- package/dist/middleware/language/index.js +15 -0
- package/dist/middleware/language/language.js +178 -0
- package/dist/middleware/logger/index.js +2 -3
- package/dist/request.js +1 -1
- package/dist/router/linear-router/router.js +3 -1
- package/dist/router/trie-router/node.js +24 -11
- package/dist/types/adapter/cloudflare-pages/handler.d.ts +1 -1
- package/dist/types/adapter/cloudflare-workers/websocket.d.ts +1 -1
- package/dist/types/adapter/lambda-edge/handler.d.ts +2 -2
- package/dist/types/client/types.d.ts +7 -8
- package/dist/types/compose.d.ts +11 -1
- package/dist/types/context.d.ts +31 -21
- package/dist/types/helper/accepts/accepts.d.ts +0 -1
- package/dist/types/helper/adapter/index.d.ts +2 -2
- package/dist/types/helper/conninfo/types.d.ts +2 -2
- package/dist/types/helper/css/common.d.ts +6 -1
- package/dist/types/helper/factory/index.d.ts +289 -12
- package/dist/types/helper/proxy/index.d.ts +54 -0
- package/dist/types/helper/ssg/ssg.d.ts +1 -1
- package/dist/types/helper/websocket/index.d.ts +1 -2
- package/dist/types/hono-base.d.ts +18 -15
- package/dist/types/hono.d.ts +1 -1
- package/dist/types/jsx/base.d.ts +4 -1
- package/dist/types/jsx/dom/hooks/index.d.ts +9 -3
- package/dist/types/jsx/dom/index.d.ts +28 -7
- package/dist/types/jsx/dom/intrinsic-element/components.d.ts +6 -6
- package/dist/types/jsx/dom/render.d.ts +28 -4
- package/dist/types/jsx/dom/server.d.ts +28 -7
- package/dist/types/jsx/hooks/index.d.ts +20 -5
- package/dist/types/jsx/index.d.ts +28 -7
- package/dist/types/jsx/intrinsic-element/components.d.ts +4 -4
- package/dist/types/jsx/intrinsic-elements.d.ts +46 -46
- package/dist/types/middleware/compress/index.d.ts +4 -1
- package/dist/types/middleware/etag/digest.d.ts +1 -1
- package/dist/types/middleware/etag/index.d.ts +4 -0
- package/dist/types/middleware/jwk/index.d.ts +1 -0
- package/dist/types/middleware/jwk/jwk.d.ts +40 -0
- package/dist/types/middleware/language/index.d.ts +7 -0
- package/dist/types/middleware/language/language.d.ts +102 -0
- package/dist/types/middleware/secure-headers/permissions-policy.d.ts +3 -3
- package/dist/types/middleware/secure-headers/secure-headers.d.ts +1 -1
- package/dist/types/preset/quick.d.ts +1 -1
- package/dist/types/preset/tiny.d.ts +1 -1
- package/dist/types/request.d.ts +5 -3
- package/dist/types/router/linear-router/router.d.ts +0 -1
- package/dist/types/router/pattern-router/router.d.ts +0 -1
- package/dist/types/router/reg-exp-router/node.d.ts +4 -2
- package/dist/types/router/reg-exp-router/router.d.ts +0 -1
- package/dist/types/router/reg-exp-router/trie.d.ts +5 -2
- package/dist/types/router/smart-router/router.d.ts +0 -1
- package/dist/types/router/trie-router/node.d.ts +6 -2
- package/dist/types/router/trie-router/router.d.ts +0 -1
- package/dist/types/router.d.ts +20 -2
- package/dist/types/types.d.ts +2002 -111
- package/dist/types/utils/accept.d.ts +11 -0
- package/dist/types/utils/cookie.d.ts +4 -4
- package/dist/types/utils/headers.d.ts +3 -3
- package/dist/types/utils/html.d.ts +6 -2
- package/dist/types/utils/jwt/index.d.ts +4 -0
- package/dist/types/utils/jwt/jws.d.ts +4 -1
- package/dist/types/utils/jwt/jwt.d.ts +8 -2
- package/dist/types/utils/jwt/types.d.ts +4 -0
- package/dist/types/utils/mime.d.ts +2 -2
- package/dist/types/utils/stream.d.ts +0 -4
- package/dist/types/utils/url.d.ts +6 -2
- package/dist/types/validator/validator.d.ts +18 -6
- package/dist/utils/accept.js +63 -0
- package/dist/utils/jwt/index.js +2 -2
- package/dist/utils/jwt/jwt.js +54 -2
- package/dist/utils/jwt/types.js +7 -0
- package/dist/utils/url.js +6 -5
- package/package.json +24 -3
|
@@ -47,21 +47,23 @@ class Node {
|
|
|
47
47
|
const possibleKeys = [];
|
|
48
48
|
for (let i = 0, len = parts.length; i < len; i++) {
|
|
49
49
|
const p = parts[i];
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
50
|
+
const nextP = parts[i + 1];
|
|
51
|
+
const pattern = (0, import_url.getPattern)(p, nextP);
|
|
52
|
+
const key = Array.isArray(pattern) ? pattern[0] : p;
|
|
53
|
+
if (Object.keys(curNode.#children).includes(key)) {
|
|
54
|
+
curNode = curNode.#children[key];
|
|
55
|
+
const pattern2 = (0, import_url.getPattern)(p, nextP);
|
|
53
56
|
if (pattern2) {
|
|
54
57
|
possibleKeys.push(pattern2[1]);
|
|
55
58
|
}
|
|
56
59
|
continue;
|
|
57
60
|
}
|
|
58
|
-
curNode.#children[
|
|
59
|
-
const pattern = (0, import_url.getPattern)(p);
|
|
61
|
+
curNode.#children[key] = new Node();
|
|
60
62
|
if (pattern) {
|
|
61
63
|
curNode.#patterns.push(pattern);
|
|
62
64
|
possibleKeys.push(pattern[1]);
|
|
63
65
|
}
|
|
64
|
-
curNode = curNode.#children[
|
|
66
|
+
curNode = curNode.#children[key];
|
|
65
67
|
}
|
|
66
68
|
const m = /* @__PURE__ */ Object.create(null);
|
|
67
69
|
const handlerSet = {
|
|
@@ -100,6 +102,7 @@ class Node {
|
|
|
100
102
|
const curNode = this;
|
|
101
103
|
let curNodes = [curNode];
|
|
102
104
|
const parts = (0, import_url.splitPath)(path);
|
|
105
|
+
const curNodesQueue = [];
|
|
103
106
|
for (let i = 0, len = parts.length; i < len; i++) {
|
|
104
107
|
const part = parts[i];
|
|
105
108
|
const isLast = i === len - 1;
|
|
@@ -127,6 +130,7 @@ class Node {
|
|
|
127
130
|
const astNode = node.#children["*"];
|
|
128
131
|
if (astNode) {
|
|
129
132
|
handlerSets.push(...this.#getHandlerSets(astNode, method, node.#params));
|
|
133
|
+
astNode.#params = params;
|
|
130
134
|
tempNodes.push(astNode);
|
|
131
135
|
}
|
|
132
136
|
continue;
|
|
@@ -137,10 +141,19 @@ class Node {
|
|
|
137
141
|
const [key, name, matcher] = pattern;
|
|
138
142
|
const child = node.#children[key];
|
|
139
143
|
const restPathString = parts.slice(i).join("/");
|
|
140
|
-
if (matcher instanceof RegExp
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
+
if (matcher instanceof RegExp) {
|
|
145
|
+
const m = matcher.exec(restPathString);
|
|
146
|
+
if (m) {
|
|
147
|
+
params[name] = m[0];
|
|
148
|
+
handlerSets.push(...this.#getHandlerSets(child, method, node.#params, params));
|
|
149
|
+
if (Object.keys(child.#children).length) {
|
|
150
|
+
child.#params = params;
|
|
151
|
+
const componentCount = m[0].match(/\//)?.length ?? 0;
|
|
152
|
+
const targetCurNodes = curNodesQueue[componentCount] ||= [];
|
|
153
|
+
targetCurNodes.push(child);
|
|
154
|
+
}
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
144
157
|
}
|
|
145
158
|
if (matcher === true || matcher.test(part)) {
|
|
146
159
|
params[name] = part;
|
|
@@ -158,7 +171,7 @@ class Node {
|
|
|
158
171
|
}
|
|
159
172
|
}
|
|
160
173
|
}
|
|
161
|
-
curNodes = tempNodes;
|
|
174
|
+
curNodes = tempNodes.concat(curNodesQueue.shift() ?? []);
|
|
162
175
|
}
|
|
163
176
|
if (handlerSets.length > 1) {
|
|
164
177
|
handlerSets.sort((a, b) => {
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var accept_exports = {};
|
|
20
|
+
__export(accept_exports, {
|
|
21
|
+
parseAccept: () => parseAccept
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(accept_exports);
|
|
24
|
+
const parseAccept = (acceptHeader) => {
|
|
25
|
+
if (!acceptHeader) {
|
|
26
|
+
return [];
|
|
27
|
+
}
|
|
28
|
+
const acceptValues = acceptHeader.split(",").map((value, index) => ({ value, index }));
|
|
29
|
+
return acceptValues.map(parseAcceptValue).filter((item) => Boolean(item)).sort(sortByQualityAndIndex).map(({ type, params, q }) => ({ type, params, q }));
|
|
30
|
+
};
|
|
31
|
+
const parseAcceptValueRegex = /;(?=(?:(?:[^"]*"){2})*[^"]*$)/;
|
|
32
|
+
const parseAcceptValue = ({ value, index }) => {
|
|
33
|
+
const parts = value.trim().split(parseAcceptValueRegex).map((s) => s.trim());
|
|
34
|
+
const type = parts[0];
|
|
35
|
+
if (!type) {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
const params = parseParams(parts.slice(1));
|
|
39
|
+
const q = parseQuality(params.q);
|
|
40
|
+
return { type, params, q, index };
|
|
41
|
+
};
|
|
42
|
+
const parseParams = (paramParts) => {
|
|
43
|
+
return paramParts.reduce((acc, param) => {
|
|
44
|
+
const [key, val] = param.split("=").map((s) => s.trim());
|
|
45
|
+
if (key && val) {
|
|
46
|
+
acc[key] = val;
|
|
47
|
+
}
|
|
48
|
+
return acc;
|
|
49
|
+
}, {});
|
|
50
|
+
};
|
|
51
|
+
const parseQuality = (qVal) => {
|
|
52
|
+
if (qVal === void 0) {
|
|
53
|
+
return 1;
|
|
54
|
+
}
|
|
55
|
+
if (qVal === "") {
|
|
56
|
+
return 1;
|
|
57
|
+
}
|
|
58
|
+
if (qVal === "NaN") {
|
|
59
|
+
return 0;
|
|
60
|
+
}
|
|
61
|
+
const num = Number(qVal);
|
|
62
|
+
if (num === Infinity) {
|
|
63
|
+
return 1;
|
|
64
|
+
}
|
|
65
|
+
if (num === -Infinity) {
|
|
66
|
+
return 0;
|
|
67
|
+
}
|
|
68
|
+
if (Number.isNaN(num)) {
|
|
69
|
+
return 1;
|
|
70
|
+
}
|
|
71
|
+
if (num < 0 || num > 1) {
|
|
72
|
+
return 1;
|
|
73
|
+
}
|
|
74
|
+
return num;
|
|
75
|
+
};
|
|
76
|
+
const sortByQualityAndIndex = (a, b) => {
|
|
77
|
+
const qDiff = b.q - a.q;
|
|
78
|
+
if (qDiff !== 0) {
|
|
79
|
+
return qDiff;
|
|
80
|
+
}
|
|
81
|
+
return a.index - b.index;
|
|
82
|
+
};
|
|
83
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
84
|
+
0 && (module.exports = {
|
|
85
|
+
parseAccept
|
|
86
|
+
});
|
|
@@ -22,7 +22,7 @@ __export(jwt_exports, {
|
|
|
22
22
|
});
|
|
23
23
|
module.exports = __toCommonJS(jwt_exports);
|
|
24
24
|
var import_jwt = require("./jwt");
|
|
25
|
-
const Jwt = { sign: import_jwt.sign, verify: import_jwt.verify, decode: import_jwt.decode };
|
|
25
|
+
const Jwt = { sign: import_jwt.sign, verify: import_jwt.verify, decode: import_jwt.decode, verifyFromJwks: import_jwt.verifyFromJwks };
|
|
26
26
|
// Annotate the CommonJS export names for ESM import in node:
|
|
27
27
|
0 && (module.exports = {
|
|
28
28
|
Jwt
|
|
@@ -19,9 +19,11 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
19
19
|
var jwt_exports = {};
|
|
20
20
|
__export(jwt_exports, {
|
|
21
21
|
decode: () => decode,
|
|
22
|
+
decodeHeader: () => decodeHeader,
|
|
22
23
|
isTokenHeader: () => isTokenHeader,
|
|
23
24
|
sign: () => sign,
|
|
24
|
-
verify: () => verify
|
|
25
|
+
verify: () => verify,
|
|
26
|
+
verifyFromJwks: () => verifyFromJwks
|
|
25
27
|
});
|
|
26
28
|
module.exports = __toCommonJS(jwt_exports);
|
|
27
29
|
var import_encode = require("../../utils/encode");
|
|
@@ -41,7 +43,13 @@ function isTokenHeader(obj) {
|
|
|
41
43
|
}
|
|
42
44
|
const sign = async (payload, privateKey, alg = "HS256") => {
|
|
43
45
|
const encodedPayload = encodeJwtPart(payload);
|
|
44
|
-
|
|
46
|
+
let encodedHeader;
|
|
47
|
+
if (typeof privateKey === "object" && "alg" in privateKey) {
|
|
48
|
+
alg = privateKey.alg;
|
|
49
|
+
encodedHeader = encodeJwtPart({ alg, typ: "JWT", kid: privateKey.kid });
|
|
50
|
+
} else {
|
|
51
|
+
encodedHeader = encodeJwtPart({ alg, typ: "JWT" });
|
|
52
|
+
}
|
|
45
53
|
const partialToken = `${encodedHeader}.${encodedPayload}`;
|
|
46
54
|
const signaturePart = await (0, import_jws.signing)(privateKey, alg, import_utf8.utf8Encoder.encode(partialToken));
|
|
47
55
|
const signature = encodeSignaturePart(signaturePart);
|
|
@@ -78,6 +86,41 @@ const verify = async (token, publicKey, alg = "HS256") => {
|
|
|
78
86
|
}
|
|
79
87
|
return payload;
|
|
80
88
|
};
|
|
89
|
+
const verifyFromJwks = async (token, options, init) => {
|
|
90
|
+
const header = decodeHeader(token);
|
|
91
|
+
if (!isTokenHeader(header)) {
|
|
92
|
+
throw new import_types.JwtHeaderInvalid(header);
|
|
93
|
+
}
|
|
94
|
+
if (!header.kid) {
|
|
95
|
+
throw new import_types.JwtHeaderRequiresKid(header);
|
|
96
|
+
}
|
|
97
|
+
let keys = typeof options.keys === "function" ? await options.keys() : options.keys;
|
|
98
|
+
if (options.jwks_uri) {
|
|
99
|
+
const response = await fetch(options.jwks_uri, init);
|
|
100
|
+
if (!response.ok) {
|
|
101
|
+
throw new Error(`failed to fetch JWKS from ${options.jwks_uri}`);
|
|
102
|
+
}
|
|
103
|
+
const data = await response.json();
|
|
104
|
+
if (!data.keys) {
|
|
105
|
+
throw new Error('invalid JWKS response. "keys" field is missing');
|
|
106
|
+
}
|
|
107
|
+
if (!Array.isArray(data.keys)) {
|
|
108
|
+
throw new Error('invalid JWKS response. "keys" field is not an array');
|
|
109
|
+
}
|
|
110
|
+
if (keys) {
|
|
111
|
+
keys.push(...data.keys);
|
|
112
|
+
} else {
|
|
113
|
+
keys = data.keys;
|
|
114
|
+
}
|
|
115
|
+
} else if (!keys) {
|
|
116
|
+
throw new Error('verifyFromJwks requires options for either "keys" or "jwks_uri" or both');
|
|
117
|
+
}
|
|
118
|
+
const matchingKey = keys.find((key) => key.kid === header.kid);
|
|
119
|
+
if (!matchingKey) {
|
|
120
|
+
throw new import_types.JwtTokenInvalid(token);
|
|
121
|
+
}
|
|
122
|
+
return await verify(token, matchingKey, matchingKey.alg);
|
|
123
|
+
};
|
|
81
124
|
const decode = (token) => {
|
|
82
125
|
try {
|
|
83
126
|
const [h, p] = token.split(".");
|
|
@@ -91,10 +134,20 @@ const decode = (token) => {
|
|
|
91
134
|
throw new import_types.JwtTokenInvalid(token);
|
|
92
135
|
}
|
|
93
136
|
};
|
|
137
|
+
const decodeHeader = (token) => {
|
|
138
|
+
try {
|
|
139
|
+
const [h] = token.split(".");
|
|
140
|
+
return decodeJwtPart(h);
|
|
141
|
+
} catch {
|
|
142
|
+
throw new import_types.JwtTokenInvalid(token);
|
|
143
|
+
}
|
|
144
|
+
};
|
|
94
145
|
// Annotate the CommonJS export names for ESM import in node:
|
|
95
146
|
0 && (module.exports = {
|
|
96
147
|
decode,
|
|
148
|
+
decodeHeader,
|
|
97
149
|
isTokenHeader,
|
|
98
150
|
sign,
|
|
99
|
-
verify
|
|
151
|
+
verify,
|
|
152
|
+
verifyFromJwks
|
|
100
153
|
});
|
|
@@ -21,6 +21,7 @@ __export(types_exports, {
|
|
|
21
21
|
CryptoKeyUsage: () => CryptoKeyUsage,
|
|
22
22
|
JwtAlgorithmNotImplemented: () => JwtAlgorithmNotImplemented,
|
|
23
23
|
JwtHeaderInvalid: () => JwtHeaderInvalid,
|
|
24
|
+
JwtHeaderRequiresKid: () => JwtHeaderRequiresKid,
|
|
24
25
|
JwtTokenExpired: () => JwtTokenExpired,
|
|
25
26
|
JwtTokenInvalid: () => JwtTokenInvalid,
|
|
26
27
|
JwtTokenIssuedAt: () => JwtTokenIssuedAt,
|
|
@@ -64,6 +65,12 @@ class JwtHeaderInvalid extends Error {
|
|
|
64
65
|
this.name = "JwtHeaderInvalid";
|
|
65
66
|
}
|
|
66
67
|
}
|
|
68
|
+
class JwtHeaderRequiresKid extends Error {
|
|
69
|
+
constructor(header) {
|
|
70
|
+
super(`required "kid" in jwt header: ${JSON.stringify(header)}`);
|
|
71
|
+
this.name = "JwtHeaderRequiresKid";
|
|
72
|
+
}
|
|
73
|
+
}
|
|
67
74
|
class JwtTokenSignatureMismatched extends Error {
|
|
68
75
|
constructor(token) {
|
|
69
76
|
super(`token(${token}) signature mismatched`);
|
|
@@ -86,6 +93,7 @@ var CryptoKeyUsage = /* @__PURE__ */ ((CryptoKeyUsage2) => {
|
|
|
86
93
|
CryptoKeyUsage,
|
|
87
94
|
JwtAlgorithmNotImplemented,
|
|
88
95
|
JwtHeaderInvalid,
|
|
96
|
+
JwtHeaderRequiresKid,
|
|
89
97
|
JwtTokenExpired,
|
|
90
98
|
JwtTokenInvalid,
|
|
91
99
|
JwtTokenIssuedAt,
|
package/dist/cjs/utils/url.js
CHANGED
|
@@ -66,20 +66,21 @@ const replaceGroupMarks = (paths, groups) => {
|
|
|
66
66
|
return paths;
|
|
67
67
|
};
|
|
68
68
|
const patternCache = {};
|
|
69
|
-
const getPattern = (label) => {
|
|
69
|
+
const getPattern = (label, next) => {
|
|
70
70
|
if (label === "*") {
|
|
71
71
|
return "*";
|
|
72
72
|
}
|
|
73
73
|
const match = label.match(/^\:([^\{\}]+)(?:\{(.+)\})?$/);
|
|
74
74
|
if (match) {
|
|
75
|
-
|
|
75
|
+
const cacheKey = `${label}#${next}`;
|
|
76
|
+
if (!patternCache[cacheKey]) {
|
|
76
77
|
if (match[2]) {
|
|
77
|
-
patternCache[
|
|
78
|
+
patternCache[cacheKey] = next && next[0] !== ":" && next[0] !== "*" ? [cacheKey, match[1], new RegExp(`^${match[2]}(?=/${next})`)] : [label, match[1], new RegExp(`^${match[2]}$`)];
|
|
78
79
|
} else {
|
|
79
|
-
patternCache[
|
|
80
|
+
patternCache[cacheKey] = [label, match[1], true];
|
|
80
81
|
}
|
|
81
82
|
}
|
|
82
|
-
return patternCache[
|
|
83
|
+
return patternCache[cacheKey];
|
|
83
84
|
}
|
|
84
85
|
return null;
|
|
85
86
|
};
|
|
@@ -1,25 +1,5 @@
|
|
|
1
1
|
// src/helper/accepts/accepts.ts
|
|
2
|
-
|
|
3
|
-
const accepts2 = acceptHeader.split(",");
|
|
4
|
-
return accepts2.map((accept) => {
|
|
5
|
-
const parts = accept.trim().split(";");
|
|
6
|
-
const type = parts[0];
|
|
7
|
-
const params = parts.slice(1);
|
|
8
|
-
const q = params.find((param) => param.startsWith("q="));
|
|
9
|
-
const paramsObject = params.reduce((acc, param) => {
|
|
10
|
-
const keyValue = param.split("=");
|
|
11
|
-
const key = keyValue[0].trim();
|
|
12
|
-
const value = keyValue[1].trim();
|
|
13
|
-
acc[key] = value;
|
|
14
|
-
return acc;
|
|
15
|
-
}, {});
|
|
16
|
-
return {
|
|
17
|
-
type,
|
|
18
|
-
params: paramsObject,
|
|
19
|
-
q: q ? parseFloat(q.split("=")[1]) : 1
|
|
20
|
-
};
|
|
21
|
-
});
|
|
22
|
-
};
|
|
2
|
+
import { parseAccept } from "../../utils/accept.js";
|
|
23
3
|
var defaultMatch = (accepts2, config) => {
|
|
24
4
|
const { supports, default: defaultSupport } = config;
|
|
25
5
|
const accept = accepts2.sort((a, b) => b.q - a.q).find((accept2) => supports.includes(accept2.type));
|
|
@@ -36,6 +16,5 @@ var accepts = (c, options) => {
|
|
|
36
16
|
};
|
|
37
17
|
export {
|
|
38
18
|
accepts,
|
|
39
|
-
defaultMatch
|
|
40
|
-
parseAccept
|
|
19
|
+
defaultMatch
|
|
41
20
|
};
|
|
@@ -2,11 +2,15 @@
|
|
|
2
2
|
import { Hono } from "../../hono.js";
|
|
3
3
|
var Factory = class {
|
|
4
4
|
initApp;
|
|
5
|
+
#defaultAppOptions;
|
|
5
6
|
constructor(init) {
|
|
6
7
|
this.initApp = init?.initApp;
|
|
8
|
+
this.#defaultAppOptions = init?.defaultAppOptions;
|
|
7
9
|
}
|
|
8
|
-
createApp = () => {
|
|
9
|
-
const app = new Hono(
|
|
10
|
+
createApp = (options) => {
|
|
11
|
+
const app = new Hono(
|
|
12
|
+
options && this.#defaultAppOptions ? { ...this.#defaultAppOptions, ...options } : options ?? this.#defaultAppOptions
|
|
13
|
+
);
|
|
10
14
|
if (this.initApp) {
|
|
11
15
|
this.initApp(app);
|
|
12
16
|
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// src/helper/proxy/index.ts
|
|
2
|
+
var hopByHopHeaders = [
|
|
3
|
+
"connection",
|
|
4
|
+
"keep-alive",
|
|
5
|
+
"proxy-authenticate",
|
|
6
|
+
"proxy-authorization",
|
|
7
|
+
"te",
|
|
8
|
+
"trailers",
|
|
9
|
+
"transfer-encoding"
|
|
10
|
+
];
|
|
11
|
+
var buildRequestInitFromRequest = (request) => {
|
|
12
|
+
if (!request) {
|
|
13
|
+
return {};
|
|
14
|
+
}
|
|
15
|
+
const headers = new Headers(request.headers);
|
|
16
|
+
hopByHopHeaders.forEach((header) => {
|
|
17
|
+
headers.delete(header);
|
|
18
|
+
});
|
|
19
|
+
return {
|
|
20
|
+
method: request.method,
|
|
21
|
+
body: request.body,
|
|
22
|
+
duplex: request.body ? "half" : void 0,
|
|
23
|
+
headers
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
var proxy = async (input, proxyInit) => {
|
|
27
|
+
const { raw, ...requestInit } = proxyInit ?? {};
|
|
28
|
+
const req = new Request(
|
|
29
|
+
input,
|
|
30
|
+
{
|
|
31
|
+
...buildRequestInitFromRequest(raw),
|
|
32
|
+
...requestInit
|
|
33
|
+
}
|
|
34
|
+
);
|
|
35
|
+
req.headers.delete("accept-encoding");
|
|
36
|
+
const res = await fetch(req);
|
|
37
|
+
const resHeaders = new Headers(res.headers);
|
|
38
|
+
hopByHopHeaders.forEach((header) => {
|
|
39
|
+
resHeaders.delete(header);
|
|
40
|
+
});
|
|
41
|
+
if (resHeaders.has("content-encoding")) {
|
|
42
|
+
resHeaders.delete("content-encoding");
|
|
43
|
+
resHeaders.delete("content-length");
|
|
44
|
+
}
|
|
45
|
+
return new Response(res.body, {
|
|
46
|
+
...res,
|
|
47
|
+
headers: resHeaders
|
|
48
|
+
});
|
|
49
|
+
};
|
|
50
|
+
export {
|
|
51
|
+
proxy
|
|
52
|
+
};
|
|
@@ -8,7 +8,7 @@ var mergeBuffers = (buffer1, buffer2) => {
|
|
|
8
8
|
merged.set(buffer2, buffer1.byteLength);
|
|
9
9
|
return merged;
|
|
10
10
|
};
|
|
11
|
-
var generateDigest = async (stream) => {
|
|
11
|
+
var generateDigest = async (stream, generator) => {
|
|
12
12
|
if (!stream || !crypto || !crypto.subtle) {
|
|
13
13
|
return null;
|
|
14
14
|
}
|
|
@@ -19,12 +19,7 @@ var generateDigest = async (stream) => {
|
|
|
19
19
|
if (done) {
|
|
20
20
|
break;
|
|
21
21
|
}
|
|
22
|
-
result = await
|
|
23
|
-
{
|
|
24
|
-
name: "SHA-1"
|
|
25
|
-
},
|
|
26
|
-
mergeBuffers(result, value)
|
|
27
|
-
);
|
|
22
|
+
result = await generator(mergeBuffers(result, value));
|
|
28
23
|
}
|
|
29
24
|
if (!result) {
|
|
30
25
|
return null;
|
|
@@ -14,20 +14,25 @@ function etagMatches(etag2, ifNoneMatch) {
|
|
|
14
14
|
var etag = (options) => {
|
|
15
15
|
const retainedHeaders = options?.retainedHeaders ?? RETAINED_304_HEADERS;
|
|
16
16
|
const weak = options?.weak ?? false;
|
|
17
|
+
const generator = options?.generateDigest ?? ((body) => crypto.subtle.digest(
|
|
18
|
+
{
|
|
19
|
+
name: "SHA-1"
|
|
20
|
+
},
|
|
21
|
+
body
|
|
22
|
+
));
|
|
17
23
|
return async function etag2(c, next) {
|
|
18
24
|
const ifNoneMatch = c.req.header("If-None-Match") ?? null;
|
|
19
25
|
await next();
|
|
20
26
|
const res = c.res;
|
|
21
27
|
let etag3 = res.headers.get("ETag");
|
|
22
28
|
if (!etag3) {
|
|
23
|
-
const hash = await generateDigest(res.clone().body);
|
|
29
|
+
const hash = await generateDigest(res.clone().body, generator);
|
|
24
30
|
if (hash === null) {
|
|
25
31
|
return;
|
|
26
32
|
}
|
|
27
33
|
etag3 = weak ? `W/"${hash}"` : `"${hash}"`;
|
|
28
34
|
}
|
|
29
35
|
if (etagMatches(etag3, ifNoneMatch)) {
|
|
30
|
-
await c.res.blob();
|
|
31
36
|
c.res = new Response(null, {
|
|
32
37
|
status: 304,
|
|
33
38
|
statusText: "Not Modified",
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
// src/middleware/jwk/jwk.ts
|
|
2
|
+
import { getCookie, getSignedCookie } from "../../helper/cookie/index.js";
|
|
3
|
+
import { HTTPException } from "../../http-exception.js";
|
|
4
|
+
import { Jwt } from "../../utils/jwt/index.js";
|
|
5
|
+
import "../../context.js";
|
|
6
|
+
var jwk = (options, init) => {
|
|
7
|
+
if (!options || !(options.keys || options.jwks_uri)) {
|
|
8
|
+
throw new Error('JWK auth middleware requires options for either "keys" or "jwks_uri" or both');
|
|
9
|
+
}
|
|
10
|
+
if (!crypto.subtle || !crypto.subtle.importKey) {
|
|
11
|
+
throw new Error("`crypto.subtle.importKey` is undefined. JWK auth middleware requires it.");
|
|
12
|
+
}
|
|
13
|
+
return async function jwk2(ctx, next) {
|
|
14
|
+
const credentials = ctx.req.raw.headers.get("Authorization");
|
|
15
|
+
let token;
|
|
16
|
+
if (credentials) {
|
|
17
|
+
const parts = credentials.split(/\s+/);
|
|
18
|
+
if (parts.length !== 2) {
|
|
19
|
+
const errDescription = "invalid credentials structure";
|
|
20
|
+
throw new HTTPException(401, {
|
|
21
|
+
message: errDescription,
|
|
22
|
+
res: unauthorizedResponse({
|
|
23
|
+
ctx,
|
|
24
|
+
error: "invalid_request",
|
|
25
|
+
errDescription
|
|
26
|
+
})
|
|
27
|
+
});
|
|
28
|
+
} else {
|
|
29
|
+
token = parts[1];
|
|
30
|
+
}
|
|
31
|
+
} else if (options.cookie) {
|
|
32
|
+
if (typeof options.cookie == "string") {
|
|
33
|
+
token = getCookie(ctx, options.cookie);
|
|
34
|
+
} else if (options.cookie.secret) {
|
|
35
|
+
if (options.cookie.prefixOptions) {
|
|
36
|
+
token = await getSignedCookie(
|
|
37
|
+
ctx,
|
|
38
|
+
options.cookie.secret,
|
|
39
|
+
options.cookie.key,
|
|
40
|
+
options.cookie.prefixOptions
|
|
41
|
+
);
|
|
42
|
+
} else {
|
|
43
|
+
token = await getSignedCookie(ctx, options.cookie.secret, options.cookie.key);
|
|
44
|
+
}
|
|
45
|
+
} else {
|
|
46
|
+
if (options.cookie.prefixOptions) {
|
|
47
|
+
token = getCookie(ctx, options.cookie.key, options.cookie.prefixOptions);
|
|
48
|
+
} else {
|
|
49
|
+
token = getCookie(ctx, options.cookie.key);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if (!token) {
|
|
54
|
+
const errDescription = "no authorization included in request";
|
|
55
|
+
throw new HTTPException(401, {
|
|
56
|
+
message: errDescription,
|
|
57
|
+
res: unauthorizedResponse({
|
|
58
|
+
ctx,
|
|
59
|
+
error: "invalid_request",
|
|
60
|
+
errDescription
|
|
61
|
+
})
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
let payload;
|
|
65
|
+
let cause;
|
|
66
|
+
try {
|
|
67
|
+
payload = await Jwt.verifyFromJwks(token, options, init);
|
|
68
|
+
} catch (e) {
|
|
69
|
+
cause = e;
|
|
70
|
+
}
|
|
71
|
+
if (!payload) {
|
|
72
|
+
if (cause instanceof Error && cause.constructor === Error) {
|
|
73
|
+
throw cause;
|
|
74
|
+
}
|
|
75
|
+
throw new HTTPException(401, {
|
|
76
|
+
message: "Unauthorized",
|
|
77
|
+
res: unauthorizedResponse({
|
|
78
|
+
ctx,
|
|
79
|
+
error: "invalid_token",
|
|
80
|
+
statusText: "Unauthorized",
|
|
81
|
+
errDescription: "token verification failure"
|
|
82
|
+
}),
|
|
83
|
+
cause
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
ctx.set("jwtPayload", payload);
|
|
87
|
+
await next();
|
|
88
|
+
};
|
|
89
|
+
};
|
|
90
|
+
function unauthorizedResponse(opts) {
|
|
91
|
+
return new Response("Unauthorized", {
|
|
92
|
+
status: 401,
|
|
93
|
+
statusText: opts.statusText,
|
|
94
|
+
headers: {
|
|
95
|
+
"WWW-Authenticate": `Bearer realm="${opts.ctx.req.url}",error="${opts.error}",error_description="${opts.errDescription}"`
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
export {
|
|
100
|
+
jwk
|
|
101
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// src/middleware/language/index.ts
|
|
2
|
+
import {
|
|
3
|
+
languageDetector,
|
|
4
|
+
detectFromCookie,
|
|
5
|
+
detectFromHeader,
|
|
6
|
+
detectFromPath,
|
|
7
|
+
detectFromQuery
|
|
8
|
+
} from "./language.js";
|
|
9
|
+
export {
|
|
10
|
+
detectFromCookie,
|
|
11
|
+
detectFromHeader,
|
|
12
|
+
detectFromPath,
|
|
13
|
+
detectFromQuery,
|
|
14
|
+
languageDetector
|
|
15
|
+
};
|