Skip to content

Commit 1928b53

Browse files
committed
feat: use external validation for token
1 parent f19fcdd commit 1928b53

File tree

8 files changed

+127
-46
lines changed

8 files changed

+127
-46
lines changed

_abnf.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,4 @@ if (import.meta.main) {
6767
console.log("challenge:", optimize(challenge).toRegExp());
6868
console.log("element: ", element);
6969
console.log("authParam: ", optimize(authParam).toRegExp());
70-
console.log("token: ", optimize(token).toRegExp());
71-
console.log("token68: ", optimize(token68).toRegExp());
72-
console.log(
73-
"quoted-string: ",
74-
optimize(quotedString).toRegExp(),
75-
);
7670
}

_dev_deps.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
export {
22
assert,
33
assertEquals,
4+
assertFalse,
45
assertIsError,
56
assertThrows,
67
} from "https://deno.land/[email protected]/testing/asserts.ts";

_tools/meta.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,5 +64,15 @@ export const makeOptions = (version: string): BuildOptions => ({
6464
version: "1.3.1",
6565
subPath: "is_nullable.js",
6666
},
67+
"https://deno.land/x/[email protected]/quoted_string.ts": {
68+
name: "@httpland/http-utils",
69+
version: "1.1.0",
70+
subPath: "quoted_string.js",
71+
},
72+
"https://deno.land/x/[email protected]/token.ts": {
73+
name: "@httpland/http-utils",
74+
version: "1.1.0",
75+
subPath: "token.js",
76+
},
6777
},
6878
});

deno.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

deps.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,5 @@ export { head } from "https://deno.land/x/[email protected]/head.ts";
77
export { isString } from "https://deno.land/x/[email protected]/is_string.ts";
88
export { isNullable } from "https://deno.land/x/[email protected]/is_nullable.ts";
99
export { mapValues } from "https://deno.land/[email protected]/collections/map_values.ts";
10+
export { isQuotedString } from "https://deno.land/x/[email protected]/quoted_string.ts";
11+
export { isToken } from "https://deno.land/x/[email protected]/token.ts";

stringify.ts

Lines changed: 9 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,15 @@
11
// Copyright 2023-latest the httpland authors. All rights reserved. MIT license.
22
// This module is browser compatible.
33

4-
import { isNullable, isString, mapValues, toLowerCase } from "./deps.ts";
5-
import { duplicate } from "./utils.ts";
4+
import {
5+
isNullable,
6+
isQuotedString,
7+
isString,
8+
isToken,
9+
mapValues,
10+
toLowerCase,
11+
} from "./deps.ts";
12+
import { assertToken, assertToken68, duplicate } from "./utils.ts";
613
import { Msg } from "./constants.ts";
714
import type { Authorization, AuthParams } from "./types.ts";
815

@@ -47,41 +54,6 @@ export function stringifyAuthorization(input: AuthorizationLike): string {
4754
return [input.authScheme, data].filter(Boolean).join(" ");
4855
}
4956

50-
const reToken = /^(?=([\w!#$%&'*+.^`|~-]+))\1$/;
51-
52-
export function assertToken(
53-
input: string,
54-
msg?: string,
55-
constructor: ErrorConstructor = Error,
56-
): asserts input {
57-
if (!isToken(input)) throw new constructor(msg);
58-
}
59-
60-
export function isToken(input: string): boolean {
61-
return reToken.test(input);
62-
}
63-
64-
const reToken68 = /^(?=((?:[A-Za-z]|\d|[+./_~-])+))\1(?=(=*))\2$/;
65-
66-
export function isToken68(input: string): boolean {
67-
return reToken68.test(input);
68-
}
69-
70-
export function assertToken68(
71-
input: string,
72-
msg?: string,
73-
constructor: ErrorConstructor = Error,
74-
): asserts input {
75-
if (!isToken68(input)) throw new constructor(msg);
76-
}
77-
78-
const reQuotedString =
79-
/^"(?=((?:\t| |!|[ \x23-\x5B\x5D-\x7E]|[\x80-\xFF]|\\(?:\t| |[\x21-\x7E]|[\x80-\xFF]))*))\1"$/;
80-
81-
export function isQuotedString(input: string): boolean {
82-
return reQuotedString.test(input);
83-
}
84-
8557
function assertAuthParam(input: AuthParams): asserts input {
8658
for (const key in input) {
8759
assertToken(key, `token key ${Msg.InvalidToken}`);

utils.ts

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright 2023-latest the httpland authors. All rights reserved. MIT license.
22
// This module is browser compatible.
33

4-
import { trim } from "./deps.ts";
4+
import { isToken, trim } from "./deps.ts";
55

66
export function duplicate<T>(list: readonly T[]): T[] {
77
const duplicates = new Set<T>();
@@ -24,3 +24,34 @@ export function parseList(input: string): string[] {
2424
.map(trim)
2525
.filter(Boolean);
2626
}
27+
28+
/**
29+
* ```abnf
30+
* token68 = 1*( ALPHA / DIGIT /
31+
* "-" / "." / "_" / "~" / "+" / "/" ) *"="
32+
* ```
33+
*/
34+
const reToken68 = /^[\w.~+/-]+?=*?$/;
35+
36+
/** Whether the input is [token68](https://www.rfc-editor.org/rfc/rfc9110.html#section-11.2-2) or not. */
37+
export function isToken68(input: string): boolean {
38+
return reToken68.test(input);
39+
}
40+
41+
/** Assert the input is [token68](https://www.rfc-editor.org/rfc/rfc9110.html#section-11.2-2). */
42+
export function assertToken68(
43+
input: string,
44+
msg?: string,
45+
constructor: ErrorConstructor = Error,
46+
): asserts input {
47+
if (!isToken68(input)) throw new constructor(msg);
48+
}
49+
50+
/** Assert the input is [token](https://www.rfc-editor.org/rfc/rfc9110.html#section-5.6.2-2). */
51+
export function assertToken(
52+
input: string,
53+
msg?: string,
54+
constructor: ErrorConstructor = Error,
55+
): asserts input {
56+
if (!isToken(input)) throw new constructor(msg);
57+
}

utils_test.ts

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
1-
import { parseList } from "./utils.ts";
2-
import { assertEquals, describe, it } from "./_dev_deps.ts";
1+
import { assertToken, assertToken68, isToken68, parseList } from "./utils.ts";
2+
import {
3+
assert,
4+
assertEquals,
5+
assertFalse,
6+
assertThrows,
7+
describe,
8+
it,
9+
} from "./_dev_deps.ts";
310

411
describe("parseList", () => {
512
it("should return", () => {
@@ -67,3 +74,65 @@ describe("parseList", () => {
6774
});
6875
});
6976
});
77+
78+
describe("isToken68", () => {
79+
it("should return true", () => {
80+
const table: string[] = [
81+
"a",
82+
"abcdefghijklmnopqrstuvwxyz",
83+
"ABCDEFGHIJKLMNOPQRSTUVWXYZ",
84+
"0123456789",
85+
"~",
86+
"+",
87+
"/",
88+
"-",
89+
"_",
90+
".",
91+
"a=",
92+
"a===========",
93+
];
94+
95+
table.forEach((input) => {
96+
assert(isToken68(input));
97+
});
98+
});
99+
100+
it("should return false", () => {
101+
const table: string[] = [
102+
"",
103+
" ",
104+
" a",
105+
"=",
106+
"あ",
107+
":",
108+
"`",
109+
"a=a",
110+
];
111+
112+
table.forEach((input) => {
113+
assertFalse(isToken68(input));
114+
});
115+
});
116+
});
117+
118+
describe("assertToken68", () => {
119+
it("should return void if the input is valid token68", () => {
120+
assertFalse(assertToken68("a=="));
121+
});
122+
123+
it("should throw error if the input is invalid token68", () => {
124+
assertThrows(() => assertToken68(""));
125+
assertThrows(() => assertToken68("?"));
126+
});
127+
});
128+
129+
describe("assertToken", () => {
130+
it("should return void if the input is valid token", () => {
131+
assertFalse(assertToken("a"));
132+
});
133+
134+
it("should throw error if the input is invalid token", () => {
135+
assertThrows(() => assertToken(""));
136+
assertThrows(() => assertToken("a=="));
137+
});
138+
});

0 commit comments

Comments
 (0)