70 lines
2.4 KiB
TypeScript
70 lines
2.4 KiB
TypeScript
import type { DevToolbarRule } from "./types.ts";
|
|
import { createIssue } from "./helpers.ts";
|
|
|
|
export const linkRules: DevToolbarRule[] = [
|
|
{
|
|
id: "links/basics",
|
|
category: "links",
|
|
defaultSeverity: "warning",
|
|
description: "Checks unsafe and incomplete links.",
|
|
run: ({ root, url }) => {
|
|
const issues = [];
|
|
for (const anchor of root.querySelectorAll<HTMLAnchorElement>("a")) {
|
|
const raw = anchor.getAttribute("href");
|
|
if (!raw || raw === "#")
|
|
issues.push(
|
|
createIssue({
|
|
ruleId: "links/empty",
|
|
category: "links",
|
|
severity: "warning",
|
|
title: "Link has no useful destination",
|
|
message: `The href is ${raw ? '"#"' : "missing"}.`,
|
|
element: anchor,
|
|
recommendation: "Provide a real URL or use a button for an action.",
|
|
}),
|
|
);
|
|
if (raw?.trim().toLowerCase().startsWith("javascript:"))
|
|
issues.push(
|
|
createIssue({
|
|
ruleId: "links/javascript-url",
|
|
category: "security",
|
|
severity: "error",
|
|
title: "JavaScript URL used",
|
|
message: "javascript: links are unsafe and inaccessible.",
|
|
element: anchor,
|
|
recommendation: "Use a button and a normal event handler.",
|
|
}),
|
|
);
|
|
if (
|
|
anchor.target === "_blank" &&
|
|
!anchor.rel.split(/\s+/).some((value) => value === "noopener" || value === "noreferrer")
|
|
)
|
|
issues.push(
|
|
createIssue({
|
|
ruleId: "links/blank-rel",
|
|
category: "security",
|
|
severity: "warning",
|
|
title: "New-tab link lacks rel protection",
|
|
message: "The opened page may retain access to window.opener.",
|
|
element: anchor,
|
|
recommendation: 'Add rel="noopener noreferrer".',
|
|
}),
|
|
);
|
|
if (raw?.startsWith("http://") && url.protocol === "https:")
|
|
issues.push(
|
|
createIssue({
|
|
ruleId: "links/mixed-content",
|
|
category: "security",
|
|
severity: "error",
|
|
title: "Insecure link on HTTPS page",
|
|
message: "This link uses HTTP from an HTTPS page.",
|
|
element: anchor,
|
|
recommendation: "Use an HTTPS destination.",
|
|
}),
|
|
);
|
|
}
|
|
return issues;
|
|
},
|
|
},
|
|
];
|