Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/turbohtml/migration/bleach.py: 87%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

23 statements  

1""" 

2A compatible ``bleach.clean`` interface for projects migrating off bleach. 

3 

4This is a thin translator over :mod:`turbohtml.clean`, kept apart from the main API so the compatibility surface stays 

5bounded. ``clean(text, tags=..., attributes=..., protocols=..., strip=...)`` keeps bleach's signature, including the 

6list, per-tag-dict, and callable forms of ``attributes``. Kept attributes and text may change entity spelling after 

7serialization. Event-handler attributes and ``javascript:`` URLs are dropped unconditionally, even when a permissive 

8``attributes`` callable would keep them, because the underlying policy's safety baseline is fixed. 

9""" 

10 

11from __future__ import annotations 

12 

13from collections.abc import Callable, Iterable, Mapping 

14from typing import TypeAlias 

15 

16from turbohtml._html import _bleach_allow_relative, _bleach_attributes 

17from turbohtml.clean import DEFAULT_ATTRIBUTES, DEFAULT_SCHEMES, DEFAULT_TAGS, OnDisallowed, Policy, sanitize 

18 

19#: bleach's default allowed tags, attributes, and protocols, under their bleach names. 

20ALLOWED_TAGS = DEFAULT_TAGS 

21ALLOWED_ATTRIBUTES = DEFAULT_ATTRIBUTES 

22ALLOWED_PROTOCOLS = DEFAULT_SCHEMES 

23 

24_AttributeRules: TypeAlias = ( 

25 Iterable[str] | Mapping[str, Iterable[str] | Callable[[str, str, str], bool]] | Callable[[str, str, str], bool] 

26) 

27 

28 

29def clean( # ruff:ignore[too-many-arguments, too-many-positional-arguments] # this is bleach.clean's signature, kept verbatim for compatibility 

30 text: str, 

31 tags: Iterable[str] | None = None, 

32 attributes: _AttributeRules | None = None, 

33 protocols: Iterable[str] | None = None, 

34 strip: bool = False, # ruff:ignore[boolean-type-hint-positional-argument, boolean-default-value-positional-argument] # bleach keeps strip a positional flag 

35 strip_comments: bool = True, # ruff:ignore[boolean-type-hint-positional-argument, boolean-default-value-positional-argument] # bleach keeps strip_comments a positional flag 

36 css_sanitizer: object = None, 

37) -> str: 

38 """ 

39 Sanitize HTML against a bleach-style allowlist, the way ``bleach.clean`` did. 

40 

41 :param text: the untrusted HTML. 

42 :param tags: the allowed tag names; None uses bleach's default set. 

43 :param attributes: the allowed attributes as a flat list, a per-tag dict, or a (tag, name, value) predicate; 

44 None uses bleach's default. 

45 :param protocols: the allowed URL schemes; None uses bleach's default. 

46 :param strip: drop a disallowed tag and keep its children, rather than escaping it to text. 

47 :param strip_comments: drop HTML comments from the output. 

48 :param css_sanitizer: accepted for signature compatibility; passing one raises ``NotImplementedError``. 

49 :returns: the sanitized, safe HTML. 

50 """ 

51 if css_sanitizer is not None: # CSS sanitizing is a separate sub-problem, not yet ported 

52 msg = "css_sanitizer is not implemented yet; drop the style attribute and <style> instead" 

53 raise NotImplementedError(msg) 

54 names, attribute_predicate = attribute_policy(ALLOWED_ATTRIBUTES if attributes is None else attributes) 

55 if protocols is None: 

56 policy = Policy( 

57 tags=ALLOWED_TAGS if tags is None else frozenset(tags), 

58 attributes=names, 

59 url_schemes=ALLOWED_PROTOCOLS, 

60 on_disallowed_tag=OnDisallowed.STRIP if strip else OnDisallowed.ESCAPE, 

61 strip_comments=strip_comments, 

62 attribute_predicate=attribute_predicate, 

63 _bleach_url_policy=True, 

64 ) 

65 else: 

66 schemes = frozenset(protocols) 

67 policy = Policy( 

68 tags=ALLOWED_TAGS if tags is None else frozenset(tags), 

69 attributes=names, 

70 url_schemes=schemes, 

71 allow_relative_urls=_bleach_allow_relative(schemes), 

72 allow_fragment_urls=True, 

73 on_disallowed_tag=OnDisallowed.STRIP if strip else OnDisallowed.ESCAPE, 

74 strip_comments=strip_comments, 

75 attribute_predicate=attribute_predicate, 

76 _bleach_url_policy=True, 

77 ) 

78 return sanitize(text, policy) 

79 

80 

81def attribute_policy( 

82 attributes: _AttributeRules, 

83) -> tuple[dict[str, frozenset[str]], Callable[[str, str, str], bool] | None]: 

84 """Keep bleach attribute rules when configuring a native ``Policy``.""" 

85 return _bleach_attributes(attributes, Mapping) 

86 

87 

88__all__ = [ 

89 "ALLOWED_ATTRIBUTES", 

90 "ALLOWED_PROTOCOLS", 

91 "ALLOWED_TAGS", 

92 "attribute_policy", 

93 "clean", 

94]