Skip to content

Commit 1d8ca39

Browse files
authored
Merge pull request #868 from jsonwebtoken/fix_newlines_support
fix: ensure newlines are supported in jwt input
1 parent 49a06b7 commit 1d8ca39

File tree

4 files changed

+62
-3
lines changed

4 files changed

+62
-3
lines changed

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,6 @@
6565
"prettier": "^3.2.5",
6666
"typescript": "^5.4.5",
6767
"vite-tsconfig-paths": "^4.3.2",
68-
"vitest": "^1.4.0"
68+
"vitest": "^1.6.1"
6969
}
7070
}

src/features/common/services/utils.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,14 @@ export const extractJwt = (value: string): string => {
2222
return "";
2323
}
2424

25-
const jwt = value.split(/\s+/).filter((element) => element.startsWith("ey"));
25+
// Check if it's a JWT string with newlines - compact it if so
26+
if (value.trim().startsWith("ey") && (value.match(/\./g) || []).length >= 2) {
27+
// It looks like a valid JWT, so remove all whitespace (including newlines)
28+
return value.replace(/\s+/g, "");
29+
}
2630

31+
// Otherwise, use the extraction logic to find JWT in a larger text block
32+
const jwt = value.split(/\s+/).filter((element) => element.startsWith("ey"));
2733
return jwt[0] || value;
2834
};
2935

tests/utils.test.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { describe, expect, test } from "vitest";
2+
import { extractJwt } from "@/features/common/services/utils";
3+
4+
describe("extractJwt", () => {
5+
test("should return empty string for empty input", () => {
6+
expect(extractJwt("")).toBe("");
7+
expect(extractJwt(null as unknown as string)).toBe("");
8+
expect(extractJwt(undefined as unknown as string)).toBe("");
9+
});
10+
11+
test("should extract JWT from normal input", () => {
12+
const jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c";
13+
expect(extractJwt(jwt)).toBe(jwt);
14+
});
15+
16+
test("should extract JWT with leading/trailing whitespace", () => {
17+
const jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c";
18+
const jwtWithSpaces = ` ${jwt} `;
19+
expect(extractJwt(jwtWithSpaces)).toBe(jwt);
20+
});
21+
22+
test("should compact multiline JWTs by removing all whitespace", () => {
23+
const multilineJWT = `eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.
24+
eyJjbGllbnRfaWQiOiJZekV6TUdkb01ISm5PSEJpT0cxaWJEaHlOVEE9IiwicmVzcG9uc2Vf
25+
dHlwZSI6ImNvZGUiLCJzY29wZSI6ImludHJvc2NwZWN0X3Rva2VucywgcmV2b2tlX3Rva2Vu
26+
cyIsImlzcyI6ImJqaElSak0xY1hwYWEyMXpkV3RJU25wNmVqbE1iazQ0YlRsTlpqazNkWEU9
27+
Iiwic3ViIjoiWXpFek1HZG9NSEpuT0hCaU9HMWliRGh5TlRBPSIsImF1ZCI6Imh0dHBzOi8v
28+
bG9jYWxob3N0Ojg0NDMve3RpZH0ve2FpZH0vb2F1dGgyL2F1dGhvcml6ZSIsImp0aSI6IjE1
29+
MTYyMzkwMjIiLCJleHAiOiIyMDIxLTA1LTE3VDA3OjA5OjQ4LjAwMCswNTQ1In0.
30+
IxvaN4ER-PlPgLYzfRhk_JiY4VAow3GNjaK5rYCINFsEPa7VaYnRsaCmQVq8CTgddihEPPXe
31+
t2laH8_c3WqxY4AeZO5eljwSCobCHzxYdOoFKbpNXIm7dqHg_5xpQz-YBJMiDM1ILOEsER8A
32+
DyF4NC2sN0K_0t6xZLSAQIRrHvpGOrtYr5E-SllTWHWPmqCkX2BUZxoYNK2FWgQZpuUOD55H
33+
fsvFXNVQa_5TFRDibi9LsT7Sd_az0iGB0TfAb0v3ZR0qnmgyp5pTeIeU5UqhtbgU9RnUCVmG
34+
IK-SZYNvrlXgv9hiKAZGhLgeI8hO40utfT2YTYHgD2Aiufqo3RIbJA`;
35+
36+
const compactedJWT = multilineJWT.replace(/\s+/g, "");
37+
expect(extractJwt(multilineJWT)).toBe(compactedJWT);
38+
});
39+
40+
test("should extract JWT from text with other content", () => {
41+
const jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c";
42+
const textWithJWT = `Here is my token: ${jwt} and some other text`;
43+
expect(extractJwt(textWithJWT)).toBe(jwt);
44+
});
45+
46+
test("should compact JWT with internal spaces", () => {
47+
// This is a scenario where the JWT itself contains spaces (invalid, but should be handled)
48+
const jwtWithSpaces = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0 NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c";
49+
// The spaces should be removed by our new implementation
50+
const compactedJWT = jwtWithSpaces.replace(/\s+/g, "");
51+
expect(extractJwt(jwtWithSpaces)).toBe(compactedJWT);
52+
});
53+
});

0 commit comments

Comments
 (0)