comparison data/plugin/macro/span.py @ 533:1f9926e7f5b5

span macro: add (hopefully safe) style support, let through only properties on whitelist
author Thomas Waldmann <tw AT waldmann-edv DOT de>
date Tue, 22 Jun 2010 16:49:38 +0200
parents 942f9b55773e
children 7bcfe0b3823a
comparison
equal deleted inserted replaced
532:942f9b55773e 533:1f9926e7f5b5
1 # -*- coding: iso-8859-1 -*- 1 # -*- coding: iso-8859-1 -*-
2 """ 2 """
3 MoinMoin - span generating macro 3 MoinMoin - span generating macro
4 4
5 Supported attrs: css_class, id, lang, dir, title 5 Supported attrs: css_class, id, lang, dir, title
6
7 Partially supported attrs: style - only safe stuff on whitelist (with
8 SUPPORT_STYLE_ATTR = True), other stuff
9 can contain javascript, XSS danger!
10 If you don't need style, consider using
11 SUPPORT_STYLE_ATTR = False for better safety.
6 12
7 Unsupported attrs: style - can contain javascript, XSS danger 13 Unsupported attrs: event attrs - unsafe, can contain javascript, XSS danger
8 event attrs - same reason
9 align - deprecated by the W3C (use css classes) 14 align - deprecated by the W3C (use css classes)
10 15
11 Usage: 16 Usage:
12 <<span(red)>>some text contained in a span with css class red<<span>> 17 <<span(red)>>some text contained in a span with css class red<<span>>
13 <<span(css_class=red)>>same as above<<span>> 18 <<span(css_class=red)>>same as above<<span>>
14 <<span(id=foobar)>>some text in a span with id foobar<<span>> 19 <<span(id=foobar)>>some text in a span with id foobar<<span>>
15 <<span(title="read this!")>>some text with a mouseover title<<span>> 20 <<span(title="read this!")>>some text with a mouseover title<<span>>
21 <<span(style="color: red; font: 20pt sans-serif;")>>20pt sans-serif red<<span>>
16 22
17 @copyright: 2010 MoinMoin:ThomasWaldmann 23 @copyright: 2010 MoinMoin:ThomasWaldmann
18 @license: GNU GPL, see COPYING for details. 24 @license: GNU GPL, see COPYING for details.
19 """ 25 """
20 26
27 SUPPORT_STYLE_ATTR = True # True should be safe, False is safer :)
28
21 Dependencies = [] 29 Dependencies = []
22 30
23 from MoinMoin.wikiutil import required_arg 31 from MoinMoin.wikiutil import required_arg
32
33 def make_style_safe(style):
34 """ make html 'style' attribute value safe """
35 # whitelist of safe style attributes, taken from:
36 # http://validator.w3.org/feed/docs/warning/DangerousStyleAttr.html
37 whitelist = ("azimuth,background,background-color,border,border-bottom,"
38 "border-bottom-color,border-bottom-style,border-bottom-width,"
39 "border-collapse,border-color,border-left,border-left-color,"
40 "border-left-style,border-left-width,border-right,border-right-color,"
41 "border-right-style,border-right-width,border-spacing,border-style,"
42 "border-top,border-top-color,border-top-style,border-top-width,"
43 "border-width,clear,color,cursor,direction,display,elevation,"
44 "float,font,font-family,font-size,font-style,font-variant,"
45 "font-weight,height,letter-spacing,line-height,margin,"
46 "margin-bottom,margin-left,margin-right,margin-top,overflow,"
47 "padding,padding-bottom,padding-left,padding-right,padding-top,"
48 "pause,pause-after,pause-before,pitch,pitch-range,richness,"
49 "speak,speak-header,speak-numeral,speak-punctuation,speech-rate,"
50 "stress,text-align,text-decoration,text-indent,unicode-bidi,"
51 "vertical-align,voice-family,volume,white-space,width").split(',')
52
53 def style_split(style):
54 """
55 split style into a list of declarations,
56 split the declarations into property, value tuples,
57 remove all surrounding whitespace
58 """
59 decls = [decl.split(u':', 1) for decl in style.split(u';')]
60 # remove spaces from propery and value
61 result = []
62 for decl in decls:
63 if len(decl) == 2:
64 result.append((decl[0].strip(), decl[1].strip()))
65 return result
66
67 def style_join(decls):
68 """
69 join a list of prop, value tuples into a style declaration
70 """
71 decls = [u'%s: %s' % (prop, val) for prop, val in decls]
72 style = u'; '.join(decls)
73 return style
74
75 def decl_filter(decls):
76 """
77 filter a list of prop, value tuples, only let whitelisted props through
78 """
79 return [(prop, val) for prop, val in decls if prop in whitelist]
80
81 decls = style_split(style)
82 decls = decl_filter(decls)
83 style = style_join(decls)
84 return style
85
24 86
25 def macro_span(macro, 87 def macro_span(macro,
26 # first the stuff we can directly give to span formatter: 88 # first the stuff we can directly give to span formatter:
27 css_class=u'', 89 css_class=u'',
28 id=u'', 90 id=u'',
29 lang=u'', 91 lang=u'',
30 dir=u'', 92 dir=u'',
31 title=u'', 93 title=u'',
32 # deprecated by W3C: 94 # deprecated by W3C:
33 #align=u'', 95 #align=u'',
34 # dangerous, see docstring: 96 style=u'',
35 #style=u'',
36 ): 97 ):
37 attrs = {} 98 attrs = {}
38 for key, value in [ 99 for key, value in [
39 ('css_class', css_class), ('id', id), 100 ('css_class', css_class), ('id', id),
40 ('lang', lang), ('dir', dir), 101 ('lang', lang), ('dir', dir),
41 ('title', title), 102 ('title', title),
42 #('align', align), 103 #('align', align),
43 #('style', style),
44 ]: 104 ]:
45 if value: 105 if value:
46 attrs[key] = value 106 attrs[key] = value
107
108 if SUPPORT_STYLE_ATTR:
109 if style:
110 attrs['style'] = make_style_safe(style)
111
47 span = macro.formatter.span 112 span = macro.formatter.span
48 if attrs: 113 if attrs:
49 return span(True, **attrs) 114 return span(True, **attrs)
50 else: 115 else:
51 return span(False) 116 return span(False)