gooderp18绿色标准版
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

74 line
2.5KB

  1. # -*- coding: utf-8 -*-
  2. from datetime import date, datetime
  3. import json as json_
  4. import re
  5. import markupsafe
  6. from .func import lazy
  7. from .misc import ReadonlyDict
  8. JSON_SCRIPTSAFE_MAPPER = {
  9. '&': r'\u0026',
  10. '<': r'\u003c',
  11. '>': r'\u003e',
  12. '\u2028': r'\u2028',
  13. '\u2029': r'\u2029'
  14. }
  15. class _ScriptSafe(str):
  16. def __html__(self):
  17. # replacement can be done straight in the serialised JSON as the
  18. # problematic characters are not JSON metacharacters (and can thus
  19. # only occur in strings)
  20. return markupsafe.Markup(re.sub(
  21. r'[<>&\u2028\u2029]',
  22. lambda m: JSON_SCRIPTSAFE_MAPPER[m[0]],
  23. self,
  24. ))
  25. class JSON:
  26. def loads(self, *args, **kwargs):
  27. return json_.loads(*args, **kwargs)
  28. def dumps(self, *args, **kwargs):
  29. """ JSON used as JS in HTML (script tags) is problematic: <script>
  30. tags are a special context which only waits for </script> but doesn't
  31. interpret anything else, this means standard htmlescaping does not
  32. work (it breaks double quotes, and e.g. `<` will become `&lt;` *in
  33. the resulting JSON/JS* not just inside the page).
  34. However, failing to escape embedded json means the json strings could
  35. contains `</script>` and thus become XSS vector.
  36. The solution turns out to be very simple: use JSON-level unicode
  37. escapes for HTML-unsafe characters (e.g. "<" -> "\u003C". This removes
  38. the XSS issue without breaking the json, and there is no difference to
  39. the end result once it's been parsed back from JSON. So it will work
  40. properly even for HTML attributes or raw text.
  41. Also handle U+2028 and U+2029 the same way just in case as these are
  42. interpreted as newlines in javascript but not in JSON, which could
  43. lead to oddities and issues.
  44. .. warning::
  45. except inside <script> elements, this should be escaped following
  46. the normal rules of the containing format
  47. Cf https://code.djangoproject.com/ticket/17419#comment:27
  48. """
  49. return _ScriptSafe(json_.dumps(*args, **kwargs))
  50. scriptsafe = JSON()
  51. def json_default(obj):
  52. from odoo import fields # noqa: PLC0415
  53. if isinstance(obj, datetime):
  54. return fields.Datetime.to_string(obj)
  55. if isinstance(obj, date):
  56. return fields.Date.to_string(obj)
  57. if isinstance(obj, lazy):
  58. return obj._value
  59. if isinstance(obj, ReadonlyDict):
  60. return dict(obj)
  61. if isinstance(obj, bytes):
  62. return obj.decode()
  63. return str(obj)
上海开阖软件有限公司 沪ICP备12045867号-1