view data/plugin/macro/ @ 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
line wrap: on
line source
# -*- coding: iso-8859-1 -*-
    MoinMoin - span generating macro

    Supported attrs: css_class, id, lang, dir, title
    Partially supported attrs: style - only safe stuff on whitelist (with
                               SUPPORT_STYLE_ATTR = True), other stuff
                               can contain javascript, XSS danger!
                               If you don't need style, consider using
                               SUPPORT_STYLE_ATTR = False for better safety.

    Unsupported attrs: event attrs - unsafe, can contain javascript, XSS danger
                       align - deprecated by the W3C (use css classes)

    <<span(red)>>some text contained in a span with css class red<<span>>
    <<span(css_class=red)>>same as above<<span>>
    <<span(id=foobar)>>some text in a span with id foobar<<span>>
    <<span(title="read this!")>>some text with a mouseover title<<span>>
    <<span(style="color: red; font: 20pt sans-serif;")>>20pt sans-serif red<<span>>

    @copyright: 2010 MoinMoin:ThomasWaldmann
    @license: GNU GPL, see COPYING for details.

SUPPORT_STYLE_ATTR = True # True should be safe, False is safer :)

Dependencies = []

from MoinMoin.wikiutil import required_arg

def make_style_safe(style):
    """ make html 'style' attribute value safe """
    # whitelist of safe style attributes, taken from:
    whitelist = ("azimuth,background,background-color,border,border-bottom,"

    def style_split(style):
        split style into a list of declarations,
        split the declarations into property, value tuples,
        remove all surrounding whitespace
        decls = [decl.split(u':', 1) for decl in style.split(u';')]
        # remove spaces from propery and value
        result = []
        for decl in decls:
            if len(decl) == 2:
                result.append((decl[0].strip(), decl[1].strip()))
        return result

    def style_join(decls):
        join a list of prop, value tuples into a style declaration
        decls = [u'%s: %s' % (prop, val) for prop, val in decls]
        style = u'; '.join(decls)
        return style

    def decl_filter(decls):
        filter a list of prop, value tuples, only let whitelisted props through
        return [(prop, val) for prop, val in decls if prop in whitelist]

    decls = style_split(style)
    decls = decl_filter(decls)
    style = style_join(decls)
    return style

def macro_span(macro,
               # first the stuff we can directly give to span formatter:
               # deprecated by W3C:
    attrs = {}
    for key, value in [
        ('css_class', css_class), ('id', id),
        ('lang', lang), ('dir', dir),
        ('title', title),
        #('align', align),
        if value:
            attrs[key] = value

        if style:
            attrs['style'] = make_style_safe(style)

    span = macro.formatter.span
    if attrs:
        return span(True, **attrs)
        return span(False)