Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Warnings

/* Any copyright is dedicated to the Public Domain.
"use strict";
const BASE_INVALID_LINKS = [
{ title: "Missing URI" },
{
title: "Valid link. This will be trimmed".repeat(101),
uri: "https://example.com?" + "a".repeat(4000),
},
{
title: "A string url. Will fail regex match",
uri: "invalid-url that will be removed by makeValidLink function",
},
{
title: "About link. Will fail regex match",
uri: "about:robots",
},
{
title: "Will pass regex but fail URL constructor and be removed",
uri: "https",
},
{
title: "Will pass regex but fail URL constructor and be removed",
uri: "https://",
},
{
title: "Unencoded braces pass WHATWG URL but fail schema format: uri",
},
];
const INVALID_TABS_SHARE = {
title: "tabs".repeat(101),
type: "tabs",
children: [
...BASE_INVALID_LINKS,
...Array.from({ length: 30 }, (_, i) => ({
title: `Example link ${i}`,
})),
],
};
const INVALID_TABGROUP_SHARE = {
title: "tab_group".repeat(101),
type: "tab_group",
children: [
...BASE_INVALID_LINKS,
...Array.from({ length: 30 }, (_, i) => ({
title: `Example link ${i}`,
})),
],
};
const INVALID_BOOKMARKS_SHARE = {
title: "bookmarks".repeat(101),
type: "bookmarks",
children: [
...BASE_INVALID_LINKS,
{
type: "bookmarks",
title: "Nested bookmark folder".repeat(101),
children: [
...BASE_INVALID_LINKS,
{
type: "bookmarks",
title: "Doubly Nested bookmark folder".repeat(101),
children: [
...BASE_INVALID_LINKS,
...Array.from({ length: 30 }, (_, i) => ({
title: `Doubly Nested Example link ${i}`,
})),
],
},
],
},
...Array.from({ length: 30 }, (_, i) => ({
title: `Example link ${i}`,
})),
],
};
const INVALID_BOOKMARKS_SHARE_2 = {
title: "Many nested bookmarks",
type: "bookmarks",
children: [],
};
function makeManyNestedBookmarks(depth) {
if (depth > 35) {
return [
{
title: `Link at depth ${depth}`,
uri: `https://example.com/${depth}`,
},
];
}
const bookmark = {
type: "bookmarks",
title: `Nested bookmark folder at depth ${depth}`,
children: [makeManyNestedBookmarks(depth + 1)],
};
return bookmark;
}
const INVALID_BOOKMARKS_SHARE_3 = {
title: "Many nested bookmarks",
type: "bookmarks",
children: [],
};
function makeManyNestedBookmarksWithLink(depth) {
if (depth > 35) {
return [
{
title: `Link at depth ${depth}`,
uri: `https://example.com/${depth}`,
},
];
}
const bookmark = {
type: "bookmarks",
title: `Nested bookmark folder at depth ${depth}`,
children: [
{
title: `Link at depth ${depth}`,
uri: `https://example.com/${depth}`,
},
makeManyNestedBookmarksWithLink(depth + 1),
],
};
return bookmark;
}
add_task(async function test_makeValid() {
INVALID_BOOKMARKS_SHARE_2.children.push(makeManyNestedBookmarks(0));
INVALID_BOOKMARKS_SHARE_3.children.push(makeManyNestedBookmarksWithLink(0));
// buildShare drops individual invalid links synchronously, so the per-link
// validator must be loaded first.
await ContentSharingUtils.getLinkValidator();
for (let [invalidShare, shouldPass] of [
[INVALID_TABS_SHARE, true],
[INVALID_TABGROUP_SHARE, true],
[INVALID_BOOKMARKS_SHARE, true],
[INVALID_BOOKMARKS_SHARE_2, false],
[INVALID_BOOKMARKS_SHARE_3, true],
]) {
let shareResult = ContentSharingUtils.buildShare(invalidShare);
shareResult = await ContentSharingUtils.validateSchema(shareResult);
if (shouldPass) {
Assert.equal(
shareResult.error,
null,
"There should be no error in the share result"
);
} else {
Assert.equal(
shareResult.error,
ERRORS.INVALID_SCHEMA,
"ERRORS.INVALID_SCHEMA should be set on the share result"
);
}
}
});
add_task(async function test_dropsInvalidLinksKeepsValid() {
await ContentSharingUtils.getLinkValidator();
const MIXED_SHARE = {
title: "Mixed tabs",
type: "tabs",
children: [
{ title: "Good", uri: "https://example.com/good" },
{
title: "Bad braces",
},
{ title: "Also good", uri: "https://example.com/also-good" },
],
};
let shareResult = ContentSharingUtils.buildShare(MIXED_SHARE);
Assert.equal(
shareResult.share.links.length,
2,
"The link with unencoded braces should be dropped, keeping the two valid links"
);
Assert.ok(
shareResult.share.links.every(link => !link.url.includes("{")),
"No surviving link should contain unencoded braces"
);
shareResult = await ContentSharingUtils.validateSchema(shareResult);
Assert.equal(
shareResult.error,
null,
"A share with at least one valid link should not error"
);
});
add_task(async function test_allInvalidLinksErrors() {
await ContentSharingUtils.getLinkValidator();
const ALL_INVALID_SHARE = {
title: "All invalid tabs",
type: "tabs",
children: [
{ title: "Braces", uri: "https://example.com/?a={b}" },
{ title: "About", uri: "about:robots" },
],
};
let shareResult = ContentSharingUtils.buildShare(ALL_INVALID_SHARE);
Assert.equal(
shareResult.share.links.length,
0,
"All links should be dropped"
);
shareResult = await ContentSharingUtils.validateSchema(shareResult);
Assert.equal(
shareResult.error,
ERRORS.INVALID_SCHEMA,
"A share with no valid links should error with INVALID_SCHEMA"
);
});