@ez1219/sanitize-url 7.1.2-rc.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/src/index.ts ADDED
@@ -0,0 +1,114 @@
1
+ import {
2
+ BLANK_URL,
3
+ ctrlCharactersRegex,
4
+ htmlCtrlEntityRegex,
5
+ htmlEntitiesRegex,
6
+ invalidProtocolRegex,
7
+ relativeFirstCharacters,
8
+ whitespaceEscapeCharsRegex,
9
+ urlSchemeRegex,
10
+ } from "./constants";
11
+
12
+ function isRelativeUrlWithoutProtocol(url: string): boolean {
13
+ return relativeFirstCharacters.indexOf(url[0]) > -1;
14
+ }
15
+
16
+ function decodeHtmlCharacters(str: string) {
17
+ const removedNullByte = str.replace(ctrlCharactersRegex, "");
18
+ return removedNullByte.replace(htmlEntitiesRegex, (match, dec) => {
19
+ return String.fromCharCode(dec);
20
+ });
21
+ }
22
+
23
+ function isValidUrl(url: string): boolean {
24
+ if (typeof URL !== "undefined" && typeof URL.canParse === "function") {
25
+ return URL.canParse(url);
26
+ }
27
+ try {
28
+ return Boolean(new URL(url));
29
+ } catch {
30
+ return false;
31
+ }
32
+ }
33
+
34
+ function decodeURI(uri: string): string {
35
+ try {
36
+ return decodeURIComponent(uri);
37
+ } catch (e: unknown) {
38
+ // Ignoring error
39
+ // It is possible that the URI contains a `%` not associated
40
+ // with URI/URL-encoding.
41
+ return uri;
42
+ }
43
+ }
44
+
45
+ export function sanitizeUrl(url?: string): string {
46
+ if (!url) {
47
+ return BLANK_URL;
48
+ }
49
+
50
+ let charsToDecode;
51
+ let decodedUrl = decodeURI(url.trim());
52
+
53
+ do {
54
+ decodedUrl = decodeHtmlCharacters(decodedUrl)
55
+ .replace(htmlCtrlEntityRegex, "")
56
+ .replace(ctrlCharactersRegex, "")
57
+ .replace(whitespaceEscapeCharsRegex, "")
58
+ .trim();
59
+
60
+ decodedUrl = decodeURI(decodedUrl);
61
+
62
+ charsToDecode =
63
+ decodedUrl.match(ctrlCharactersRegex) ||
64
+ decodedUrl.match(htmlEntitiesRegex) ||
65
+ decodedUrl.match(htmlCtrlEntityRegex) ||
66
+ decodedUrl.match(whitespaceEscapeCharsRegex);
67
+ } while (charsToDecode && charsToDecode.length > 0);
68
+
69
+ const sanitizedUrl = decodedUrl;
70
+
71
+ if (!sanitizedUrl) {
72
+ return BLANK_URL;
73
+ }
74
+
75
+ if (isRelativeUrlWithoutProtocol(sanitizedUrl)) {
76
+ return sanitizedUrl;
77
+ }
78
+
79
+ // Remove any leading whitespace before checking the URL scheme
80
+ const trimmedUrl = sanitizedUrl.trimStart();
81
+ const urlSchemeParseResults = trimmedUrl.match(urlSchemeRegex);
82
+
83
+ if (!urlSchemeParseResults) {
84
+ return sanitizedUrl;
85
+ }
86
+
87
+ const urlScheme = urlSchemeParseResults[0].toLowerCase().trim();
88
+
89
+ if (invalidProtocolRegex.test(urlScheme)) {
90
+ return BLANK_URL;
91
+ }
92
+
93
+ const backSanitized = trimmedUrl.replace(/\\/g, "/");
94
+
95
+ // Handle special cases for mailto: and custom deep-link protocols
96
+ if (urlScheme === "mailto:" || urlScheme.includes("://")) {
97
+ return backSanitized;
98
+ }
99
+
100
+ // For http and https URLs, perform additional validation
101
+ if (urlScheme === "http:" || urlScheme === "https:") {
102
+ if (!isValidUrl(backSanitized)) {
103
+ return BLANK_URL;
104
+ }
105
+
106
+ const url = new URL(backSanitized);
107
+ url.protocol = url.protocol.toLowerCase();
108
+ url.hostname = url.hostname.toLowerCase();
109
+
110
+ return url.toString();
111
+ }
112
+
113
+ return backSanitized;
114
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,12 @@
1
+ {
2
+ "compilerOptions": {
3
+ "outDir": "./dist",
4
+ "allowJs": true,
5
+ "strict": true,
6
+ "target": "es5",
7
+ "resolveJsonModule": true,
8
+ "lib": ["es2015", "dom"]
9
+ },
10
+ "include": ["./src/**/*"],
11
+ "exclude": ["**/__tests__/*"]
12
+ }
@@ -0,0 +1,17 @@
1
+ import { defineConfig } from "vitest/config";
2
+
3
+ export default defineConfig({
4
+ test: {
5
+ globals: true,
6
+ environment: "happy-dom",
7
+ coverage: {
8
+ enabled: true,
9
+ thresholds: {
10
+ lines: 80,
11
+ statements: 80,
12
+ branches: 80,
13
+ functions: 80,
14
+ },
15
+ },
16
+ },
17
+ });