Skip to content

Instantly share code, notes, and snippets.

@kwilczynski
Last active May 13, 2023 09:09
Show Gist options
  • Save kwilczynski/ba19cf331ae43911fd7527a8874445d7 to your computer and use it in GitHub Desktop.
Save kwilczynski/ba19cf331ae43911fd7527a8874445d7 to your computer and use it in GitHub Desktop.
Simple Chrome extension that replaces Git commit IDs and URL with proper links
var textAreasCount = 0;
var linesCount = 0;
var linesReplaced = 0;
var linesSkipped = 0;
var start = performance.now();
function formatMilliseconds(ms) {
return Number.parseFloat(ms.toFixed(3))
}
function escapeHTML(html) {
return (new Option(html).innerHTML);
}
function findTextNodes(body) {
let walker = document.createTreeWalker(body, NodeFilter.SHOW_TEXT,
function(node) {
if (node.textContent.length === 0) {
return NodeFilter.FILTER_SKIP;
}
textAreasCount++;
return NodeFilter.FILTER_ACCEPT;
},
false);
let nodes = [];
while (walker.nextNode()) {
nodes.push(walker.currentNode);
}
return nodes;
}
function getMailingListURL() {
const DEFAULT_LINK = '<a href="https://git.kernel.org/linus/$1">$1</a>';
if (!window.location.host === 'lore.kernel.org')
return DEFAULT_LINK;
if (match = window.location.pathname.match(/\/(.+?)\//)) {
let path = match[1];
switch(path) {
case 'qemu-devel':
return '<a href="https://git.qemu.org/?p=qemu.git&a=commitdiff&h=$1">$1</a>';
default:
return DEFAULT_LINK;
}
}
}
findTextNodes(document.body).forEach(function(node) {
let text = node.textContent;
let lines = [];
const CVE_LINK = '<a href="https://cve.mitre.org/cgi-bin/cvename.cgi?name=$1">$1</a>';
const ZDI_LINK = '<a href="https://www.zerodayinitiative.com/advisories/$1/">$1</a>';
const GENERIC_LINK = '$1<a href="$2">$2</a>';
const TAGS = [
'acked-by:',
'co-developed-by:',
'reported-by:',
'reviewed-by:',
'signed-off-by:',
'suggested-by',
'tested-by:'
];
const REGISTERS = [
'CR0:', 'CR2:', 'CR3:',
'CR4:', 'DR0:', 'DR1:',
'DR2:', 'DR3:', 'DR6:',
'DR7:', 'EAX:', 'EBP:',
'EBX:', 'ECX:', 'EDI:',
'EDX:', 'EIP:', 'ESI:',
'ESP:', 'R08:', 'R09:',
'R10:', 'R11:', 'R12:',
'R13:', 'R14:', 'R15:',
'RAX:', 'RBP:', 'RBX:',
'RCX:', 'RDI:', 'RDX:',
'RSI:', 'RSP:'
];
text.split('\n').forEach(function(line) {
linesCount++;
if (line.length === 0) {
linesSkipped++;
lines.push("");
return;
}
if (line.length < 8) {
linesSkipped++;
lines.push(line);
return;
}
// Skip elements that are commonly seen in the "lspci" output.
if (line.match(/(Region .+ Memory at|Expansion ROM( at|@))/)) {
linesSkipped++;
lines.push(line);
return;
}
// Skip elements that are commonly seen in the "lspci" output and
// might look like HTML tags. Try to match before matching HTML tags.
if (line.match(/(Secondary status: |Status: |Capabilities: |Bridge(.+)?: |(.+)?<\?>)/)) {
linesSkipped++;
lines.push(escapeHTML(line));
return;
}
// Match anything that looks like an HTML tag.
if (line.match(/<\s*\w+[^>]*>|<\s*\w+[^>]*>(.*?)<\s*\/\s*\w+>/)) {
// Match URL enclosed in a set of angle brackets, and pass along if found.
if (!line.match(/(.+)?<https?:\/\//)) {
linesSkipped++;
lines.push(escapeHTML(line));
return;
}
}
// Skip common elements in the kernel panic and/or Oops messages such as
// various CPU registers, etc.
if (line.match('(EFLAGS:|' + REGISTERS.join('|') + '\\s+[0-9a-f]{8})')) {
linesSkipped++;
lines.push(line);
return;
}
// Skip common elements that might match special "Link:" tag.
if (line.match(/(?<=Link:)(\s+)?[0-9a-f]{8}(\s+)?/)) {
linesSkipped++;
lines.push(line);
return;
}
// Skip common elements that are present in the backtrace.
if (line.match(/(<[0-9a-f]{8}>|((f|i|s)p|r\d+)(\s+)?:(\s+)?[0-9a-f]{8}|\s.+=[0-9a-f]{8}|]?\s{2}([a-f0-9]{8}\s?){8}|\s?0x[a-f0-9]{8,16}\s?|\sx\d{1,2}\s?: [a-f0-9]{8,16})|\b[0-9a-f]{8}\.\w+|\w+\@[0-9a-f]{8}\b/)) {
linesSkipped++;
lines.push(line);
return;
}
// Skip more specific elements of backtrace.
if (line.match(/(Read of size \d+ at .+ [0-9a-f]+ by task|task: .+ task\.(\w+): |Register .+ information: |\[ end trace .+ \])/)) {
linesSkipped++;
lines.push(line);
return;
}
// Skip elements that are commonly seen in the "lspci" output.
if (line.match(/(Region .+ Memory at|Expansion ROM( at|@))/)) {
linesSkipped++;
lines.push(line);
return;
}
// Skip anything that looks like disassembled instructions.
if (line.match(/[a-f0-9]+:\s+[a-f0-9]{8}\s+\w+/)) {
linesSkipped++;
lines.push(line);
return;
}
// Skip line matching kernel version (as seen in the kernel ring buffer).
if (line.match(/Linux version .+ \(.+ GCC [\d\.]+ .+\)/)) {
linesSkipped++;
lines.push(line);
return;
}
// Match common tags used in e-mails e.g., "Reviewed-by", etc.
if (line.toLowerCase().match('(' + TAGS.join('|') + ')')) {
linesSkipped++;
lines.push(escapeHTML(line));
return;
}
// Match common CVE and/or ZDI references.
if (line.match(/(CVE-\d{4}-\d{4,7}|ZDI-[\w\d]+-\d{3,5})/)) {
linesReplaced++;
line = line.replace(/(CVE-\d{4}-\d{4,7})/g, CVE_LINK);
line = line.replace(/(ZDI-[\w\d]+-\d{3,5})/g, ZDI_LINK);
lines.push(line);
return;
}
// Match anything that looks like an URL.
if (line.match(/(.+)?https?:\/\//)) {
// Skip lines that document how to perform a Git checkout.
if (line.match(/^\s+(git clone|public-inbox-init)\s/)) {
linesSkipped++;
lines.push(line);
return;
}
// Match an URL up to a whitespace character or at the word boundary,
// and turn the URL into a proper link.
linesReplaced++;
lines.push(line.replace(/(.+)?(https?:\/\/(.+\s+|.+\b))/, GENERIC_LINK));
return;
}
// Match the "Fixes:" tag and turn into a proper and correct link.
if (line.match(/Fixes: [0-9a-f]{8,16}\b/)) {
linesReplaced++;
lines.push(line.replace(/([0-9a-f]{8,16})\b/, getMailingListURL()));
return;
}
// Match special "Link:" tag and turn URL it mentions into a proper link.
if (line.match(/.+Link: https?:\/\//)) {
linesReplaced++;
lines.push(line.replace(/(.+)(https?:\/\/.+)/, GENERIC_LINK));
return;
}
// Skip any line that does not contain any resemblence of the Git commit ID,
// incuding a possible false positives such as "added", etc., that could
// possibly match the provided regular expression.
if (match = line.match(/[0-9a-f]{8,40}/)) {
let candidate = match[0];
if (candidate.match(/^\d+$/) || candidate.match(/^[a-f]+$/)) {
linesSkipped++;
lines.push(line);
return;
}
}
// Skip line included in the unified Diff that contains two commit IDs.
if (line.match(/index\s[0-9a-f]{5,}\.\.[0-9a-f]{5,}\s/)) {
linesSkipped++;
lines.push(line);
return;
}
// Match long SHA1 of the commit ID and turn it into a proper link.
if (line.match(/\b[0-9a-f]{40}\b/)) {
let link = getMailingListURL()
if (!link) {
linesSkipped++;
lines.push(line);
return
}
linesReplaced++;
lines.push(line.replace(/\b([0-9a-f]{40})\b/g, link));
return;
}
// Match preferred format for citing Git commits, and turn the Git
// commit ID into a proper link.
if (line.match(/(commit|Commit)\s([0-9a-f]{8,40})/)) {
linesReplaced++;
lines.push(line.replace(/\b([0-9a-f]{8,40})\b/g, getMailingListURL()));
return;
}
// Match anything that resembles short SHA1 of a commit ID.
if (line.match(/[0-9a-f]{8,16}/)) {
// Match anything that looks like preferred format for citing Git commits,
// but only match the first half of it, as the subject line will not be used,
// and turn the Git commit ID into a proper link.
if (line.match(/[0-9a-f]{8,16} \(".+("\))?/)) {
linesReplaced++;
lines.push(line.replace(/\b([0-9a-f]{8,16})\b/g, getMailingListURL()));
return;
}
// Match anything that looks like the Git commit ID that might have been
// cited within the commit message itself and between other words,
// and turn it into a proper link.
if (line.match(/\b[\(]?([0-9a-f]{8,16})[\.,:\()]?\s+?\b/)) {
linesReplaced++;
lines.push(line.replace(/\b([0-9a-f]{8,16})\b/g, getMailingListURL()));
return;
}
// Match short SHA1 of the commit ID and turn it into a proper link.
if (line.match(/\s([0-9a-f]{8,16})\s/)) {
linesReplaced++;
lines.push(line.replace(/([0-9a-f]{8,16})/g, getMailingListURL()));
return;
}
}
linesSkipped++;
lines.push(line);
})
let replacedText = lines.join('\n');
if (replacedText !== text) {
let span = document.createElement('span');
span.innerHTML = replacedText;
node.parentNode.replaceChild(span, node);
}
});
console.log(JSON.stringify({
url: window.location.href,
count: {
textAreas: textAreasCount,
lines: {
total: linesCount,
replaced: linesReplaced,
skipped: linesSkipped,
},
},
elapsed_milliseconds: formatMilliseconds(performance.now() - start),
}, null, 2));
{
"manifest_version": 3,
"name": "Bjorn's link updater",
"description": "Update all matching Git commits IDs with a link to the official Git kernel repository, and detect URLs converting them into usable links.",
"version": "0.16.0",
"content_scripts": [
{
"matches": [
"https://lore.kernel.org/*/*",
"https://lkml.org/lkml/*",
"https://git.kernel.org/pub/scm/*",
"https://git.qemu.org/*",
"https://patchwork.kernel.org/project/*/cover/*",
"https://patchwork.kernel.org/project/*/patch/*"
],
"all_frames": true,
"js": [
"content.js"
],
"run_at": "document_end"
}
]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment