hono 4.6.19 → 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/adapter/lambda-edge/handler.js +6 -2
- package/dist/cjs/adapter/lambda-edge/handler.js +6 -2
- 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/helper/streaming/sse.js +8 -5
- package/dist/cjs/helper/streaming/stream.js +8 -5
- package/dist/cjs/helper/streaming/utils.js +36 -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/helper/streaming/sse.js +8 -5
- package/dist/helper/streaming/stream.js +8 -5
- package/dist/helper/streaming/utils.js +13 -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/client/types.d.ts +1 -2
- package/dist/types/context.d.ts +2 -2
- package/dist/types/helper/accepts/accepts.d.ts +0 -1
- package/dist/types/helper/adapter/index.d.ts +1 -1
- package/dist/types/helper/factory/index.d.ts +4 -1
- package/dist/types/helper/proxy/index.d.ts +54 -0
- package/dist/types/helper/streaming/utils.d.ts +1 -0
- 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/utils/accept.d.ts +11 -0
- 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 +7 -1
- package/dist/types/utils/jwt/types.d.ts +4 -0
- package/dist/types/utils/url.d.ts +1 -1
- 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 +26 -5
- package/perf-measures/bundle-check/generated/.gitkeep +0 -0
- package/perf-measures/type-check/generated/.gitkeep +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const generateDigest: (stream: ReadableStream<Uint8Array> | null) => Promise<string | null>;
|
|
1
|
+
export declare const generateDigest: (stream: ReadableStream<Uint8Array> | null, generator: (body: Uint8Array) => ArrayBuffer | Promise<ArrayBuffer>) => Promise<string | null>;
|
|
@@ -6,6 +6,7 @@ import type { MiddlewareHandler } from '../../types';
|
|
|
6
6
|
type ETagOptions = {
|
|
7
7
|
retainedHeaders?: string[];
|
|
8
8
|
weak?: boolean;
|
|
9
|
+
generateDigest?: (body: Uint8Array) => ArrayBuffer | Promise<ArrayBuffer>;
|
|
9
10
|
};
|
|
10
11
|
/**
|
|
11
12
|
* Default headers to pass through on 304 responses. From the spec:
|
|
@@ -22,6 +23,9 @@ export declare const RETAINED_304_HEADERS: string[];
|
|
|
22
23
|
* @param {ETagOptions} [options] - The options for the ETag middleware.
|
|
23
24
|
* @param {boolean} [options.weak=false] - Define using or not using a weak validation. If true is set, then `W/` is added to the prefix of the value.
|
|
24
25
|
* @param {string[]} [options.retainedHeaders=RETAINED_304_HEADERS] - The headers that you want to retain in the 304 Response.
|
|
26
|
+
* @param {function(Uint8Array): ArrayBuffer | Promise<ArrayBuffer>} [options.generateDigest] -
|
|
27
|
+
* A custom digest generation function. By default, it uses 'SHA-1'
|
|
28
|
+
* This function is called with the response body as a `Uint8Array` and should return a hash as an `ArrayBuffer` or a Promise of one.
|
|
25
29
|
* @returns {MiddlewareHandler} The middleware handler function.
|
|
26
30
|
*
|
|
27
31
|
* @example
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { jwk } from './jwk';
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module
|
|
3
|
+
* JWK Auth Middleware for Hono.
|
|
4
|
+
*/
|
|
5
|
+
import type { MiddlewareHandler } from '../../types';
|
|
6
|
+
import type { CookiePrefixOptions } from '../../utils/cookie';
|
|
7
|
+
import '../../context';
|
|
8
|
+
import type { HonoJsonWebKey } from '../../utils/jwt/jws';
|
|
9
|
+
/**
|
|
10
|
+
* JWK Auth Middleware for Hono.
|
|
11
|
+
*
|
|
12
|
+
* @see {@link https://hono.dev/docs/middleware/builtin/jwk}
|
|
13
|
+
*
|
|
14
|
+
* @param {object} options - The options for the JWK middleware.
|
|
15
|
+
* @param {HonoJsonWebKey[] | (() => Promise<HonoJsonWebKey[]>)} [options.keys] - The values of your public keys, or a function that returns them.
|
|
16
|
+
* @param {string} [options.jwks_uri] - If this value is set, attempt to fetch JWKs from this URI, expecting a JSON response with `keys` which are added to the provided options.keys
|
|
17
|
+
* @param {string} [options.cookie] - If this value is set, then the value is retrieved from the cookie header using that value as a key, which is then validated as a token.
|
|
18
|
+
* @param {RequestInit} [init] - Optional initialization options for the `fetch` request when retrieving JWKS from a URI.
|
|
19
|
+
* @returns {MiddlewareHandler} The middleware handler function.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```ts
|
|
23
|
+
* const app = new Hono()
|
|
24
|
+
*
|
|
25
|
+
* app.use("/auth/*", jwk({ jwks_uri: "https://example-backend.hono.dev/.well-known/jwks.json" }))
|
|
26
|
+
*
|
|
27
|
+
* app.get('/auth/page', (c) => {
|
|
28
|
+
* return c.text('You are authorized')
|
|
29
|
+
* })
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export declare const jwk: (options: {
|
|
33
|
+
keys?: HonoJsonWebKey[] | (() => Promise<HonoJsonWebKey[]>);
|
|
34
|
+
jwks_uri?: string;
|
|
35
|
+
cookie?: string | {
|
|
36
|
+
key: string;
|
|
37
|
+
secret?: string | BufferSource;
|
|
38
|
+
prefixOptions?: CookiePrefixOptions;
|
|
39
|
+
};
|
|
40
|
+
}, init?: RequestInit) => MiddlewareHandler;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { LanguageVariables, DetectorOptions, DetectorType, CacheType } from './language';
|
|
2
|
+
export type { LanguageVariables, DetectorOptions, DetectorType, CacheType };
|
|
3
|
+
export { languageDetector, detectFromCookie, detectFromHeader, detectFromPath, detectFromQuery, } from './language';
|
|
4
|
+
declare module '../..' {
|
|
5
|
+
interface ContextVariableMap extends LanguageVariables {
|
|
6
|
+
}
|
|
7
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module
|
|
3
|
+
* Language module for Hono.
|
|
4
|
+
*/
|
|
5
|
+
import type { Context } from '../../context';
|
|
6
|
+
import type { MiddlewareHandler } from '../../types';
|
|
7
|
+
export type DetectorType = "path" | "querystring" | "cookie" | "header";
|
|
8
|
+
export type CacheType = "cookie";
|
|
9
|
+
export interface DetectorOptions {
|
|
10
|
+
/** Order of language detection strategies */
|
|
11
|
+
order: DetectorType[];
|
|
12
|
+
/** Query parameter name for language */
|
|
13
|
+
lookupQueryString: string;
|
|
14
|
+
/** Cookie name for language */
|
|
15
|
+
lookupCookie: string;
|
|
16
|
+
/** Index in URL path where language code appears */
|
|
17
|
+
lookupFromPathIndex: number;
|
|
18
|
+
/** Header key for language detection */
|
|
19
|
+
lookupFromHeaderKey: string;
|
|
20
|
+
/** Caching strategies */
|
|
21
|
+
caches: CacheType[] | false;
|
|
22
|
+
/** Cookie configuration options */
|
|
23
|
+
cookieOptions?: {
|
|
24
|
+
domain?: string;
|
|
25
|
+
path?: string;
|
|
26
|
+
sameSite?: "Strict" | "Lax" | "None";
|
|
27
|
+
secure?: boolean;
|
|
28
|
+
maxAge?: number;
|
|
29
|
+
httpOnly?: boolean;
|
|
30
|
+
};
|
|
31
|
+
/** Whether to ignore case in language codes */
|
|
32
|
+
ignoreCase: boolean;
|
|
33
|
+
/** Default language if none detected */
|
|
34
|
+
fallbackLanguage: string;
|
|
35
|
+
/** List of supported language codes */
|
|
36
|
+
supportedLanguages: string[];
|
|
37
|
+
/** Optional function to transform detected language codes */
|
|
38
|
+
convertDetectedLanguage?: (lang: string) => string;
|
|
39
|
+
/** Enable debug logging */
|
|
40
|
+
debug?: boolean;
|
|
41
|
+
}
|
|
42
|
+
export interface LanguageVariables {
|
|
43
|
+
language: string;
|
|
44
|
+
}
|
|
45
|
+
export declare const DEFAULT_OPTIONS: DetectorOptions;
|
|
46
|
+
/**
|
|
47
|
+
* Parse Accept-Language header values with quality scores
|
|
48
|
+
* @param header Accept-Language header string
|
|
49
|
+
* @returns Array of parsed languages with quality scores
|
|
50
|
+
*/
|
|
51
|
+
export declare function parseAcceptLanguage(header: string): Array<{
|
|
52
|
+
lang: string;
|
|
53
|
+
q: number;
|
|
54
|
+
}>;
|
|
55
|
+
/**
|
|
56
|
+
* Validate and normalize language codes
|
|
57
|
+
* @param lang Language code to normalize
|
|
58
|
+
* @param options Detector options
|
|
59
|
+
* @returns Normalized language code or undefined
|
|
60
|
+
*/
|
|
61
|
+
export declare const normalizeLanguage: (lang: string | null | undefined, options: DetectorOptions) => string | undefined;
|
|
62
|
+
/**
|
|
63
|
+
* Detects language from query parameter
|
|
64
|
+
*/
|
|
65
|
+
export declare const detectFromQuery: (c: Context, options: DetectorOptions) => string | undefined;
|
|
66
|
+
/**
|
|
67
|
+
* Detects language from cookie
|
|
68
|
+
*/
|
|
69
|
+
export declare const detectFromCookie: (c: Context, options: DetectorOptions) => string | undefined;
|
|
70
|
+
/**
|
|
71
|
+
* Detects language from Accept-Language header
|
|
72
|
+
*/
|
|
73
|
+
export declare function detectFromHeader(c: Context, options: DetectorOptions): string | undefined;
|
|
74
|
+
/**
|
|
75
|
+
* Detects language from URL path
|
|
76
|
+
*/
|
|
77
|
+
export declare function detectFromPath(c: Context, options: DetectorOptions): string | undefined;
|
|
78
|
+
/**
|
|
79
|
+
* Collection of all language detection strategies
|
|
80
|
+
*/
|
|
81
|
+
export declare const detectors: {
|
|
82
|
+
readonly querystring: (c: Context, options: DetectorOptions) => string | undefined;
|
|
83
|
+
readonly cookie: (c: Context, options: DetectorOptions) => string | undefined;
|
|
84
|
+
readonly header: typeof detectFromHeader;
|
|
85
|
+
readonly path: typeof detectFromPath;
|
|
86
|
+
};
|
|
87
|
+
/** Type for detector functions */
|
|
88
|
+
export type DetectorFunction = (c: Context, options: DetectorOptions) => string | undefined;
|
|
89
|
+
/** Type-safe detector map */
|
|
90
|
+
export type Detectors = Record<keyof typeof detectors, DetectorFunction>;
|
|
91
|
+
/**
|
|
92
|
+
* Validate detector options
|
|
93
|
+
* @param options Detector options to validate
|
|
94
|
+
* @throws Error if options are invalid
|
|
95
|
+
*/
|
|
96
|
+
export declare function validateOptions(options: DetectorOptions): void;
|
|
97
|
+
/**
|
|
98
|
+
* Language detector middleware factory
|
|
99
|
+
* @param userOptions Configuration options for the language detector
|
|
100
|
+
* @returns Hono middleware function
|
|
101
|
+
*/
|
|
102
|
+
export declare const languageDetector: (userOptions: Partial<DetectorOptions>) => MiddlewareHandler;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface Accept {
|
|
2
|
+
type: string;
|
|
3
|
+
params: Record<string, string>;
|
|
4
|
+
q: number;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Parse an Accept header into an array of objects with type, parameters, and quality score.
|
|
8
|
+
* @param acceptHeader The Accept header string
|
|
9
|
+
* @returns An array of parsed Accept values
|
|
10
|
+
*/
|
|
11
|
+
export declare const parseAccept: (acceptHeader: string) => Accept[];
|
|
@@ -9,4 +9,8 @@ export declare const Jwt: {
|
|
|
9
9
|
header: import("./jwt").TokenHeader;
|
|
10
10
|
payload: import("./types").JWTPayload;
|
|
11
11
|
};
|
|
12
|
+
verifyFromJwks: (token: string, options: {
|
|
13
|
+
keys?: import("./jws").HonoJsonWebKey[] | (() => Promise<import("./jws").HonoJsonWebKey[]>);
|
|
14
|
+
jwks_uri?: string;
|
|
15
|
+
}, init?: RequestInit) => Promise<import("./types").JWTPayload>;
|
|
12
16
|
};
|
|
@@ -4,6 +4,9 @@
|
|
|
4
4
|
* https://datatracker.ietf.org/doc/html/rfc7515
|
|
5
5
|
*/
|
|
6
6
|
import type { SignatureAlgorithm } from './jwa';
|
|
7
|
-
export
|
|
7
|
+
export interface HonoJsonWebKey extends JsonWebKey {
|
|
8
|
+
kid?: string;
|
|
9
|
+
}
|
|
10
|
+
export type SignatureKey = string | HonoJsonWebKey | CryptoKey;
|
|
8
11
|
export declare function signing(privateKey: SignatureKey, alg: SignatureAlgorithm, data: BufferSource): Promise<ArrayBuffer>;
|
|
9
12
|
export declare function verifying(publicKey: SignatureKey, alg: SignatureAlgorithm, signature: BufferSource, data: BufferSource): Promise<boolean>;
|
|
@@ -4,16 +4,22 @@
|
|
|
4
4
|
* https://datatracker.ietf.org/doc/html/rfc7519
|
|
5
5
|
*/
|
|
6
6
|
import type { SignatureAlgorithm } from './jwa';
|
|
7
|
-
import type { SignatureKey } from './jws';
|
|
7
|
+
import type { HonoJsonWebKey, SignatureKey } from './jws';
|
|
8
8
|
import type { JWTPayload } from './types';
|
|
9
9
|
export interface TokenHeader {
|
|
10
10
|
alg: SignatureAlgorithm;
|
|
11
11
|
typ?: "JWT";
|
|
12
|
+
kid?: string;
|
|
12
13
|
}
|
|
13
14
|
export declare function isTokenHeader(obj: unknown): obj is TokenHeader;
|
|
14
15
|
export declare const sign: (payload: JWTPayload, privateKey: SignatureKey, alg?: SignatureAlgorithm) => Promise<string>;
|
|
15
16
|
export declare const verify: (token: string, publicKey: SignatureKey, alg?: SignatureAlgorithm) => Promise<JWTPayload>;
|
|
17
|
+
export declare const verifyFromJwks: (token: string, options: {
|
|
18
|
+
keys?: HonoJsonWebKey[] | (() => Promise<HonoJsonWebKey[]>);
|
|
19
|
+
jwks_uri?: string;
|
|
20
|
+
}, init?: RequestInit) => Promise<JWTPayload>;
|
|
16
21
|
export declare const decode: (token: string) => {
|
|
17
22
|
header: TokenHeader;
|
|
18
23
|
payload: JWTPayload;
|
|
19
24
|
};
|
|
25
|
+
export declare const decodeHeader: (token: string) => TokenHeader;
|
|
@@ -20,6 +20,9 @@ export declare class JwtTokenIssuedAt extends Error {
|
|
|
20
20
|
export declare class JwtHeaderInvalid extends Error {
|
|
21
21
|
constructor(header: object);
|
|
22
22
|
}
|
|
23
|
+
export declare class JwtHeaderRequiresKid extends Error {
|
|
24
|
+
constructor(header: object);
|
|
25
|
+
}
|
|
23
26
|
export declare class JwtTokenSignatureMismatched extends Error {
|
|
24
27
|
constructor(token: string);
|
|
25
28
|
}
|
|
@@ -51,3 +54,4 @@ export type JWTPayload = {
|
|
|
51
54
|
*/
|
|
52
55
|
iat?: number;
|
|
53
56
|
};
|
|
57
|
+
export type { HonoJsonWebKey } from './jws';
|
|
@@ -9,7 +9,7 @@ export type Pattern = readonly [
|
|
|
9
9
|
] | "*";
|
|
10
10
|
export declare const splitPath: (path: string) => string[];
|
|
11
11
|
export declare const splitRoutingPath: (routePath: string) => string[];
|
|
12
|
-
export declare const getPattern: (label: string) => Pattern | null;
|
|
12
|
+
export declare const getPattern: (label: string, next?: string) => Pattern | null;
|
|
13
13
|
type Decoder = (str: string) => string;
|
|
14
14
|
export declare const tryDecode: (str: string, decoder: Decoder) => string;
|
|
15
15
|
export declare const getPath: (request: Request) => string;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// src/utils/accept.ts
|
|
2
|
+
var parseAccept = (acceptHeader) => {
|
|
3
|
+
if (!acceptHeader) {
|
|
4
|
+
return [];
|
|
5
|
+
}
|
|
6
|
+
const acceptValues = acceptHeader.split(",").map((value, index) => ({ value, index }));
|
|
7
|
+
return acceptValues.map(parseAcceptValue).filter((item) => Boolean(item)).sort(sortByQualityAndIndex).map(({ type, params, q }) => ({ type, params, q }));
|
|
8
|
+
};
|
|
9
|
+
var parseAcceptValueRegex = /;(?=(?:(?:[^"]*"){2})*[^"]*$)/;
|
|
10
|
+
var parseAcceptValue = ({ value, index }) => {
|
|
11
|
+
const parts = value.trim().split(parseAcceptValueRegex).map((s) => s.trim());
|
|
12
|
+
const type = parts[0];
|
|
13
|
+
if (!type) {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
const params = parseParams(parts.slice(1));
|
|
17
|
+
const q = parseQuality(params.q);
|
|
18
|
+
return { type, params, q, index };
|
|
19
|
+
};
|
|
20
|
+
var parseParams = (paramParts) => {
|
|
21
|
+
return paramParts.reduce((acc, param) => {
|
|
22
|
+
const [key, val] = param.split("=").map((s) => s.trim());
|
|
23
|
+
if (key && val) {
|
|
24
|
+
acc[key] = val;
|
|
25
|
+
}
|
|
26
|
+
return acc;
|
|
27
|
+
}, {});
|
|
28
|
+
};
|
|
29
|
+
var parseQuality = (qVal) => {
|
|
30
|
+
if (qVal === void 0) {
|
|
31
|
+
return 1;
|
|
32
|
+
}
|
|
33
|
+
if (qVal === "") {
|
|
34
|
+
return 1;
|
|
35
|
+
}
|
|
36
|
+
if (qVal === "NaN") {
|
|
37
|
+
return 0;
|
|
38
|
+
}
|
|
39
|
+
const num = Number(qVal);
|
|
40
|
+
if (num === Infinity) {
|
|
41
|
+
return 1;
|
|
42
|
+
}
|
|
43
|
+
if (num === -Infinity) {
|
|
44
|
+
return 0;
|
|
45
|
+
}
|
|
46
|
+
if (Number.isNaN(num)) {
|
|
47
|
+
return 1;
|
|
48
|
+
}
|
|
49
|
+
if (num < 0 || num > 1) {
|
|
50
|
+
return 1;
|
|
51
|
+
}
|
|
52
|
+
return num;
|
|
53
|
+
};
|
|
54
|
+
var sortByQualityAndIndex = (a, b) => {
|
|
55
|
+
const qDiff = b.q - a.q;
|
|
56
|
+
if (qDiff !== 0) {
|
|
57
|
+
return qDiff;
|
|
58
|
+
}
|
|
59
|
+
return a.index - b.index;
|
|
60
|
+
};
|
|
61
|
+
export {
|
|
62
|
+
parseAccept
|
|
63
|
+
};
|
package/dist/utils/jwt/index.js
CHANGED
package/dist/utils/jwt/jwt.js
CHANGED
|
@@ -4,6 +4,7 @@ import { AlgorithmTypes } from "./jwa.js";
|
|
|
4
4
|
import { signing, verifying } from "./jws.js";
|
|
5
5
|
import {
|
|
6
6
|
JwtHeaderInvalid,
|
|
7
|
+
JwtHeaderRequiresKid,
|
|
7
8
|
JwtTokenExpired,
|
|
8
9
|
JwtTokenInvalid,
|
|
9
10
|
JwtTokenIssuedAt,
|
|
@@ -23,7 +24,13 @@ function isTokenHeader(obj) {
|
|
|
23
24
|
}
|
|
24
25
|
var sign = async (payload, privateKey, alg = "HS256") => {
|
|
25
26
|
const encodedPayload = encodeJwtPart(payload);
|
|
26
|
-
|
|
27
|
+
let encodedHeader;
|
|
28
|
+
if (typeof privateKey === "object" && "alg" in privateKey) {
|
|
29
|
+
alg = privateKey.alg;
|
|
30
|
+
encodedHeader = encodeJwtPart({ alg, typ: "JWT", kid: privateKey.kid });
|
|
31
|
+
} else {
|
|
32
|
+
encodedHeader = encodeJwtPart({ alg, typ: "JWT" });
|
|
33
|
+
}
|
|
27
34
|
const partialToken = `${encodedHeader}.${encodedPayload}`;
|
|
28
35
|
const signaturePart = await signing(privateKey, alg, utf8Encoder.encode(partialToken));
|
|
29
36
|
const signature = encodeSignaturePart(signaturePart);
|
|
@@ -60,6 +67,41 @@ var verify = async (token, publicKey, alg = "HS256") => {
|
|
|
60
67
|
}
|
|
61
68
|
return payload;
|
|
62
69
|
};
|
|
70
|
+
var verifyFromJwks = async (token, options, init) => {
|
|
71
|
+
const header = decodeHeader(token);
|
|
72
|
+
if (!isTokenHeader(header)) {
|
|
73
|
+
throw new JwtHeaderInvalid(header);
|
|
74
|
+
}
|
|
75
|
+
if (!header.kid) {
|
|
76
|
+
throw new JwtHeaderRequiresKid(header);
|
|
77
|
+
}
|
|
78
|
+
let keys = typeof options.keys === "function" ? await options.keys() : options.keys;
|
|
79
|
+
if (options.jwks_uri) {
|
|
80
|
+
const response = await fetch(options.jwks_uri, init);
|
|
81
|
+
if (!response.ok) {
|
|
82
|
+
throw new Error(`failed to fetch JWKS from ${options.jwks_uri}`);
|
|
83
|
+
}
|
|
84
|
+
const data = await response.json();
|
|
85
|
+
if (!data.keys) {
|
|
86
|
+
throw new Error('invalid JWKS response. "keys" field is missing');
|
|
87
|
+
}
|
|
88
|
+
if (!Array.isArray(data.keys)) {
|
|
89
|
+
throw new Error('invalid JWKS response. "keys" field is not an array');
|
|
90
|
+
}
|
|
91
|
+
if (keys) {
|
|
92
|
+
keys.push(...data.keys);
|
|
93
|
+
} else {
|
|
94
|
+
keys = data.keys;
|
|
95
|
+
}
|
|
96
|
+
} else if (!keys) {
|
|
97
|
+
throw new Error('verifyFromJwks requires options for either "keys" or "jwks_uri" or both');
|
|
98
|
+
}
|
|
99
|
+
const matchingKey = keys.find((key) => key.kid === header.kid);
|
|
100
|
+
if (!matchingKey) {
|
|
101
|
+
throw new JwtTokenInvalid(token);
|
|
102
|
+
}
|
|
103
|
+
return await verify(token, matchingKey, matchingKey.alg);
|
|
104
|
+
};
|
|
63
105
|
var decode = (token) => {
|
|
64
106
|
try {
|
|
65
107
|
const [h, p] = token.split(".");
|
|
@@ -73,9 +115,19 @@ var decode = (token) => {
|
|
|
73
115
|
throw new JwtTokenInvalid(token);
|
|
74
116
|
}
|
|
75
117
|
};
|
|
118
|
+
var decodeHeader = (token) => {
|
|
119
|
+
try {
|
|
120
|
+
const [h] = token.split(".");
|
|
121
|
+
return decodeJwtPart(h);
|
|
122
|
+
} catch {
|
|
123
|
+
throw new JwtTokenInvalid(token);
|
|
124
|
+
}
|
|
125
|
+
};
|
|
76
126
|
export {
|
|
77
127
|
decode,
|
|
128
|
+
decodeHeader,
|
|
78
129
|
isTokenHeader,
|
|
79
130
|
sign,
|
|
80
|
-
verify
|
|
131
|
+
verify,
|
|
132
|
+
verifyFromJwks
|
|
81
133
|
};
|
package/dist/utils/jwt/types.js
CHANGED
|
@@ -35,6 +35,12 @@ var JwtHeaderInvalid = class extends Error {
|
|
|
35
35
|
this.name = "JwtHeaderInvalid";
|
|
36
36
|
}
|
|
37
37
|
};
|
|
38
|
+
var JwtHeaderRequiresKid = class extends Error {
|
|
39
|
+
constructor(header) {
|
|
40
|
+
super(`required "kid" in jwt header: ${JSON.stringify(header)}`);
|
|
41
|
+
this.name = "JwtHeaderRequiresKid";
|
|
42
|
+
}
|
|
43
|
+
};
|
|
38
44
|
var JwtTokenSignatureMismatched = class extends Error {
|
|
39
45
|
constructor(token) {
|
|
40
46
|
super(`token(${token}) signature mismatched`);
|
|
@@ -56,6 +62,7 @@ export {
|
|
|
56
62
|
CryptoKeyUsage,
|
|
57
63
|
JwtAlgorithmNotImplemented,
|
|
58
64
|
JwtHeaderInvalid,
|
|
65
|
+
JwtHeaderRequiresKid,
|
|
59
66
|
JwtTokenExpired,
|
|
60
67
|
JwtTokenInvalid,
|
|
61
68
|
JwtTokenIssuedAt,
|
package/dist/utils/url.js
CHANGED
|
@@ -33,20 +33,21 @@ var replaceGroupMarks = (paths, groups) => {
|
|
|
33
33
|
return paths;
|
|
34
34
|
};
|
|
35
35
|
var patternCache = {};
|
|
36
|
-
var getPattern = (label) => {
|
|
36
|
+
var getPattern = (label, next) => {
|
|
37
37
|
if (label === "*") {
|
|
38
38
|
return "*";
|
|
39
39
|
}
|
|
40
40
|
const match = label.match(/^\:([^\{\}]+)(?:\{(.+)\})?$/);
|
|
41
41
|
if (match) {
|
|
42
|
-
|
|
42
|
+
const cacheKey = `${label}#${next}`;
|
|
43
|
+
if (!patternCache[cacheKey]) {
|
|
43
44
|
if (match[2]) {
|
|
44
|
-
patternCache[
|
|
45
|
+
patternCache[cacheKey] = next && next[0] !== ":" && next[0] !== "*" ? [cacheKey, match[1], new RegExp(`^${match[2]}(?=/${next})`)] : [label, match[1], new RegExp(`^${match[2]}$`)];
|
|
45
46
|
} else {
|
|
46
|
-
patternCache[
|
|
47
|
+
patternCache[cacheKey] = [label, match[1], true];
|
|
47
48
|
}
|
|
48
49
|
}
|
|
49
|
-
return patternCache[
|
|
50
|
+
return patternCache[cacheKey];
|
|
50
51
|
}
|
|
51
52
|
return null;
|
|
52
53
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hono",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.7.0",
|
|
4
4
|
"description": "Web framework built on Web Standards",
|
|
5
5
|
"main": "dist/cjs/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -204,6 +204,11 @@
|
|
|
204
204
|
"import": "./dist/middleware/jwt/index.js",
|
|
205
205
|
"require": "./dist/cjs/middleware/jwt/index.js"
|
|
206
206
|
},
|
|
207
|
+
"./jwk": {
|
|
208
|
+
"types": "./dist/types/middleware/jwk/index.d.ts",
|
|
209
|
+
"import": "./dist/middleware/jwk/index.js",
|
|
210
|
+
"require": "./dist/cjs/middleware/jwk/index.js"
|
|
211
|
+
},
|
|
207
212
|
"./timeout": {
|
|
208
213
|
"types": "./dist/types/middleware/timeout/index.d.ts",
|
|
209
214
|
"import": "./dist/middleware/timeout/index.js",
|
|
@@ -239,6 +244,11 @@
|
|
|
239
244
|
"import": "./dist/middleware/request-id/index.js",
|
|
240
245
|
"require": "./dist/cjs/middleware/request-id/index.js"
|
|
241
246
|
},
|
|
247
|
+
"./language": {
|
|
248
|
+
"types": "./dist/types/middleware/language/index.d.ts",
|
|
249
|
+
"import": "./dist/middleware/language/index.js",
|
|
250
|
+
"require": "./dist/cjs/middleware/language/index.js"
|
|
251
|
+
},
|
|
242
252
|
"./secure-headers": {
|
|
243
253
|
"types": "./dist/types/middleware/secure-headers/index.d.ts",
|
|
244
254
|
"import": "./dist/middleware/secure-headers/index.js",
|
|
@@ -388,6 +398,11 @@
|
|
|
388
398
|
"types": "./dist/types/helper/conninfo/index.d.ts",
|
|
389
399
|
"import": "./dist/helper/conninfo/index.js",
|
|
390
400
|
"require": "./dist/cjs/helper/conninfo/index.js"
|
|
401
|
+
},
|
|
402
|
+
"./proxy": {
|
|
403
|
+
"types": "./dist/types/helper/proxy/index.d.ts",
|
|
404
|
+
"import": "./dist/helper/proxy/index.js",
|
|
405
|
+
"require": "./dist/cjs/helper/proxy/index.js"
|
|
391
406
|
}
|
|
392
407
|
},
|
|
393
408
|
"typesVersions": {
|
|
@@ -506,6 +521,9 @@
|
|
|
506
521
|
"request-id": [
|
|
507
522
|
"./dist/types/middleware/request-id"
|
|
508
523
|
],
|
|
524
|
+
"language": [
|
|
525
|
+
"./dist/types/middleware/language"
|
|
526
|
+
],
|
|
509
527
|
"streaming": [
|
|
510
528
|
"./dist/types/helper/streaming"
|
|
511
529
|
],
|
|
@@ -595,6 +613,9 @@
|
|
|
595
613
|
],
|
|
596
614
|
"conninfo": [
|
|
597
615
|
"./dist/types/helper/conninfo"
|
|
616
|
+
],
|
|
617
|
+
"proxy": [
|
|
618
|
+
"./dist/types/helper/proxy"
|
|
598
619
|
]
|
|
599
620
|
}
|
|
600
621
|
},
|
|
@@ -632,21 +653,21 @@
|
|
|
632
653
|
"@types/jsdom": "^21.1.7",
|
|
633
654
|
"@types/node": "20.11.4",
|
|
634
655
|
"@types/supertest": "^2.0.16",
|
|
635
|
-
"@vitest/coverage-v8": "^
|
|
656
|
+
"@vitest/coverage-v8": "^3.0.5",
|
|
636
657
|
"arg": "^5.0.2",
|
|
637
|
-
"bun-types": "^1.1.
|
|
658
|
+
"bun-types": "^1.1.39",
|
|
638
659
|
"esbuild": "^0.15.18",
|
|
639
660
|
"eslint": "^9.10.0",
|
|
640
661
|
"glob": "^11.0.0",
|
|
641
662
|
"jsdom": "^22.1.0",
|
|
642
663
|
"msw": "^2.6.0",
|
|
643
|
-
"np": "
|
|
664
|
+
"np": "10.2.0",
|
|
644
665
|
"prettier": "^2.6.2",
|
|
645
666
|
"publint": "^0.1.16",
|
|
646
667
|
"supertest": "^6.3.4",
|
|
647
668
|
"typescript": "^5.3.3",
|
|
648
669
|
"vite-plugin-fastly-js-compute": "^0.4.2",
|
|
649
|
-
"vitest": "^
|
|
670
|
+
"vitest": "^3.0.5",
|
|
650
671
|
"wrangler": "3.58.0",
|
|
651
672
|
"ws": "^8.18.0",
|
|
652
673
|
"zod": "^3.23.8"
|
|
File without changes
|
|
File without changes
|