1
0

svg.go 1.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. package svg
  2. import (
  3. "bytes"
  4. "io"
  5. "strings"
  6. "github.com/tdewolff/parse/v2"
  7. "github.com/tdewolff/parse/v2/xml"
  8. "github.com/imgproxy/imgproxy/v3/imagedata"
  9. )
  10. func cloneHeaders(src map[string]string) map[string]string {
  11. if src == nil {
  12. return nil
  13. }
  14. dst := make(map[string]string, len(src))
  15. for k, v := range src {
  16. dst[k] = v
  17. }
  18. return dst
  19. }
  20. func Sanitize(data *imagedata.ImageData) (*imagedata.ImageData, error) {
  21. r := bytes.NewReader(data.Data)
  22. l := xml.NewLexer(parse.NewInput(r))
  23. buf, cancel := imagedata.BorrowBuffer()
  24. ignoreTag := 0
  25. var curTagName string
  26. for {
  27. tt, tdata := l.Next()
  28. if tt == xml.ErrorToken {
  29. if l.Err() != io.EOF {
  30. cancel()
  31. return nil, l.Err()
  32. }
  33. break
  34. }
  35. if ignoreTag > 0 {
  36. switch tt {
  37. case xml.EndTagToken, xml.StartTagCloseVoidToken:
  38. ignoreTag--
  39. case xml.StartTagToken:
  40. ignoreTag++
  41. }
  42. continue
  43. }
  44. switch tt {
  45. case xml.StartTagToken:
  46. curTagName = strings.ToLower(string(l.Text()))
  47. if curTagName == "script" {
  48. ignoreTag++
  49. continue
  50. }
  51. buf.Write(tdata)
  52. case xml.AttributeToken:
  53. attrName := strings.ToLower(string(l.Text()))
  54. if _, unsafe := unsafeAttrs[attrName]; unsafe {
  55. continue
  56. }
  57. if curTagName == "use" && (attrName == "href" || attrName == "xlink:href") {
  58. val := strings.TrimSpace(strings.Trim(string(l.AttrVal()), `"'`))
  59. if len(val) > 0 && val[0] != '#' {
  60. continue
  61. }
  62. }
  63. buf.Write(tdata)
  64. default:
  65. buf.Write(tdata)
  66. }
  67. }
  68. newData := imagedata.ImageData{
  69. Data: buf.Bytes(),
  70. Type: data.Type,
  71. Headers: cloneHeaders(data.Headers),
  72. }
  73. newData.SetCancel(cancel)
  74. return &newData, nil
  75. }