(buffer)
| 20 | }; |
| 21 | |
| 22 | const isSafeSvgBuffer = (buffer) => { |
| 23 | if (!Buffer.isBuffer(buffer) || buffer.length === 0) { |
| 24 | return false; |
| 25 | } |
| 26 | |
| 27 | const content = buffer.toString("utf8").replace(/^\uFEFF/, "").trim(); |
| 28 | if (!content) return false; |
| 29 | |
| 30 | const hasSvgRoot = /^(?:<\?xml[\s\S]*?\?>\s*)?<svg[\s>][\s\S]*$/i.test(content); |
| 31 | if (!hasSvgRoot) { |
| 32 | return false; |
| 33 | } |
| 34 | |
| 35 | const hasClosingSvg = /<\/svg>\s*$/i.test(content); |
| 36 | const hasSelfClosingSvg = /<svg[^>]*\/>\s*$/i.test(content); |
| 37 | if (!hasClosingSvg && !hasSelfClosingSvg) { |
| 38 | return false; |
| 39 | } |
| 40 | |
| 41 | const unsafePatterns = [ |
| 42 | /<script[\s>]/i, |
| 43 | /\son[a-z]+\s*=/i, |
| 44 | /\b(?:href|xlink:href)\s*=\s*["']?\s*javascript:/i, |
| 45 | /<foreignobject[\s>]/i, |
| 46 | /<iframe[\s>]/i, |
| 47 | /<object[\s>]/i, |
| 48 | /<embed[\s>]/i, |
| 49 | ]; |
| 50 | |
| 51 | return !unsafePatterns.some((pattern) => pattern.test(content)); |
| 52 | }; |
| 53 | |
| 54 | const getImageTypeFromBuffer = (buffer) => { |
| 55 | if (!Buffer.isBuffer(buffer) || buffer.length < 12) { |
no outgoing calls
no test coverage detected