more styling
[roojs1] / Roo / htmleditor / FilterAttributes.js
1  
2
3 /**
4  * @class Roo.htmleditor.FilterAttributes
5  * clean attributes and  styles including http:// etc.. in attribute
6  * @constructor
7 * Run a new Attribute Filter
8 * @param {Object} config Configuration options
9  */
10 Roo.htmleditor.FilterAttributes = function(cfg)
11 {
12     Roo.apply(this, cfg);
13     this.attrib_black = this.attrib_black || [];
14     this.attrib_white = this.attrib_white || [];
15
16     this.attrib_clean = this.attrib_clean || [];
17     this.style_white = this.style_white || [];
18     this.style_black = this.style_black || [];
19     this.walk(cfg.node);
20 }
21
22 Roo.extend(Roo.htmleditor.FilterAttributes, Roo.htmleditor.Filter,
23 {
24     tag: true, // all tags
25     
26     attrib_black : false, // array
27     attrib_clean : false,
28     attrib_white : false,
29
30     style_white : false,
31     style_black : false,
32      
33      
34     replaceTag : function(node)
35     {
36         if (!node.attributes || !node.attributes.length) {
37             return true;
38         }
39         
40         for (var i = node.attributes.length-1; i > -1 ; i--) {
41             var a = node.attributes[i];
42             //console.log(a);
43             if (this.attrib_white.length && this.attrib_white.indexOf(a.name.toLowerCase()) < 0) {
44                 node.removeAttribute(a.name);
45                 continue;
46             }
47             
48             
49             
50             if (a.name.toLowerCase().substr(0,2)=='on')  {
51                 node.removeAttribute(a.name);
52                 continue;
53             }
54             
55             
56             if (this.attrib_black.indexOf(a.name.toLowerCase()) > -1) {
57                 node.removeAttribute(a.name);
58                 continue;
59             }
60             if (this.attrib_clean.indexOf(a.name.toLowerCase()) > -1) {
61                 this.cleanAttr(node,a.name,a.value); // fixme..
62                 continue;
63             }
64             if (a.name == 'style') {
65                 this.cleanStyle(node,a.name,a.value);
66                 continue;
67             }
68             /// clean up MS crap..
69             // tecnically this should be a list of valid class'es..
70             
71             
72             if (a.name == 'class') {
73                 if (a.value.match(/^Mso/)) {
74                     node.removeAttribute('class');
75                 }
76                 
77                 if (a.value.match(/^body$/)) {
78                     node.removeAttribute('class');
79                 }
80                 continue;
81             }
82             
83             
84             // style cleanup!?
85             // class cleanup?
86             
87         }
88         return true; // clean children
89     },
90         
91     cleanAttr: function(node, n,v)
92     {
93         
94         if (v.match(/^\./) || v.match(/^\//)) {
95             return;
96         }
97         if (v.match(/^(http|https):\/\//)
98             || v.match(/^mailto:/) 
99             || v.match(/^ftp:/)
100             || v.match(/^data:/)
101             ) {
102             return;
103         }
104         if (v.match(/^#/)) {
105             return;
106         }
107         if (v.match(/^\{/)) { // allow template editing.
108             return;
109         }
110 //            Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
111         node.removeAttribute(n);
112         
113     },
114     cleanStyle : function(node,  n,v)
115     {
116         if (v.match(/expression/)) { //XSS?? should we even bother..
117             node.removeAttribute(n);
118             return;
119         }
120         
121         var parts = v.split(/;/);
122         var clean = [];
123         
124         Roo.each(parts, function(p) {
125             p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
126             if (!p.length) {
127                 return true;
128             }
129             var l = p.split(':').shift().replace(/\s+/g,'');
130             l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
131             
132             if ( this.style_black.length && (this.style_black.indexOf(l) > -1 || this.style_black.indexOf(l.toLowerCase()) > -1)) {
133                 return true;
134             }
135             //Roo.log()
136             // only allow 'c whitelisted system attributes'
137             if ( this.style_white.length &&  style_white.indexOf(l) < 0 && style_white.indexOf(l.toLowerCase()) < 0 ) {
138                 return true;
139             }
140             
141             
142             clean.push(p);
143             return true;
144         },this);
145         if (clean.length) { 
146             node.setAttribute(n, clean.join(';'));
147         } else {
148             node.removeAttribute(n);
149         }
150         
151     }
152         
153         
154         
155     
156 });