[IMP] web: url utils: add redirect function

This function must be used to safely redirect to another url. It
ensures that we stay on the same origin, and thus that the url is
safe.

Part-of: odoo/odoo#138054
This commit is contained in:
Aaron Bohy
2023-10-11 08:18:46 +00:00
parent 7470797be7
commit 634409188c
2 changed files with 52 additions and 2 deletions
+17
View File
@@ -3,6 +3,8 @@
import { session } from "@web/session";
import { browser } from "../browser/browser";
export class RedirectionError extends Error {}
/**
* Transforms a key value mapping to a string formatted as url hash, e.g.
* {a: "x", b: 2} -> "a=x&b=2"
@@ -83,3 +85,18 @@ export function getDataURLFromFile(file) {
reader.readAsDataURL(file);
});
}
/**
* Safely redirects to the given url within the same origin.
*
* @param {string} url
* @throws {RedirectionError} if the given url has a different origin
*/
export function redirect(url) {
const { origin, pathname } = browser.location;
const _url = new URL(url, `${origin}${pathname}`);
if (_url.origin !== origin) {
throw new RedirectionError("Can't redirect to another origin");
}
browser.location = _url.href;
}
@@ -1,7 +1,13 @@
/** @odoo-module */
import { browser } from "@web/core/browser/browser";
import { getDataURLFromFile, getOrigin, url } from "@web/core/utils/urls";
import {
getDataURLFromFile,
getOrigin,
redirect,
RedirectionError,
url,
} from "@web/core/utils/urls";
import { patchWithCleanup } from "../../helpers/utils";
QUnit.module("URLS", (hooks) => {
@@ -63,6 +69,33 @@ QUnit.module("URLS", (hooks) => {
QUnit.test("getDataURLFromFile handles empty file", async (assert) => {
const emptyFile = new File([""], "empty.txt", { type: "text/plain" });
const dataUrl = await getDataURLFromFile(emptyFile);
assert.strictEqual(dataUrl, "data:text/plain;base64,", "dataURL for empty file is not proper");
assert.strictEqual(
dataUrl,
"data:text/plain;base64,",
"dataURL for empty file is not proper"
);
});
QUnit.test("redirect", (assert) => {
function testRedirect(url) {
browser.location = {
protocol: "http:",
host: "testhost",
origin: "http://www.test.com",
pathname: "/some/tests",
};
redirect(url);
return browser.location;
}
assert.strictEqual(testRedirect("abc"), "http://www.test.com/some/abc");
assert.strictEqual(testRedirect("./abc"), "http://www.test.com/some/abc");
assert.strictEqual(testRedirect("../abc/def"), "http://www.test.com/abc/def");
assert.strictEqual(testRedirect("/abc/def"), "http://www.test.com/abc/def");
assert.strictEqual(testRedirect("/abc/def?x=y"), "http://www.test.com/abc/def?x=y");
assert.strictEqual(testRedirect("/abc?x=y#a=1&b=2"), "http://www.test.com/abc?x=y#a=1&b=2");
assert.throws(() => testRedirect("https://www.odoo.com"), RedirectionError);
assert.throws(() => testRedirect("javascript:alert('boom');"), RedirectionError);
});
});