selma 0.2.2 → 0.4.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5,9 +5,11 @@ use lol_html::{
5
5
  html_content::{Comment, ContentType, Doctype, Element, EndTag},
6
6
  };
7
7
  use magnus::{
8
- class, function, method, scan_args,
8
+ class, eval, exception, function, method,
9
+ r_hash::ForEach,
10
+ scan_args,
9
11
  value::{Opaque, ReprValue},
10
- Module, Object, RArray, RHash, RModule, Ruby, Value,
12
+ Module, Object, RArray, RHash, RModule, RString, Ruby, Symbol, Value,
11
13
  };
12
14
 
13
15
  #[derive(Clone, Debug, Default)]
@@ -45,34 +47,234 @@ impl SelmaSanitizer {
45
47
  let args = scan_args::scan_args::<(), (Option<RHash>,), (), (), (), ()>(arguments)?;
46
48
  let (opt_config,): (Option<RHash>,) = args.optional;
47
49
 
50
+ let ruby = Ruby::get().unwrap();
51
+
48
52
  let config = match opt_config {
49
53
  Some(config) => config,
50
54
  // TODO: this seems like a hack to fix?
51
55
  None => magnus::eval::<RHash>(r#"Selma::Sanitizer::Config::DEFAULT"#).unwrap(),
52
56
  };
53
57
 
58
+ let mut flags = [0; crate::tags::Tag::TAG_COUNT];
59
+ let mut sanitizer_allowed_attrs = vec![];
60
+ let sanitizer_allowed_classes = vec![];
61
+ match Self::setup_config(&mut flags, config) {
62
+ Ok(_) => {}
63
+ Err(e) => {
64
+ return Err(e);
65
+ }
66
+ };
67
+
54
68
  let mut element_sanitizers = HashMap::new();
69
+
70
+ // TODO: set up default tags; do we need this?
55
71
  crate::tags::Tag::html_tags().iter().for_each(|html_tag| {
56
- let es = ElementSanitizer::default();
57
- element_sanitizers.insert(
58
- crate::tags::Tag::element_name_from_enum(html_tag).to_string(),
59
- es,
60
- );
72
+ let element_name = crate::tags::Tag::element_name_from_enum(html_tag).to_string();
73
+
74
+ let element_sanitizer = ElementSanitizer::default();
75
+ element_sanitizers.insert(element_name, element_sanitizer);
61
76
  });
62
77
 
78
+ // def allow_attribute(element, attrs)
79
+ // attrs.flatten.each { |attr| set_allowed_attribute(element, attr, true) }
80
+ // end
81
+ if let Some(value) = config.get(ruby.to_symbol("attributes")) {
82
+ if let Some(allowed_attributes) = RHash::from_value(value) {
83
+ allowed_attributes.foreach(|element_value: Value, attributes: RArray| {
84
+ attributes.into_iter().for_each(|attr: Value| {
85
+ match RString::from_value(attr) {
86
+ None => {}
87
+ Some(attribute_name) => {
88
+ let attr_name = attribute_name.to_string().unwrap();
89
+ let element = match element_value.to_r_string() {
90
+ Err(_) => "".to_string(),
91
+ Ok(element_name) => element_name.to_string().unwrap(),
92
+ };
93
+ if element == "all" {
94
+ Self::set_allowed(
95
+ &mut sanitizer_allowed_attrs,
96
+ &attr_name,
97
+ true,
98
+ );
99
+ } else {
100
+ let element_sanitizer = Self::get_element_sanitizer(
101
+ &mut element_sanitizers,
102
+ &element,
103
+ );
104
+ element_sanitizer.allowed_attrs.push(attr_name);
105
+ }
106
+ }
107
+ }
108
+ });
109
+
110
+ Ok(ForEach::Continue)
111
+ })?;
112
+ }
113
+ };
114
+
115
+ // def allow_protocol(element, attr, protos)
116
+ // if protos.is_a?(Array)
117
+ // raise ArgumentError, "`:all` must be passed outside of an array" if protos.include?(:all)
118
+ // else
119
+ // protos = [protos]
120
+ // end
121
+ // set_allowed_protocols(element, attr, protos)
122
+ // end
123
+ if let Some(value) = config.get(ruby.to_symbol("protocols")) {
124
+ if let Some(allowed_protocols) = RHash::from_value(value) {
125
+ allowed_protocols.foreach(|element_name: String, protocols: RHash| {
126
+ protocols.foreach(|attribute_name: String, protocol_list: Value| {
127
+ let protocols: RArray;
128
+ if protocol_list.is_kind_of(class::array()) {
129
+ protocols = RArray::from_value(protocol_list).unwrap();
130
+ if protocols.includes(ruby.to_symbol("all")) {
131
+ return Err(magnus::Error::new(
132
+ exception::arg_error(),
133
+ "`:all` must be passed outside of an array".to_string(),
134
+ ));
135
+ }
136
+ } else if protocol_list.is_kind_of(class::symbol())
137
+ && Symbol::from_value(protocol_list) == eval(":all").unwrap()
138
+ {
139
+ protocols = RArray::new();
140
+ protocols.push(ruby.to_symbol("all"))?;
141
+ } else {
142
+ return Err(magnus::Error::new(
143
+ exception::arg_error(),
144
+ "Protocol list must be an array, or just `:all`".to_string(),
145
+ ));
146
+ }
147
+
148
+ let element_sanitizer =
149
+ Self::get_element_sanitizer(&mut element_sanitizers, &element_name);
150
+
151
+ Self::set_allowed_protocols(element_sanitizer, attribute_name, protocols);
152
+ Ok(ForEach::Continue)
153
+ })?;
154
+
155
+ Ok(ForEach::Continue)
156
+ })?;
157
+ }
158
+ }
159
+
160
+ let escape_tagfilter = match config.get(ruby.to_symbol("escape_tagfilter")) {
161
+ Some(value) => value.to_bool(),
162
+ None => true,
163
+ };
164
+
165
+ let allow_comments = match config.get(ruby.to_symbol("allow_comments")) {
166
+ Some(value) => value.to_bool(),
167
+ None => false,
168
+ };
169
+
170
+ let allow_doctype = match config.get(ruby.to_symbol("allow_doctype")) {
171
+ Some(value) => value.to_bool(),
172
+ None => true,
173
+ };
174
+
63
175
  Ok(Self(std::cell::RefCell::new(Sanitizer {
64
- flags: [0; crate::tags::Tag::TAG_COUNT],
65
- allowed_attrs: vec![],
66
- allowed_classes: vec![],
176
+ flags,
177
+ allowed_attrs: sanitizer_allowed_attrs,
178
+ allowed_classes: sanitizer_allowed_classes,
67
179
  element_sanitizers,
68
180
 
69
- escape_tagfilter: true,
70
- allow_comments: false,
71
- allow_doctype: true,
181
+ escape_tagfilter,
182
+ allow_comments,
183
+ allow_doctype,
72
184
  config: config.into(),
73
185
  })))
74
186
  }
75
187
 
188
+ fn setup_config(
189
+ flags: &mut [u8; crate::tags::Tag::TAG_COUNT],
190
+ config: RHash,
191
+ ) -> Result<(), magnus::Error> {
192
+ let ruby = Ruby::get().unwrap();
193
+
194
+ // def allow_element(elements)
195
+ // elements.flatten.each { |e| set_flag(e, ALLOW, true) }
196
+ // end
197
+ if let Some(value) = config.get(ruby.to_symbol("elements")) {
198
+ if let Some(elements) = RArray::from_value(value) {
199
+ elements
200
+ .into_iter()
201
+ .for_each(|element| match RString::from_value(element) {
202
+ None => {}
203
+ Some(element_name) => {
204
+ Self::set_flag(
205
+ element_name.to_string().unwrap(),
206
+ flags,
207
+ Self::SELMA_SANITIZER_ALLOW,
208
+ true,
209
+ );
210
+ }
211
+ });
212
+ }
213
+ }
214
+
215
+ // def remove_contents(elements)
216
+ // if elements.is_a?(TrueClass) || elements.is_a?(FalseClass)
217
+ // set_all_flags(REMOVE_CONTENTS, elements)
218
+ // else
219
+ // elements.flatten.each { |e| set_flag(e, REMOVE_CONTENTS, true) }
220
+ // end
221
+ // end
222
+ if let Some(remove_contents) = config.get(ruby.to_symbol("remove_contents")) {
223
+ if remove_contents.is_kind_of(class::true_class())
224
+ || remove_contents.is_kind_of(class::false_class())
225
+ {
226
+ Self::set_all_flags(
227
+ flags,
228
+ Self::SELMA_SANITIZER_REMOVE_CONTENTS,
229
+ remove_contents.to_bool(),
230
+ );
231
+ } else if remove_contents.is_kind_of(class::array()) {
232
+ let elements = RArray::from_value(remove_contents).unwrap();
233
+ elements
234
+ .into_iter()
235
+ .for_each(|element| match RString::from_value(element) {
236
+ None => {}
237
+ Some(element_name) => {
238
+ Self::set_flag(
239
+ element_name.to_string().unwrap(),
240
+ flags,
241
+ Self::SELMA_SANITIZER_REMOVE_CONTENTS,
242
+ true,
243
+ );
244
+ }
245
+ });
246
+ } else {
247
+ return Err(magnus::Error::new(
248
+ exception::arg_error(),
249
+ "remove_contents must be `true`, `false`, or an array".to_string(),
250
+ ));
251
+ }
252
+ }
253
+
254
+ // def wrap_with_whitespace(elements)
255
+ // elements.flatten.each { |e| set_flag(e, WRAP_WHITESPACE, true) }
256
+ // end
257
+ if let Some(value) = config.get(ruby.to_symbol("whitespace_elements")) {
258
+ if let Some(elements) = RArray::from_value(value) {
259
+ elements
260
+ .into_iter()
261
+ .for_each(|element| match RString::from_value(element) {
262
+ None => {}
263
+ Some(element_name) => {
264
+ Self::set_flag(
265
+ element_name.to_string().unwrap(),
266
+ flags,
267
+ Self::SELMA_SANITIZER_WRAP_WHITESPACE,
268
+ true,
269
+ );
270
+ }
271
+ });
272
+ }
273
+ };
274
+
275
+ Ok(())
276
+ }
277
+
76
278
  fn get_config(&self) -> Result<RHash, magnus::Error> {
77
279
  let binding = self.0.borrow();
78
280
  let ruby = Ruby::get().unwrap();
@@ -81,40 +283,39 @@ impl SelmaSanitizer {
81
283
  }
82
284
 
83
285
  /// Toggle a sanitizer option on or off.
84
- fn set_flag(&self, tag_name: String, flag: u8, set: bool) {
286
+ fn set_flag(
287
+ tag_name: String,
288
+ flags: &mut [u8; crate::tags::Tag::TAG_COUNT],
289
+ flag: u8,
290
+ set: bool,
291
+ ) {
85
292
  let tag = crate::tags::Tag::tag_from_tag_name(tag_name.as_str());
86
293
  if set {
87
- self.0.borrow_mut().flags[tag.index] |= flag;
294
+ flags[tag.index] |= flag;
88
295
  } else {
89
- self.0.borrow_mut().flags[tag.index] &= !flag;
296
+ flags[tag.index] &= !flag;
90
297
  }
91
298
  }
92
299
 
93
300
  /// Toggles all sanitization options on or off.
94
- fn set_all_flags(&self, flag: u8, set: bool) {
301
+ fn set_all_flags(flags: &mut [u8; crate::tags::Tag::TAG_COUNT], flag: u8, set: bool) {
95
302
  if set {
96
303
  crate::tags::Tag::html_tags()
97
304
  .iter()
98
305
  .enumerate()
99
306
  .for_each(|(iter, _)| {
100
- self.0.borrow_mut().flags[iter] |= flag;
307
+ flags[iter] |= flag;
101
308
  });
102
309
  } else {
103
310
  crate::tags::Tag::html_tags()
104
311
  .iter()
105
312
  .enumerate()
106
313
  .for_each(|(iter, _)| {
107
- self.0.borrow_mut().flags[iter] &= flag;
314
+ flags[iter] &= flag;
108
315
  });
109
316
  }
110
317
  }
111
318
 
112
- /// Whether or not to keep dangerous HTML tags.
113
- fn set_escape_tagfilter(&self, allow: bool) -> bool {
114
- self.0.borrow_mut().escape_tagfilter = allow;
115
- allow
116
- }
117
-
118
319
  pub fn escape_tagfilter(&self, e: &mut Element) -> bool {
119
320
  if self.0.borrow().escape_tagfilter {
120
321
  let tag = crate::tags::Tag::tag_from_element(e);
@@ -131,12 +332,6 @@ impl SelmaSanitizer {
131
332
  self.0.borrow().escape_tagfilter
132
333
  }
133
334
 
134
- /// Whether or not to keep HTML comments.
135
- fn set_allow_comments(&self, allow: bool) -> bool {
136
- self.0.borrow_mut().allow_comments = allow;
137
- allow
138
- }
139
-
140
335
  pub fn get_allow_comments(&self) -> bool {
141
336
  self.0.borrow().allow_comments
142
337
  }
@@ -145,12 +340,6 @@ impl SelmaSanitizer {
145
340
  c.remove();
146
341
  }
147
342
 
148
- /// Whether or not to keep HTML doctype.
149
- fn set_allow_doctype(&self, allow: bool) -> bool {
150
- self.0.borrow_mut().allow_doctype = allow;
151
- allow
152
- }
153
-
154
343
  /// Whether or not to keep HTML doctype.
155
344
  pub fn get_allow_doctype(&self) -> bool {
156
345
  self.0.borrow().allow_doctype
@@ -160,48 +349,14 @@ impl SelmaSanitizer {
160
349
  d.remove();
161
350
  }
162
351
 
163
- fn set_allowed_attribute(&self, eln: Value, attr_name: String, allow: bool) -> bool {
164
- let mut binding = self.0.borrow_mut();
165
-
166
- let element_name = eln.to_r_string().unwrap().to_string().unwrap();
167
- if element_name == "all" {
168
- let allowed_attrs = &mut binding.allowed_attrs;
169
- Self::set_allowed(allowed_attrs, &attr_name, allow);
170
- } else {
171
- let element_sanitizers = &mut binding.element_sanitizers;
172
- let element_sanitizer = Self::get_element_sanitizer(element_sanitizers, &element_name);
173
-
174
- element_sanitizer.allowed_attrs.push(attr_name);
175
- }
176
-
177
- allow
178
- }
179
-
180
- fn set_allowed_class(&self, element_name: String, class_name: String, allow: bool) -> bool {
181
- let mut binding = self.0.borrow_mut();
182
- if element_name == "all" {
183
- let allowed_classes = &mut binding.allowed_classes;
184
- Self::set_allowed(allowed_classes, &class_name, allow);
185
- } else {
186
- let element_sanitizers = &mut binding.element_sanitizers;
187
- let element_sanitizer = Self::get_element_sanitizer(element_sanitizers, &element_name);
188
-
189
- let allowed_classes = element_sanitizer.allowed_classes.borrow_mut();
190
- Self::set_allowed(allowed_classes, &class_name, allow)
191
- }
192
- allow
193
- }
194
-
195
- fn set_allowed_protocols(&self, element_name: String, attr_name: String, allow_list: RArray) {
196
- let mut binding = self.0.borrow_mut();
197
-
198
- let element_sanitizers = &mut binding.element_sanitizers;
199
- let element_sanitizer = Self::get_element_sanitizer(element_sanitizers, &element_name);
200
-
352
+ fn set_allowed_protocols(
353
+ element_sanitizer: &mut ElementSanitizer,
354
+ attr_name: String,
355
+ allow_list: RArray,
356
+ ) {
201
357
  let protocol_sanitizers = &mut element_sanitizer.protocol_sanitizers.borrow_mut();
202
358
 
203
- for opt_allowed_protocol in allow_list.each() {
204
- let allowed_protocol = opt_allowed_protocol.unwrap();
359
+ for allowed_protocol in allow_list.into_iter() {
205
360
  let protocol_list = protocol_sanitizers.get_mut(&attr_name);
206
361
  if allowed_protocol.is_kind_of(class::string()) {
207
362
  match protocol_list {
@@ -211,20 +366,23 @@ impl SelmaSanitizer {
211
366
  }
212
367
  Some(protocol_list) => protocol_list.push(allowed_protocol.to_string()),
213
368
  }
214
- } else if allowed_protocol.is_kind_of(class::symbol())
215
- && allowed_protocol.inspect() == ":relative"
216
- {
217
- match protocol_list {
218
- None => {
219
- protocol_sanitizers.insert(
220
- attr_name.to_string(),
221
- vec!["#".to_string(), "/".to_string()],
222
- );
223
- }
224
- Some(protocol_list) => {
225
- protocol_list.push("#".to_string());
226
- protocol_list.push("/".to_string());
369
+ } else if allowed_protocol.is_kind_of(class::symbol()) {
370
+ let protocol_config = allowed_protocol.inspect();
371
+ if protocol_config == ":relative" {
372
+ match protocol_list {
373
+ None => {
374
+ protocol_sanitizers.insert(
375
+ attr_name.to_string(),
376
+ vec!["#".to_string(), "/".to_string()],
377
+ );
378
+ }
379
+ Some(protocol_list) => {
380
+ protocol_list.push("#".to_string());
381
+ protocol_list.push("/".to_string());
382
+ }
227
383
  }
384
+ } else if protocol_config == ":all" {
385
+ protocol_sanitizers.insert(attr_name.to_string(), vec!["all".to_string()]);
228
386
  }
229
387
  }
230
388
  }
@@ -335,7 +493,7 @@ impl SelmaSanitizer {
335
493
  element: &mut Element,
336
494
  element_sanitizer: &ElementSanitizer,
337
495
  attr_name: &String,
338
- attr_val: &String,
496
+ attr_val: &str,
339
497
  ) -> Result<bool, AttributeNameError> {
340
498
  let mut allowed: bool = false;
341
499
  let element_allowed_attrs = element_sanitizer.allowed_attrs.contains(attr_name);
@@ -387,7 +545,11 @@ impl SelmaSanitizer {
387
545
  attr_val.contains("://")
388
546
  }
389
547
 
390
- fn has_allowed_protocol(protocols_allowed: &[String], attr_val: &String) -> bool {
548
+ fn has_allowed_protocol(protocols_allowed: &[String], attr_val: &str) -> bool {
549
+ if protocols_allowed.contains(&"all".to_string()) {
550
+ return true;
551
+ }
552
+
391
553
  // FIXME: is there a more idiomatic way to do this?
392
554
  let mut pos: usize = 0;
393
555
  let mut chars = attr_val.chars();
@@ -509,6 +671,7 @@ impl SelmaSanitizer {
509
671
  element.after(" ", ContentType::Text);
510
672
  }
511
673
  }
674
+
512
675
  element.remove_and_keep_content();
513
676
  }
514
677
  }
@@ -542,7 +705,7 @@ impl SelmaSanitizer {
542
705
  ) -> &'a mut ElementSanitizer {
543
706
  element_sanitizers
544
707
  .entry(element_name.to_string())
545
- .or_insert_with(ElementSanitizer::default)
708
+ .or_default()
546
709
  }
547
710
  }
548
711
 
@@ -554,50 +717,5 @@ pub fn init(m_selma: RModule) -> Result<(), magnus::Error> {
554
717
  c_sanitizer.define_singleton_method("new", function!(SelmaSanitizer::new, -1))?;
555
718
  c_sanitizer.define_method("config", method!(SelmaSanitizer::get_config, 0))?;
556
719
 
557
- c_sanitizer.define_method("set_flag", method!(SelmaSanitizer::set_flag, 3))?;
558
- c_sanitizer.define_method("set_all_flags", method!(SelmaSanitizer::set_all_flags, 2))?;
559
-
560
- c_sanitizer.define_method(
561
- "set_escape_tagfilter",
562
- method!(SelmaSanitizer::set_escape_tagfilter, 1),
563
- )?;
564
- c_sanitizer.define_method(
565
- "escape_tagfilter",
566
- method!(SelmaSanitizer::get_escape_tagfilter, 0),
567
- )?;
568
-
569
- c_sanitizer.define_method(
570
- "set_allow_comments",
571
- method!(SelmaSanitizer::set_allow_comments, 1),
572
- )?;
573
- c_sanitizer.define_method(
574
- "allow_comments",
575
- method!(SelmaSanitizer::get_allow_comments, 0),
576
- )?;
577
-
578
- c_sanitizer.define_method(
579
- "set_allow_doctype",
580
- method!(SelmaSanitizer::set_allow_doctype, 1),
581
- )?;
582
- c_sanitizer.define_method(
583
- "allow_doctype",
584
- method!(SelmaSanitizer::get_allow_doctype, 0),
585
- )?;
586
-
587
- c_sanitizer.define_method(
588
- "set_allowed_attribute",
589
- method!(SelmaSanitizer::set_allowed_attribute, 3),
590
- )?;
591
-
592
- c_sanitizer.define_method(
593
- "set_allowed_class",
594
- method!(SelmaSanitizer::set_allowed_class, 3),
595
- )?;
596
-
597
- c_sanitizer.define_method(
598
- "set_allowed_protocols",
599
- method!(SelmaSanitizer::set_allowed_protocols, 3),
600
- )?;
601
-
602
720
  Ok(())
603
721
  }
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Selma
4
+ module Config
5
+ OPTIONS = {
6
+ memory: {
7
+ max_allowed_memory_usage: nil,
8
+ preallocated_parsing_buffer_size: nil,
9
+ },
10
+ }
11
+ end
12
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Selma
4
+ class HTML
5
+ class Element
6
+ def available?
7
+ !removed?
8
+ end
9
+ end
10
+ end
11
+ end
data/lib/selma/html.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "html/element"
4
+
3
5
  module Selma
4
6
  class HTML
5
7
  end
@@ -28,7 +28,7 @@ module Selma
28
28
 
29
29
  # URL handling protocols to allow in specific attributes. By default, no
30
30
  # protocols are allowed. Use :relative in place of a protocol if you want
31
- # to allow relative URLs sans protocol.
31
+ # to allow relative URLs sans protocol. Set to `:all` to allow any protocol.
32
32
  protocols: {},
33
33
 
34
34
  # An Array of element names whose contents will be removed. The contents
@@ -16,6 +16,7 @@ module Selma
16
16
  "colgroup",
17
17
  "data",
18
18
  "del",
19
+ "details",
19
20
  "div",
20
21
  "figcaption",
21
22
  "figure",
@@ -28,7 +28,7 @@ module Selma
28
28
  raise ArgumentError, "other_config must be a Hash" unless other_config.is_a?(Hash)
29
29
 
30
30
  merged = {}
31
- keys = Set.new(config.keys + other_config.keys)
31
+ keys = Set.new(config.keys + other_config.keys).to_a
32
32
 
33
33
  keys.each do |key|
34
34
  oldval = config[key]
@@ -39,7 +39,7 @@ module Selma
39
39
  merged[key] = if oldval.is_a?(Hash) && newval.is_a?(Hash)
40
40
  oldval.empty? ? newval.dup : merge(oldval, newval)
41
41
  elsif newval.is_a?(Array) && key != :transformers
42
- Set.new(newval)
42
+ Set.new(newval).to_a
43
43
  else
44
44
  can_dupe?(newval) ? newval.dup : newval
45
45
  end
@@ -4,82 +4,5 @@ require "selma/sanitizer/config"
4
4
 
5
5
  module Selma
6
6
  class Sanitizer
7
- ALLOW = 1 << 0
8
- ESCAPE_TAGFILTER = (1 << 1)
9
- REMOVE_CONTENTS = (1 << 2)
10
- WRAP_WHITESPACE = (1 << 3)
11
-
12
- # initialize is in Rust, this just helps manage config setup in Ruby
13
- # TODO: could this just become initialize?
14
- def setup
15
- allow_element(config[:elements] || [])
16
-
17
- (config[:attributes] || {}).each do |element, attrs|
18
- allow_attribute(element, attrs)
19
- end
20
-
21
- (config[:protocols] || {}).each do |element, protocols|
22
- protocols.each do |attribute, pr|
23
- allow_protocol(element, attribute, pr)
24
- end
25
- end
26
-
27
- remove_contents(config[:remove_contents]) if config.include?(:remove_contents)
28
-
29
- wrap_with_whitespace(config[:whitespace_elements]) if config.include?(:whitespace_elements)
30
-
31
- set_escape_tagfilter(config.fetch(:escape_tagfilter, true))
32
- set_allow_comments(config.fetch(:allow_comments, false))
33
- set_allow_doctype(config.fetch(:allow_doctype, true))
34
- end
35
-
36
- def elements
37
- config[:elements]
38
- end
39
-
40
- def allow_element(elements)
41
- elements.flatten.each { |e| set_flag(e, ALLOW, true) }
42
- end
43
-
44
- def disallow_element(elements)
45
- elements.flatten.each { |e| set_flag(e, ALLOW, false) }
46
- end
47
-
48
- def allow_attribute(element, attrs)
49
- attrs.flatten.each { |attr| set_allowed_attribute(element, attr, true) }
50
- end
51
-
52
- def require_any_attributes(element, attrs)
53
- if attr.empty?
54
- set_required_attribute(element, "*", true)
55
- else
56
- attrs.flatten.each { |attr| set_required_attribute(element, attr, true) }
57
- end
58
- end
59
-
60
- def disallow_attribute(element, attrs)
61
- attrs.flatten.each { |attr| set_allowed_attribute(element, attr, false) }
62
- end
63
-
64
- def allow_class(element, *klass)
65
- klass.flatten.each { |k| set_allowed_class(element, k, true) }
66
- end
67
-
68
- def allow_protocol(element, attr, protos)
69
- protos = [protos] unless protos.is_a?(Array)
70
- set_allowed_protocols(element, attr, protos)
71
- end
72
-
73
- def remove_contents(elements)
74
- if elements.is_a?(TrueClass) || elements.is_a?(FalseClass)
75
- set_all_flags(REMOVE_CONTENTS, elements)
76
- else
77
- elements.flatten.each { |e| set_flag(e, REMOVE_CONTENTS, true) }
78
- end
79
- end
80
-
81
- def wrap_with_whitespace(elements)
82
- elements.flatten.each { |e| set_flag(e, WRAP_WHITESPACE, true) }
83
- end
84
7
  end
85
8
  end
data/lib/selma/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Selma
4
- VERSION = "0.2.2"
4
+ VERSION = "0.4.10"
5
5
  end