Skip to content

Commit

Permalink
feat: added url-sanitization function (#110)
Browse files Browse the repository at this point in the history
* feat: added url-sanitization function

* chore: fixed regex const

* chore: added constants and updated code

* chore: added tests, fixed build issues

* chore: removed modified dist files
  • Loading branch information
prashantjagasia committed Oct 17, 2023
1 parent 6b054d8 commit 6dfe213
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 1 deletion.
12 changes: 12 additions & 0 deletions src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,15 @@ export const ATTRIBUTES = {
};

export const UID_HASH_LENGTH = 30;

/* eslint-disable no-control-regex*/
export const invalidProtocolRegex: RegExp =
/([^\w]*)(javascript|data|vbscript)/im;
export const htmlEntitiesRegex: RegExp = /&#(\w+)(^\w|;)?/g;
export const htmlCtrlEntityRegex: RegExp = /&(newline|tab);/gi;
export const ctrlCharactersRegex: RegExp =
/[\u0000-\u001F\u007F-\u009F\u2000-\u200D\uFEFF]/gim;
export const urlSchemeRegex: RegExp = /^.+(:|:)/gim;
export const relativeFirstCharacters = [".", "/"];
export const BLANK_URL = "about:blank";
/* eslint-enable no-control-regex*/
54 changes: 53 additions & 1 deletion src/util.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
/* @flow */
/* eslint max-lines: 0 */

import { ZalgoPromise } from "@krakenjs/zalgo-promise/src";
import { WeakMap } from "@krakenjs/cross-domain-safe-weakmap/src";

import {
BLANK_URL,
ctrlCharactersRegex,
htmlCtrlEntityRegex,
htmlEntitiesRegex,
invalidProtocolRegex,
relativeFirstCharacters,
urlSchemeRegex,
} from "./constants";
import type { CancelableType } from "./types";

export function isElement(element: mixed): boolean {
Expand Down Expand Up @@ -1370,3 +1378,47 @@ export class ExtendableError extends Error {
}
}
}

function isRelativeUrlWithoutProtocol(url: string): boolean {
return relativeFirstCharacters.indexOf(url[0]) > -1;
}

function decodeHtmlCharacters(str: string): string {
const removedNullByte: string = str.replace(ctrlCharactersRegex, "");
return removedNullByte.replace(htmlEntitiesRegex, (matchRegex, dec) => {
return String.fromCharCode(dec);
});
}

export function sanitizeUrl(url?: string): string {
if (!url) {
return BLANK_URL;
}

const sanitizedUrl = decodeHtmlCharacters(url)
.replace(htmlCtrlEntityRegex, "")
.replace(ctrlCharactersRegex, "")
.trim();

if (!sanitizedUrl) {
return BLANK_URL;
}

if (isRelativeUrlWithoutProtocol(sanitizedUrl)) {
return sanitizedUrl;
}

const urlSchemeParseResults = sanitizedUrl.match(urlSchemeRegex);

if (!urlSchemeParseResults) {
return sanitizedUrl;
}

const urlScheme = urlSchemeParseResults[0];

if (invalidProtocolRegex.test(urlScheme)) {
return BLANK_URL;
}

return sanitizedUrl;
}
1 change: 1 addition & 0 deletions test/tests/util/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ import "./stringifyErrorMessage";
import "./isRegex";
import "./isDefined";
import "./base64encode";
import "./sanitizeUrl";
31 changes: 31 additions & 0 deletions test/tests/util/sanitizeUrl.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/* @flow */

import { sanitizeUrl } from "../../../src/util";

describe("sanitizeUrl", () => {
it("should return about:blank for malicious URLs", () => {
const testURL =
'https://www.paypal.com/smart/checkout/venmo/popup?parentDomain=www.paypal.com&venmoWebEnabled=true&venmoWebUrl=javascript:alert(document["cookie"])//';
const sanitizedUrl = sanitizeUrl(testURL);

if (sanitizedUrl !== "about:blank") {
throw new Error(
`Does not match. Original data:\n\n${testURL}
\n\nSanitized:\n\n${"about:blank"}\n`
);
}
});

it("should return original URL when URL is clean", () => {
const testURL =
"https://www.paypal.com/smart/checkout/venmo/popup?parentDomain=www.paypal.com&venmoWebEnabled=true&venmoWebUrl=www.venmo.com";
const sanitizedUrl = sanitizeUrl(testURL);

if (sanitizedUrl !== testURL) {
throw new Error(
`Does not match. Original data:\n\n${testURL}
\n\nSanitized:\n\n${sanitizedUrl}\n`
);
}
});
});

0 comments on commit 6dfe213

Please sign in to comment.