antisamy 0.2.1 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.rdoc +13 -0
- data/LICENSE.txt +20 -20
- data/README.rdoc +41 -41
- data/lib/antisamy.rb +46 -46
- data/lib/antisamy/css/css_filter.rb +187 -187
- data/lib/antisamy/css/css_scanner.rb +84 -84
- data/lib/antisamy/css/css_validator.rb +128 -128
- data/lib/antisamy/csspool/rsac.rb +1 -1
- data/lib/antisamy/csspool/rsac/sac.rb +14 -14
- data/lib/antisamy/csspool/rsac/sac/conditions.rb +5 -5
- data/lib/antisamy/csspool/rsac/sac/conditions/attribute_condition.rb +50 -50
- data/lib/antisamy/csspool/rsac/sac/conditions/begin_hyphen_condition.rb +18 -18
- data/lib/antisamy/csspool/rsac/sac/conditions/class_condition.rb +18 -18
- data/lib/antisamy/csspool/rsac/sac/conditions/combinator_condition.rb +36 -36
- data/lib/antisamy/csspool/rsac/sac/conditions/condition.rb +29 -29
- data/lib/antisamy/csspool/rsac/sac/conditions/id_condition.rb +23 -23
- data/lib/antisamy/csspool/rsac/sac/conditions/one_of_condition.rb +18 -18
- data/lib/antisamy/csspool/rsac/sac/conditions/pseudo_class_condition.rb +20 -20
- data/lib/antisamy/csspool/rsac/sac/document_handler.rb +66 -66
- data/lib/antisamy/csspool/rsac/sac/error_handler.rb +13 -13
- data/lib/antisamy/csspool/rsac/sac/generated_parser.rb +1012 -1012
- data/lib/antisamy/csspool/rsac/sac/generated_property_parser.rb +9284 -9284
- data/lib/antisamy/csspool/rsac/sac/lexeme.rb +27 -27
- data/lib/antisamy/csspool/rsac/sac/lexical_unit.rb +201 -201
- data/lib/antisamy/csspool/rsac/sac/parse_exception.rb +4 -4
- data/lib/antisamy/csspool/rsac/sac/parser.rb +109 -109
- data/lib/antisamy/csspool/rsac/sac/property_parser.rb +44 -44
- data/lib/antisamy/csspool/rsac/sac/selectors.rb +5 -5
- data/lib/antisamy/csspool/rsac/sac/selectors/child_selector.rb +36 -36
- data/lib/antisamy/csspool/rsac/sac/selectors/conditional_selector.rb +45 -45
- data/lib/antisamy/csspool/rsac/sac/selectors/descendant_selector.rb +36 -36
- data/lib/antisamy/csspool/rsac/sac/selectors/element_selector.rb +35 -35
- data/lib/antisamy/csspool/rsac/sac/selectors/selector.rb +25 -25
- data/lib/antisamy/csspool/rsac/sac/selectors/sibling_selector.rb +35 -35
- data/lib/antisamy/csspool/rsac/sac/selectors/simple_selector.rb +21 -21
- data/lib/antisamy/csspool/rsac/sac/token.rb +25 -25
- data/lib/antisamy/csspool/rsac/sac/tokenizer.rb +185 -185
- data/lib/antisamy/csspool/rsac/stylesheet.rb +3 -3
- data/lib/antisamy/csspool/rsac/stylesheet/rule.rb +20 -20
- data/lib/antisamy/csspool/rsac/stylesheet/stylesheet.rb +76 -76
- data/lib/antisamy/html/handler.rb +112 -99
- data/lib/antisamy/html/sax_filter.rb +305 -302
- data/lib/antisamy/html/scanner.rb +47 -43
- data/lib/antisamy/model/attribute.rb +19 -19
- data/lib/antisamy/model/css_property.rb +39 -39
- data/lib/antisamy/model/tag.rb +31 -31
- data/lib/antisamy/policy.rb +577 -545
- data/lib/antisamy/scan_results.rb +89 -89
- data/spec/antisamy_spec.rb +208 -142
- data/spec/spec_helper.rb +12 -12
- metadata +79 -81
data/CHANGELOG.rdoc
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
== 0.0.1
|
2
|
+
|
3
|
+
* Initial commit.
|
4
|
+
* CSS scanning is currently not implmented so any CSS will be passed alonger verbatim
|
5
|
+
|
6
|
+
== 0.2.1
|
7
|
+
|
8
|
+
* CSS version2 implemented
|
9
|
+
|
10
|
+
== 0.3
|
11
|
+
|
12
|
+
* Proper fragment support and policy now provides a allowed-empty section to customize
|
13
|
+
|
data/LICENSE.txt
CHANGED
@@ -1,20 +1,20 @@
|
|
1
|
-
Copyright (c) 2011 Sal Scotto
|
2
|
-
|
3
|
-
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
-
a copy of this software and associated documentation files (the
|
5
|
-
"Software"), to deal in the Software without restriction, including
|
6
|
-
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
-
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
-
permit persons to whom the Software is furnished to do so, subject to
|
9
|
-
the following conditions:
|
10
|
-
|
11
|
-
The above copyright notice and this permission notice shall be
|
12
|
-
included in all copies or substantial portions of the Software.
|
13
|
-
|
14
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
-
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
-
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
-
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
-
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
-
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
1
|
+
Copyright (c) 2011 Sal Scotto
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
CHANGED
@@ -1,41 +1,41 @@
|
|
1
|
-
= Antisamy
|
2
|
-
|
3
|
-
This project is a port of the java AntiSamy project to the ruby runtime. Its intended to provide a library for developers to add protection to their web applications from malicious
|
4
|
-
user-supplier HTML and CSS. Please check out the AntiSamy project over at OWASP[http://www.owasp.org/index.php/Category:OWASP_AntiSamy_Project].
|
5
|
-
|
6
|
-
== TODO
|
7
|
-
|
8
|
-
* At some point support CSS3
|
9
|
-
|
10
|
-
== Synopsis
|
11
|
-
|
12
|
-
require 'antisamy'
|
13
|
-
policy = AntiSamy.policy('antisamy.xml')
|
14
|
-
tainted_html = 'User supplied markup'
|
15
|
-
scan_results = AntiSamy.scan(tainted_html,policy)
|
16
|
-
clean_html = scan_results.clean_html
|
17
|
-
|
18
|
-
== Example Policies
|
19
|
-
|
20
|
-
Please check policy-examples[https://github.com/washu/antisamy-ruby/tree/master/policy-examples] for sample policy files.
|
21
|
-
|
22
|
-
== Contributing to antisamy
|
23
|
-
|
24
|
-
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
25
|
-
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
26
|
-
* Fork the project
|
27
|
-
* Start a feature/bugfix branch
|
28
|
-
* Commit and push until you are happy with your contribution
|
29
|
-
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
30
|
-
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
31
|
-
|
32
|
-
== csspool
|
33
|
-
|
34
|
-
We use a forked version of csspool 0.2.6 within antysamy, you can find the license
|
35
|
-
for csspool in the rsac[https://github.com/washu/antisamy-ruby/tree/master/lib/antisamy/csspool] directory. csspool was re-namespaced to avoid any conflicts and updated for 1.9.2 ruby compatabilty
|
36
|
-
|
37
|
-
== Copyright
|
38
|
-
|
39
|
-
Copyright (c) 2011 Sal Scotto. See LICENSE.txt for
|
40
|
-
further details.
|
41
|
-
|
1
|
+
= Antisamy
|
2
|
+
|
3
|
+
This project is a port of the java AntiSamy project to the ruby runtime. Its intended to provide a library for developers to add protection to their web applications from malicious
|
4
|
+
user-supplier HTML and CSS. Please check out the AntiSamy project over at OWASP[http://www.owasp.org/index.php/Category:OWASP_AntiSamy_Project].
|
5
|
+
|
6
|
+
== TODO
|
7
|
+
|
8
|
+
* At some point support CSS3
|
9
|
+
|
10
|
+
== Synopsis
|
11
|
+
|
12
|
+
require 'antisamy'
|
13
|
+
policy = AntiSamy.policy('antisamy.xml')
|
14
|
+
tainted_html = 'User supplied markup'
|
15
|
+
scan_results = AntiSamy.scan(tainted_html,policy)
|
16
|
+
clean_html = scan_results.clean_html
|
17
|
+
|
18
|
+
== Example Policies
|
19
|
+
|
20
|
+
Please check policy-examples[https://github.com/washu/antisamy-ruby/tree/master/policy-examples] for sample policy files.
|
21
|
+
|
22
|
+
== Contributing to antisamy
|
23
|
+
|
24
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
25
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
26
|
+
* Fork the project
|
27
|
+
* Start a feature/bugfix branch
|
28
|
+
* Commit and push until you are happy with your contribution
|
29
|
+
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
30
|
+
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
31
|
+
|
32
|
+
== csspool
|
33
|
+
|
34
|
+
We use a forked version of csspool 0.2.6 within antysamy, you can find the license
|
35
|
+
for csspool in the rsac[https://github.com/washu/antisamy-ruby/tree/master/lib/antisamy/csspool] directory. csspool was re-namespaced to avoid any conflicts and updated for 1.9.2 ruby compatabilty
|
36
|
+
|
37
|
+
== Copyright
|
38
|
+
|
39
|
+
Copyright (c) 2011 Sal Scotto. See LICENSE.txt for
|
40
|
+
further details.
|
41
|
+
|
data/lib/antisamy.rb
CHANGED
@@ -1,46 +1,46 @@
|
|
1
|
-
require 'nokogiri'
|
2
|
-
require 'antisamy/csspool/rsac'
|
3
|
-
require 'antisamy/model/attribute'
|
4
|
-
require 'antisamy/model/tag'
|
5
|
-
require 'antisamy/model/css_property'
|
6
|
-
require 'antisamy/policy'
|
7
|
-
require 'antisamy/scan_results'
|
8
|
-
require 'antisamy/html/handler'
|
9
|
-
require 'antisamy/css/css_validator'
|
10
|
-
require 'antisamy/css/css_filter'
|
11
|
-
require 'antisamy/css/css_scanner'
|
12
|
-
require 'antisamy/html/sax_filter'
|
13
|
-
require 'antisamy/html/scanner'
|
14
|
-
|
15
|
-
module AntiSamy
|
16
|
-
class << self
|
17
|
-
|
18
|
-
# Setup the input encoding, defaults to UTF-8
|
19
|
-
def input_encoding=(encoding)
|
20
|
-
@@input_encoding = encoding
|
21
|
-
end
|
22
|
-
|
23
|
-
# Setup the output encoding defaults to UTF-8
|
24
|
-
def output_encoding=(encoding)
|
25
|
-
@@output_encoding = encoding
|
26
|
-
end
|
27
|
-
|
28
|
-
# Scan the input using the provided policy.
|
29
|
-
# will raise an exception if there is some form of scannign error
|
30
|
-
def scan(input,policy)
|
31
|
-
scanner = Scanner.new(policy)
|
32
|
-
@@input_encoding ||= Scanner::DEFAULT_ENCODE
|
33
|
-
@@output_encoding ||= Scanner::DEFAULT_ENCODE
|
34
|
-
clean = scanner.scan(input,@@input_encoding, @output_encoding)
|
35
|
-
clean
|
36
|
-
end
|
37
|
-
|
38
|
-
# Create a policy out of the provided file
|
39
|
-
# will use a string or any IO object that can be read
|
40
|
-
# will raise an exception if the policy fails to validate
|
41
|
-
def policy(policy_file)
|
42
|
-
Policy.new(policy_file)
|
43
|
-
end
|
44
|
-
|
45
|
-
end
|
46
|
-
end
|
1
|
+
require 'nokogiri'
|
2
|
+
require 'antisamy/csspool/rsac'
|
3
|
+
require 'antisamy/model/attribute'
|
4
|
+
require 'antisamy/model/tag'
|
5
|
+
require 'antisamy/model/css_property'
|
6
|
+
require 'antisamy/policy'
|
7
|
+
require 'antisamy/scan_results'
|
8
|
+
require 'antisamy/html/handler'
|
9
|
+
require 'antisamy/css/css_validator'
|
10
|
+
require 'antisamy/css/css_filter'
|
11
|
+
require 'antisamy/css/css_scanner'
|
12
|
+
require 'antisamy/html/sax_filter'
|
13
|
+
require 'antisamy/html/scanner'
|
14
|
+
|
15
|
+
module AntiSamy
|
16
|
+
class << self
|
17
|
+
|
18
|
+
# Setup the input encoding, defaults to UTF-8
|
19
|
+
def input_encoding=(encoding)
|
20
|
+
@@input_encoding = encoding
|
21
|
+
end
|
22
|
+
|
23
|
+
# Setup the output encoding defaults to UTF-8
|
24
|
+
def output_encoding=(encoding)
|
25
|
+
@@output_encoding = encoding
|
26
|
+
end
|
27
|
+
|
28
|
+
# Scan the input using the provided policy.
|
29
|
+
# will raise an exception if there is some form of scannign error
|
30
|
+
def scan(input,policy)
|
31
|
+
scanner = Scanner.new(policy)
|
32
|
+
@@input_encoding ||= Scanner::DEFAULT_ENCODE
|
33
|
+
@@output_encoding ||= Scanner::DEFAULT_ENCODE
|
34
|
+
clean = scanner.scan(input,@@input_encoding, @output_encoding)
|
35
|
+
clean
|
36
|
+
end
|
37
|
+
|
38
|
+
# Create a policy out of the provided file
|
39
|
+
# will use a string or any IO object that can be read
|
40
|
+
# will raise an exception if the policy fails to validate
|
41
|
+
def policy(policy_file)
|
42
|
+
Policy.new(policy_file)
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
@@ -1,187 +1,187 @@
|
|
1
|
-
require 'uri'
|
2
|
-
module AntiSamy
|
3
|
-
class CssFilter < RSAC::DocumentHandler
|
4
|
-
|
5
|
-
attr_accessor :clean, :errors, :style_sheets
|
6
|
-
|
7
|
-
def initialize(policy,tag)
|
8
|
-
@policy = policy
|
9
|
-
@validator = CssValidator.new(@policy)
|
10
|
-
@errors = []
|
11
|
-
@clean = ''
|
12
|
-
@tag = tag
|
13
|
-
@selector_open = false
|
14
|
-
@style_sheets = []
|
15
|
-
@inline = !tag.nil?
|
16
|
-
@media_open = false
|
17
|
-
@current_media = nil
|
18
|
-
end
|
19
|
-
# Start of document
|
20
|
-
def start_document(input_source) #:nodoc:
|
21
|
-
end
|
22
|
-
|
23
|
-
# Receive notification of the end of a style sheet.
|
24
|
-
def end_document(input_source) #:nodoc:
|
25
|
-
end
|
26
|
-
|
27
|
-
# Receive notification of a comment
|
28
|
-
def comment(text)
|
29
|
-
@errors << ScanMessage.new(ScanMessage::ERROR_COMMENT_REMOVED,@tag,text)
|
30
|
-
end
|
31
|
-
|
32
|
-
def error(exception)
|
33
|
-
#puts exception
|
34
|
-
end
|
35
|
-
|
36
|
-
def fatal_error(exception)
|
37
|
-
#puts exception
|
38
|
-
end
|
39
|
-
|
40
|
-
def error(t)
|
41
|
-
#puts t
|
42
|
-
end
|
43
|
-
|
44
|
-
def warn(t)
|
45
|
-
#puts t
|
46
|
-
end
|
47
|
-
|
48
|
-
def warning_error(exception)
|
49
|
-
#puts exception
|
50
|
-
end
|
51
|
-
# Receive notification of an unknown at rule not supported by this parser.
|
52
|
-
def ignorable_at_rule(at_rule)
|
53
|
-
if inline
|
54
|
-
@errors << ScanMessage.new(ScanMessage::ERROR_CSS_TAG_RULE_NOTFOUND,@tag,at_rule)
|
55
|
-
else
|
56
|
-
@errors << ScanMessage.new(ScanMessage::ERROR_STYLESHEET_RULE_NOTFOUND,@tag,at_rule)
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
# Namespace declaration
|
61
|
-
def namespace_declaration(prefix, uri) #:nodoc:
|
62
|
-
end
|
63
|
-
|
64
|
-
# Called on an import statement
|
65
|
-
def import_style(uri, media, default_namespace_uri = nil)
|
66
|
-
# check directive
|
67
|
-
unless @policy.directive(Policy::EMBED_STYLESHEETS)
|
68
|
-
@errors << ScanMessage.new(ScanMessage::ERROR_CSS_IMPORT_DISABLED,@tag,uri)
|
69
|
-
return
|
70
|
-
end
|
71
|
-
# check for null uri
|
72
|
-
if uri.nil?
|
73
|
-
@errors << ScanMessage.new(ScanMessage::ERROR_CSS_IMPORT_URL_INVALID,@tag)
|
74
|
-
end
|
75
|
-
# check uri rules
|
76
|
-
begin
|
77
|
-
luri = RSAC::LexicalURI.new(uri)
|
78
|
-
link = URI.parse(luri.string_value)
|
79
|
-
link.normalize!
|
80
|
-
onsite = @policy.expression("offsiteURL")
|
81
|
-
offsite = @policy.expression("onsiteURL")
|
82
|
-
# bad uri
|
83
|
-
raise "Invalid URI Pattern" if link.to_s !~ onsite and link.to_s !~ offsite
|
84
|
-
raise "Invalid URI" unless link.absolute?
|
85
|
-
@style_sheets << link
|
86
|
-
rescue Exception => e
|
87
|
-
@errors << ScanMessage.new(ScanMessage::ERROR_CSS_IMPORT_URL_INVALID,@tag,uri)
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
# Notification of the start of a media statement
|
92
|
-
def start_media(media)
|
93
|
-
@media_open = true
|
94
|
-
@current_media = media
|
95
|
-
end
|
96
|
-
|
97
|
-
# Notification of the end of a media statement
|
98
|
-
def end_media(media)
|
99
|
-
@media_open = false
|
100
|
-
@current_media = nil
|
101
|
-
end
|
102
|
-
|
103
|
-
# Notification of the start of a page statement
|
104
|
-
def start_page(name = nil, pseudo_page = nil) #:nodoc:
|
105
|
-
end
|
106
|
-
|
107
|
-
# Notification of the end of a page statement
|
108
|
-
def end_page(name = nil, pseudo_page = nil) # :nodoc:
|
109
|
-
end
|
110
|
-
|
111
|
-
# Notification of the beginning of a font face statement.
|
112
|
-
def start_font_face #:nodoc:
|
113
|
-
end
|
114
|
-
|
115
|
-
# Notification of the end of a font face statement.
|
116
|
-
def end_font_face #:nodoc:
|
117
|
-
end
|
118
|
-
|
119
|
-
# Notification of the beginning of a rule statement.
|
120
|
-
def start_selector(selectors)
|
121
|
-
count = 0
|
122
|
-
selectors.each do |s|
|
123
|
-
name = s.to_css
|
124
|
-
valid = false
|
125
|
-
begin
|
126
|
-
@validator.valid_selector?(name,s)
|
127
|
-
valid = true
|
128
|
-
rescue Exception => e
|
129
|
-
if @inline
|
130
|
-
@errors << ScanMessage.new(ScanMessage::ERROR_CSS_TAG_SELECTOR_NOTFOUND,@tag,name)
|
131
|
-
else
|
132
|
-
@errors << ScanMessage.new(ScanMessage::ERROR_STYLESHEET_SELECTOR_NOTFOUND,@tag,name)
|
133
|
-
end
|
134
|
-
|
135
|
-
end
|
136
|
-
if valid
|
137
|
-
if count > 0
|
138
|
-
clean << ", "
|
139
|
-
end
|
140
|
-
clean << name
|
141
|
-
count += 1
|
142
|
-
else
|
143
|
-
# not allowed selector
|
144
|
-
if @inline
|
145
|
-
@errors << ScanMessage.new(ScanMessage::ERROR_CSS_TAG_SELECTOR_DISALLOWED,@tag,name)
|
146
|
-
else
|
147
|
-
@errors << ScanMessage.new(ScanMessage::ERROR_STYLESHEET_SELECTOR_DISALLOWED,@tag,name)
|
148
|
-
end
|
149
|
-
end
|
150
|
-
end
|
151
|
-
if count > 0
|
152
|
-
clean << " {\n"
|
153
|
-
@selector_open = true
|
154
|
-
end
|
155
|
-
end
|
156
|
-
|
157
|
-
# Notification of the end of a rule statement.
|
158
|
-
def end_selector(selectors)
|
159
|
-
if @selector_open
|
160
|
-
clean << "}\n"
|
161
|
-
end
|
162
|
-
@selector_open = false
|
163
|
-
end
|
164
|
-
|
165
|
-
# Notification of a declaration.
|
166
|
-
def property(name, value, important)
|
167
|
-
return unless @selector_open and @inline
|
168
|
-
if @validator.valid_property?(name,value)
|
169
|
-
clean << "\t" unless @inline
|
170
|
-
clean << "#{name}:"
|
171
|
-
value.each do |v|
|
172
|
-
clean << " #{v.to_s}"
|
173
|
-
end
|
174
|
-
clean << ";"
|
175
|
-
clean << "\n" unless @inline
|
176
|
-
else
|
177
|
-
cval = value.to_s
|
178
|
-
if @inline
|
179
|
-
@errors << ScanMessage.new(ScanMessage::ERROR_CSS_TAG_PROPERTY_INVALID,@tag,name,cval)
|
180
|
-
else
|
181
|
-
@errors << ScanMessage.new(ScanMessage::ERROR_STYLESHEET_PROPERTY_INVALID,@tag,name,cval)
|
182
|
-
end
|
183
|
-
end
|
184
|
-
|
185
|
-
end
|
186
|
-
end
|
187
|
-
end
|
1
|
+
require 'uri'
|
2
|
+
module AntiSamy
|
3
|
+
class CssFilter < RSAC::DocumentHandler
|
4
|
+
|
5
|
+
attr_accessor :clean, :errors, :style_sheets
|
6
|
+
|
7
|
+
def initialize(policy,tag)
|
8
|
+
@policy = policy
|
9
|
+
@validator = CssValidator.new(@policy)
|
10
|
+
@errors = []
|
11
|
+
@clean = ''
|
12
|
+
@tag = tag
|
13
|
+
@selector_open = false
|
14
|
+
@style_sheets = []
|
15
|
+
@inline = !tag.nil?
|
16
|
+
@media_open = false
|
17
|
+
@current_media = nil
|
18
|
+
end
|
19
|
+
# Start of document
|
20
|
+
def start_document(input_source) #:nodoc:
|
21
|
+
end
|
22
|
+
|
23
|
+
# Receive notification of the end of a style sheet.
|
24
|
+
def end_document(input_source) #:nodoc:
|
25
|
+
end
|
26
|
+
|
27
|
+
# Receive notification of a comment
|
28
|
+
def comment(text)
|
29
|
+
@errors << ScanMessage.new(ScanMessage::ERROR_COMMENT_REMOVED,@tag,text)
|
30
|
+
end
|
31
|
+
|
32
|
+
def error(exception)
|
33
|
+
#puts exception
|
34
|
+
end
|
35
|
+
|
36
|
+
def fatal_error(exception)
|
37
|
+
#puts exception
|
38
|
+
end
|
39
|
+
|
40
|
+
def error(t)
|
41
|
+
#puts t
|
42
|
+
end
|
43
|
+
|
44
|
+
def warn(t)
|
45
|
+
#puts t
|
46
|
+
end
|
47
|
+
|
48
|
+
def warning_error(exception)
|
49
|
+
#puts exception
|
50
|
+
end
|
51
|
+
# Receive notification of an unknown at rule not supported by this parser.
|
52
|
+
def ignorable_at_rule(at_rule)
|
53
|
+
if inline
|
54
|
+
@errors << ScanMessage.new(ScanMessage::ERROR_CSS_TAG_RULE_NOTFOUND,@tag,at_rule)
|
55
|
+
else
|
56
|
+
@errors << ScanMessage.new(ScanMessage::ERROR_STYLESHEET_RULE_NOTFOUND,@tag,at_rule)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# Namespace declaration
|
61
|
+
def namespace_declaration(prefix, uri) #:nodoc:
|
62
|
+
end
|
63
|
+
|
64
|
+
# Called on an import statement
|
65
|
+
def import_style(uri, media, default_namespace_uri = nil)
|
66
|
+
# check directive
|
67
|
+
unless @policy.directive(Policy::EMBED_STYLESHEETS)
|
68
|
+
@errors << ScanMessage.new(ScanMessage::ERROR_CSS_IMPORT_DISABLED,@tag,uri)
|
69
|
+
return
|
70
|
+
end
|
71
|
+
# check for null uri
|
72
|
+
if uri.nil?
|
73
|
+
@errors << ScanMessage.new(ScanMessage::ERROR_CSS_IMPORT_URL_INVALID,@tag)
|
74
|
+
end
|
75
|
+
# check uri rules
|
76
|
+
begin
|
77
|
+
luri = RSAC::LexicalURI.new(uri)
|
78
|
+
link = URI.parse(luri.string_value)
|
79
|
+
link.normalize!
|
80
|
+
onsite = @policy.expression("offsiteURL")
|
81
|
+
offsite = @policy.expression("onsiteURL")
|
82
|
+
# bad uri
|
83
|
+
raise "Invalid URI Pattern" if link.to_s !~ onsite and link.to_s !~ offsite
|
84
|
+
raise "Invalid URI" unless link.absolute?
|
85
|
+
@style_sheets << link
|
86
|
+
rescue Exception => e
|
87
|
+
@errors << ScanMessage.new(ScanMessage::ERROR_CSS_IMPORT_URL_INVALID,@tag,uri)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# Notification of the start of a media statement
|
92
|
+
def start_media(media)
|
93
|
+
@media_open = true
|
94
|
+
@current_media = media
|
95
|
+
end
|
96
|
+
|
97
|
+
# Notification of the end of a media statement
|
98
|
+
def end_media(media)
|
99
|
+
@media_open = false
|
100
|
+
@current_media = nil
|
101
|
+
end
|
102
|
+
|
103
|
+
# Notification of the start of a page statement
|
104
|
+
def start_page(name = nil, pseudo_page = nil) #:nodoc:
|
105
|
+
end
|
106
|
+
|
107
|
+
# Notification of the end of a page statement
|
108
|
+
def end_page(name = nil, pseudo_page = nil) # :nodoc:
|
109
|
+
end
|
110
|
+
|
111
|
+
# Notification of the beginning of a font face statement.
|
112
|
+
def start_font_face #:nodoc:
|
113
|
+
end
|
114
|
+
|
115
|
+
# Notification of the end of a font face statement.
|
116
|
+
def end_font_face #:nodoc:
|
117
|
+
end
|
118
|
+
|
119
|
+
# Notification of the beginning of a rule statement.
|
120
|
+
def start_selector(selectors)
|
121
|
+
count = 0
|
122
|
+
selectors.each do |s|
|
123
|
+
name = s.to_css
|
124
|
+
valid = false
|
125
|
+
begin
|
126
|
+
@validator.valid_selector?(name,s)
|
127
|
+
valid = true
|
128
|
+
rescue Exception => e
|
129
|
+
if @inline
|
130
|
+
@errors << ScanMessage.new(ScanMessage::ERROR_CSS_TAG_SELECTOR_NOTFOUND,@tag,name)
|
131
|
+
else
|
132
|
+
@errors << ScanMessage.new(ScanMessage::ERROR_STYLESHEET_SELECTOR_NOTFOUND,@tag,name)
|
133
|
+
end
|
134
|
+
|
135
|
+
end
|
136
|
+
if valid
|
137
|
+
if count > 0
|
138
|
+
clean << ", "
|
139
|
+
end
|
140
|
+
clean << name
|
141
|
+
count += 1
|
142
|
+
else
|
143
|
+
# not allowed selector
|
144
|
+
if @inline
|
145
|
+
@errors << ScanMessage.new(ScanMessage::ERROR_CSS_TAG_SELECTOR_DISALLOWED,@tag,name)
|
146
|
+
else
|
147
|
+
@errors << ScanMessage.new(ScanMessage::ERROR_STYLESHEET_SELECTOR_DISALLOWED,@tag,name)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
if count > 0
|
152
|
+
clean << " {\n"
|
153
|
+
@selector_open = true
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
# Notification of the end of a rule statement.
|
158
|
+
def end_selector(selectors)
|
159
|
+
if @selector_open
|
160
|
+
clean << "}\n"
|
161
|
+
end
|
162
|
+
@selector_open = false
|
163
|
+
end
|
164
|
+
|
165
|
+
# Notification of a declaration.
|
166
|
+
def property(name, value, important)
|
167
|
+
return unless @selector_open and @inline
|
168
|
+
if @validator.valid_property?(name,value)
|
169
|
+
clean << "\t" unless @inline
|
170
|
+
clean << "#{name}:"
|
171
|
+
value.each do |v|
|
172
|
+
clean << " #{v.to_s}"
|
173
|
+
end
|
174
|
+
clean << ";"
|
175
|
+
clean << "\n" unless @inline
|
176
|
+
else
|
177
|
+
cval = value.to_s
|
178
|
+
if @inline
|
179
|
+
@errors << ScanMessage.new(ScanMessage::ERROR_CSS_TAG_PROPERTY_INVALID,@tag,name,cval)
|
180
|
+
else
|
181
|
+
@errors << ScanMessage.new(ScanMessage::ERROR_STYLESHEET_PROPERTY_INVALID,@tag,name,cval)
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|