OSDN Git Service

add wp_imgswap2.py for new OSDN Magazine
[otptools/otptools.git] / HTMLTagFilter.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3
4 import re
5
6 DENY_ALLOW = 0
7 ALLOW_DENY = 1
8 # str_regex_tag = 
9 #  r"""[^"'<>]*(?:"[^"]*"[^"'<>]*|'[^']*'[^"'<>]*)*(?:>|(?=<)|$(?!\n))"""
10 # str_regex_comment =
11 #  r'<!(?:--[^-]*-(?:[^-]+-)*?-(?:[^>-]*(?:-[^>-]+)*?)??)*(?:>|$(?!\n)|--.*$)'
12
13 class HTMLTagFilter:
14     """
15     allow / deny list:
16     a -> <a>
17     a:href -> <a href>
18     a:* -> a tag's any attribute
19     *:style -> any tag's style attribute
20     """
21
22     def __init__(self, rule, allow_list, deny_list):
23         """
24         create new object.
25         
26         @param rule: filtering rule. DENY_ALLOW or ALLOW_DENY.
27         @type rule: int
28         
29         @param allow_list: allowed tag/attribute's list.
30         @type allow_list: sequence
31         
32         @param deny_list: denied tag/attribue's list.
33         @type deny_list: sequece
34         """
35         self.rule = rule
36         self.allow_list = allow_list[:]
37         self.deny_list = deny_list[:]
38
39         allow_tuple = self._create_filtering_rule(allow_list)
40         deny_tuple = self._create_filtering_rule(deny_list)
41
42         self.allow_attributes = allow_tuple[0]
43         self.allow_elements = allow_tuple[1]
44         self.deny_attributes = deny_tuple[0]
45         self.deny_elements = deny_tuple[1]
46
47
48     def _create_filtering_rule(self, rule_list):
49         attr_map = {}
50         elem_list = []
51         for item in rule_list:
52             item = item.strip()
53             if item.find(":") == -1 : # element rule
54                 elem_list.append(item)
55             else: # attribute rule
56                 match_obj = re.search(r"^(\w*|\*):(\w*|\*)$", item)
57                 elem = match_obj.group(1)
58                 attr = match_obj.group(2)
59
60                 if elem == "":
61                     elem = "*"
62                 if attr == "":
63                     attr = "*"
64
65                 attr_list = attr_map.get(elem, [])
66                 attr_list.append(attr)
67                 attr_map[elem] = attr_list
68         return (attr_map, elem_list)
69
70     def apply(self, str):
71         """
72         apply filter rule to string.
73         return string's filtered copy.
74         
75         @param str: target string
76         @type str:  string
77         """
78         ret_str = ""
79         str_regex_split = r"""(<[^"'<>]*(?:"[^"]*"[^"'<>]*|'[^']*'[^"'<>]*)*(?:>|(?=<)|$(?!\n)))"""
80         str_regex_tag = r"""^<.*>$"""
81         regex_split = re.compile(str_regex_split)
82         regex_tag = re.compile(str_regex_tag)
83         splitted_list = regex_split.split(str)
84         
85         for term in splitted_list:
86             if regex_tag.search(term):
87                 term = self.filter_tag(term)
88             else:
89                 term = self.quote(term)
90             ret_str = ret_str + term
91                 
92         return ret_str
93
94     def filter_tag(self, str):
95 #        print str + ":"
96         match_obj = re.search(r"^<(/{0,1}\s*\w+)\s*(.*)>", str)
97         tag = ""
98         attr_list = []
99         if match_obj:
100             tag = match_obj.group(1)
101             attr = match_obj.group(2).strip()
102             if not attr == "":
103                 attr_list = re.split("\s+", attr)
104
105         # element filtering
106         tag = tag.replace("/", "")
107         if self._check(tag, self.allow_elements, self.deny_elements):
108             str = self.quote(str)
109             return str
110
111         # attribute filtering
112         new_list = []
113         for item in attr_list:
114             (attr, val) = item.split("=", 1)
115             allow_list = self.allow_attributes.get(tag, [])
116             deny_list = self.deny_attributes.get(tag,[])
117
118             if not self._check(attr, allow_list, deny_list):
119                 new_list.append(item)
120
121         if len(new_list) > 0:
122             str = "<" + tag + " " + " ".join(new_list) + ">"
123         else:
124             str = "<" + tag + ">"
125         return str
126         
127     def _check(self, str, allow_list, deny_list):
128         is_allow = (str in allow_list) or ("*" in allow_list)
129         is_deny = (str in deny_list) or ("*" in deny_list)
130         if self.rule == ALLOW_DENY:
131             if (not is_allow) or (is_deny):
132                 return 1
133         elif self.rule == DENY_ALLOW:
134             if (is_deny) and (not is_allow):
135                 return 1
136         return 0
137
138     def quote(self, str):
139         str_ret = str.replace("&", "&amp;")
140         str_ret = str_ret.replace("<", "&lt;")
141         str_ret = str_ret.replace(">", "&gt;")
142         return str_ret
143
144
145 #testcode
146 #alist = ["a", "b", "br", "p", "a:href" ]
147 #dlist = ["*"]
148 #filter = HTMLTagFilter(DENY_ALLOW, alist, dlist)
149 #str = """hoge > hoge < hoge<a href="URL" style="<"><b>test</b><br>"""
150
151
152 # print "allow-elem:"
153 # for item in filter.allow_elements:
154 #     print item
155 # print "deny-elem:"
156 # for item in filter.deny_elements:
157 #     print item
158
159 # print "allow-attr:"
160 # for elem in filter.allow_attributes:
161 #     for attr in filter.allow_attributes[elem]:
162 #         print "%s : %s" % (elem, attr)
163 # print "deny-attr:"
164 # for elem in filter.deny_attributes:
165 #     for attr in filter.deny_attributes[elem]:
166 #         print "%s : %s" % (elem, attr)
167
168
169
170 #print "Input: %s" % str
171 #print filter.apply(str)