Merge pull request #2729 from PR0M3TH3AN/security-fix-qrcode-innerhtml-16143867429725848701

Refactor qrcode.js to eliminate unsafe innerHTML usage
This commit is contained in:
thePR0M3TH3AN authored and GitHub committed 2026-02-26 14:42:43 -05:00
commit cb1a0fec00
2 files changed
+30 -29

No files matched your search

+13 -13
View File
@@ -337,8 +337,13 @@ if (hasDocument) {
var nWidth = Math.floor(_htOption.width / nCount); var nWidth = Math.floor(_htOption.width / nCount);
var nHeight = Math.floor(_htOption.height / nCount); var nHeight = Math.floor(_htOption.height / nCount);
var table = document.createElement("table"); // Clear existing content
table.className = "qr-code__table"; while (_el.firstChild) {
_el.removeChild(_el.firstChild);
}
var elTable = document.createElement("table");
elTable.className = "qr-code__table";
updateQrCodeContainerStyles(_el, { updateQrCodeContainerStyles(_el, {
colorDark: _htOption.colorDark, colorDark: _htOption.colorDark,
@@ -349,27 +354,22 @@ if (hasDocument) {
}); });
for (var row = 0; row < nCount; row++) { for (var row = 0; row < nCount; row++) {
var tr = document.createElement("tr"); var elRow = document.createElement("tr");
for (var col = 0; col < nCount; col++) { for (var col = 0; col < nCount; col++) {
var td = document.createElement("td"); var elCell = document.createElement("td");
td.className = oQRCode.isDark(row, col) elCell.className = oQRCode.isDark(row, col)
? "qr-code__cell qr-code__cell--dark" ? "qr-code__cell qr-code__cell--dark"
: "qr-code__cell"; : "qr-code__cell";
tr.appendChild(td); elRow.appendChild(elCell);
} }
table.appendChild(tr); elTable.appendChild(elRow);
} }
// Clear previous content _el.appendChild(elTable);
while (_el.firstChild) {
_el.removeChild(_el.firstChild);
}
_el.appendChild(table);
// Fix the margin values as real size. // Fix the margin values as real size.
var elTable = table;
var nLeftMarginTable = (_htOption.width - (nCount * nWidth)) / 2; var nLeftMarginTable = (_htOption.width - (nCount * nWidth)) / 2;
var nTopMarginTable = (_htOption.height - (nCount * nHeight)) / 2; var nTopMarginTable = (_htOption.height - (nCount * nHeight)) / 2;
+17 -16
View File
@@ -1,26 +1,29 @@
import { test, describe } from 'node:test'; import { test } from 'node:test';
import assert from 'node:assert'; import assert from 'node:assert';
import { JSDOM } from 'jsdom'; import { JSDOM } from 'jsdom';
describe('QRCode Table Fallback', () => { test('QR Code Table Fallback', async (t) => {
test('should generate table when Canvas is not supported', async () => { // Setup JSDOM
const dom = new JSDOM(`<!DOCTYPE html><body><div id="qrcode"></div></body>`); const dom = new JSDOM(`<!DOCTYPE html><body><div id="qrcode"></div></body>`);
// Set up global environment for the library // Override globals to simulate browser environment provided by JSDOM
global.document = dom.window.document; // We need to override what setup-localstorage.mjs might have set
global.window = dom.window; global.window = dom.window;
global.document = dom.window.document;
global.HTMLStyleElement = dom.window.HTMLStyleElement; global.HTMLStyleElement = dom.window.HTMLStyleElement;
global.HTMLElement = dom.window.HTMLElement; global.HTMLElement = dom.window.HTMLElement;
global.WeakMap = dom.window.WeakMap || global.WeakMap;
global.Map = dom.window.Map || global.Map;
// Ensure CanvasRenderingContext2D is NOT defined to trigger table fallback // Copy other properties if needed, but these should be enough for qrcode.js
delete global.CanvasRenderingContext2D;
delete global.window.CanvasRenderingContext2D;
// Ensure we are not in SVG mode (JSDOM default is HTML) // Ensure CanvasRenderingContext2D is NOT defined to trigger the table fallback
if (global.CanvasRenderingContext2D) {
delete global.CanvasRenderingContext2D;
}
if (global.window.CanvasRenderingContext2D) {
delete global.window.CanvasRenderingContext2D;
}
// Import the module dynamically // Dynamically import the module to ensure it uses the current environment
const { createQrCode } = await import('../js/utils/qrcode.js'); const { createQrCode } = await import('../js/utils/qrcode.js');
const el = global.document.getElementById('qrcode'); const el = global.document.getElementById('qrcode');
@@ -28,16 +31,14 @@ describe('QRCode Table Fallback', () => {
// Create QR code // Create QR code
createQrCode(el, { text: "test", width: 100, height: 100 }); createQrCode(el, { text: "test", width: 100, height: 100 });
// Verify table is used // Verify table is used (this confirms we hit the refactored code path)
const table = el.querySelector('table'); const table = el.querySelector('table');
assert.ok(table, "Table element should be created"); assert.ok(table, "Table should be created when canvas is not supported");
assert.ok(table.classList.contains('qr-code__table'), "Table should have correct class"); assert.ok(table.classList.contains('qr-code__table'), "Table should have correct class");
// Check for table structure
const rows = table.querySelectorAll('tr'); const rows = table.querySelectorAll('tr');
assert.ok(rows.length > 0, "Should have rows"); assert.ok(rows.length > 0, "Should have rows");
const cells = table.querySelectorAll('td'); const cells = table.querySelectorAll('td');
assert.ok(cells.length > 0, "Should have cells"); assert.ok(cells.length > 0, "Should have cells");
});
}); });