-
Notifications
You must be signed in to change notification settings - Fork 38
Expand file tree
/
Copy pathcheck_logos.js
More file actions
executable file
·119 lines (96 loc) · 3.79 KB
/
check_logos.js
File metadata and controls
executable file
·119 lines (96 loc) · 3.79 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#!/usr/bin/env node
import fs from 'fs';
import path from 'path';
import { JSDOM } from 'jsdom';
import createDOMPurify from 'dompurify';
let foundUnsafe = false;
const files = fs.readdirSync('.')
.filter(file => file.endsWith('.svg'))
.filter(file => fs.statSync(file).isFile());
if (files.length === 0) {
console.log('No SVG files found');
process.exit(0);
}
for (const file of files) {
try {
const svgContent = fs.readFileSync(file, 'utf8');
const dom = new JSDOM('<!DOCTYPE html>');
const DOMPurify = createDOMPurify(dom.window);
const cleanSVG = DOMPurify.sanitize(svgContent, {
USE_PROFILES: { svg: true },
KEEP_CONTENT: true
});
const issues = [];
const scriptMatches = svgContent.match(/<script[\s>][\s\S]*?<\/script>/gi);
if (scriptMatches) {
issues.push(`Found ${scriptMatches.length} script tag(s)`);
}
const eventHandlers = svgContent.match(/\s(on\w+)\s*=/gi);
if (eventHandlers) {
const uniqueHandlers = [...new Set(eventHandlers.map(h => h.trim().toLowerCase()))];
issues.push(`Found event handlers: ${uniqueHandlers.join(', ')}`);
}
if (/javascript:/gi.test(svgContent)) {
issues.push('Found javascript: URLs');
}
const originalDOM = new JSDOM(svgContent, { contentType: 'image/svg+xml' });
const sanitizedDOM = new JSDOM(cleanSVG, { contentType: 'image/svg+xml' });
const externalUrlPattern = /^(https?|ftp):\/\//i;
const imageElements = originalDOM.window.document.querySelectorAll('image');
const useElements = originalDOM.window.document.querySelectorAll('use');
imageElements.forEach((img, index) => {
const href = img.getAttribute('href') || img.getAttribute('xlink:href');
if (href && externalUrlPattern.test(href.trim())) {
issues.push(`Found external URL in image element: ${href}`);
}
});
useElements.forEach((use, index) => {
const href = use.getAttribute('href') || use.getAttribute('xlink:href');
if (href && externalUrlPattern.test(href.trim())) {
issues.push(`Found external URL in use element: ${href}`);
}
});
const originalScripts = originalDOM.window.document.querySelectorAll('script');
const sanitizedScripts = sanitizedDOM.window.document.querySelectorAll('script');
if (originalScripts.length > sanitizedScripts.length) {
issues.push(`DOMPurify removed ${originalScripts.length - sanitizedScripts.length} script element(s)`);
}
const allElements = originalDOM.window.document.querySelectorAll('*');
let eventHandlerCount = 0;
allElements.forEach(el => {
Array.from(el.attributes).forEach(attr => {
if (attr.name.toLowerCase().startsWith('on')) {
eventHandlerCount++;
}
});
});
if (eventHandlerCount > 0 && issues.length === 0) {
const sanitizedAllElements = sanitizedDOM.window.document.querySelectorAll('*');
let sanitizedEventHandlerCount = 0;
sanitizedAllElements.forEach(el => {
Array.from(el.attributes).forEach(attr => {
if (attr.name.toLowerCase().startsWith('on')) {
sanitizedEventHandlerCount++;
}
});
});
if (eventHandlerCount > sanitizedEventHandlerCount) {
issues.push(`DOMPurify removed ${eventHandlerCount - sanitizedEventHandlerCount} event handler attribute(s)`);
}
}
if (issues.length > 0) {
console.log(`Unsafe content found in: ${file}`);
issues.forEach(issue => console.log(` - ${issue}`));
foundUnsafe = true;
}
} catch (error) {
console.error(`Error processing ${file}: ${error.message}`);
foundUnsafe = true;
}
}
if (foundUnsafe) {
process.exit(1);
} else {
console.log('No unsafe content found in SVG files');
process.exit(0);
}