1from django.utils.html import mark_safe, format_html
2from django.utils.translation import gettext_lazy
3
4try:
5    import bleach
6
7    clean_html = lambda body: mark_safe(bleach.clean(
8        body,
9        tags=[
10            'a',
11            'abbr',
12            'acronym',
13            'b',
14            'blockquote',
15            'br',
16            'caption',
17            'center',
18            'code',
19            'em',
20            'div',
21            'font',
22            'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
23            'head',
24            'hr',
25            'i',
26            'img',
27            'label',
28            'li',
29            'ol',
30            'p',
31            'pre',
32            'span',
33            'strong',
34            'table', 'tbody', 'tfoot', 'td', 'th', 'thead', 'tr',
35            'u',
36            'ul',
37        ],
38        attributes={
39            'a': ['class', 'href', 'id', 'style', 'target'],
40            'abbr': ['class', 'id', 'style'],
41            'acronym': ['class', 'id', 'style'],
42            'b': ['class', 'id', 'style'],
43            'blockquote': ['class', 'id', 'style'],
44            'br': ['class', 'id', 'style'],
45            'caption': ['class', 'id', 'style'],
46            'center': ['class', 'id', 'style'],
47            'code': ['class', 'id', 'style'],
48            'em': ['class', 'id', 'style'],
49            'div': ['class', 'id', 'style', 'align', 'dir'],
50            'font': ['class', 'id', 'style', 'color', 'face', 'size'],
51            'h1': ['class', 'id', 'style', 'align', 'dir'],
52            'h2': ['class', 'id', 'style', 'align', 'dir'],
53            'h3': ['class', 'id', 'style', 'align', 'dir'],
54            'h4': ['class', 'id', 'style', 'align', 'dir'],
55            'h5': ['class', 'id', 'style', 'align', 'dir'],
56            'h6': ['class', 'id', 'style', 'align', 'dir'],
57            'head': ['dir', 'lang'],
58            'hr': ['align', 'size', 'width'],
59            'i': ['class', 'id', 'style'],
60            'img': ['class', 'id', 'style', 'align', 'border', 'height', 'hspace', 'src', 'usemap', 'vspace', 'width'],
61            'label': ['class', 'id', 'style'],
62            'li': ['class', 'id', 'style', 'dir', 'type'],
63            'ol': ['class', 'id', 'style', 'dir', 'type'],
64            'p': ['class', 'id', 'style', 'align', 'dir'],
65            'pre': ['class', 'id', 'style'],
66            'span': ['class', 'id', 'style'],
67            'strong': ['class', 'id', 'style'],
68            'table': ['class', 'id', 'style', 'align', 'bgcolor', 'border', 'cellpadding', 'cellspacing', 'dir', 'frame', 'rules', 'width'],
69            'tbody': ['class', 'id', 'style'],
70            'tfoot': ['class', 'id', 'style'],
71            'td': ['class', 'id', 'style', 'abbr', 'align', 'bgcolor', 'colspan', 'dir', 'height', 'lang', 'rowspan', 'scope', 'style', 'valign', 'width'],
72            'th': ['class', 'id', 'style', 'abbr', 'align', 'background', 'bgcolor', 'colspan', 'dir', 'height', 'lang', 'scope', 'style', 'valign', 'width'],
73            'thead': ['class', 'id', 'style'],
74            'tr': ['class', 'id', 'style', 'align', 'bgcolor', 'dir', 'style', 'valign'],
75            'u': ['class', 'id', 'style'],
76            'ul': ['class', 'id', 'style', 'dir', 'type'],
77        },
78        strip=True,
79        strip_comments=True,
80        styles=[
81            'border', 'border-top', 'border-right', 'border-bottom', 'border-left',
82            'border-radius',
83            'box-shadow',
84            'height',
85            'margin', 'margin-top', 'margin-right', 'margin-bottom', 'margin-left',
86            'padding', 'padding-top', 'padding-right', 'padding-bottom', 'padding-left',
87            'width',
88            'max-width',
89            'min-width',
90            'border-collapse',
91            'border-spacing',
92            'caption-side',
93            'empty-cells',
94            'table-layout',
95            'direction',
96            'font',
97            'font-family',
98            'font-style',
99            'font-variant',
100            'font-size',
101            'font-weight',
102            'letter-spacing',
103            'line-height',
104            'text-align',
105            'text-decoration',
106            'text-indent',
107            'text-overflow',
108            'text-shadow',
109            'text-transform',
110            'white-space',
111            'word-spacing',
112            'word-wrap',
113            'vertical-align',
114            'color',
115            'background',
116            'background-color',
117            'background-image',
118            'background-position',
119            'background-repeat',
120            'bottom',
121            'clear',
122            'cursor',
123            'display',
124            'float',
125            'left',
126            'opacity',
127            'outline',
128            'overflow',
129            'position',
130            'resize',
131            'right',
132            'top',
133            'visibility',
134            'z-index',
135            'list-style-position',
136            'list-style-tyle',
137        ],
138    ))
139except ImportError:
140    # if bleach is not installed, render HTML as escaped text to prevent XSS attacks
141    heading = gettext_lazy("Install 'bleach' to render HTML properly.")
142    clean_html = lambda body: format_html('<p><em>{heading}</em></p>\n<div>{body}</div>',
143                                          heading=heading, body=body)
144