-
Notifications
You must be signed in to change notification settings - Fork 2
/
WebAPI.HTML.pas
119 lines (105 loc) · 3.9 KB
/
WebAPI.HTML.pas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
unit WebAPI.HTML;
interface
uses WebAPI;
type
t = array of string;
HTMLSanitizer = class static sealed
private
class var vAllowedTags : Variant := class
'b' : array of String;
'em' : array of String;
'i' : array of String;
'u' : array of String;
'strong' : array of String;
'strike' : array of String;
'br' : array of String;
'hr' : array of String;
'a' := ['href', 'name', 'target'];
'p' : array of String;
'div' : array of String;
'span' : array of String;
'pre' : array of String;
'code' : array of String;
'blockquote' : array of String;
'h1' : array of String;
'h2' : array of String;
'h3' : array of String;
'h4' : array of String;
'ul' : array of String;
'ol' : array of String;
'nl' : array of String;
'li' : array of String;
end;
class var vAllowedSchemes : Variant := class
'http' := '*';
'https' := '*';
'ftp' := '*';
'mailto' := '*';
end;
public
class function DOMtoJSON(node : Variant; sanitize : Boolean = True) : Variant; static;
class function JSONtoDOM(obj : Variant) : Variant; static;
class property AllowedTags : Variant read vAllowedTags write vAllowedTags;
class property AllowedSchemes : Variant read vAllowedSchemes write vAllowedSchemes;
end;
implementation
class function HTMLSanitizer.DOMtoJSON(node : Variant; sanitize : Boolean = True) : Variant;
begin
if node.nodeType = 1 then begin
var tagName := node.tagName.toLowerCase();
var allowedAttributes := HTMLSanitizer.AllowedTags[tagName];
if sanitize and not allowedAttributes then exit nil;
Result := class tag := node.tagName.toLowerCase() end;
var attrs := node.attributes;
if attrs and (attrs.length > 0) then begin
Result.attr := new JObject;
for var i := attrs.length-1 downto 0 do begin
var attrName := attrs[i].nodeName.toLowerCase();
var attrValue := attrs[i].nodeValue;
if sanitize and allowedAttributes[attrName] then begin
if attrName in ['href', 'src'] then
if not HTMLSanitizer.AllowedSchemes[attrValue.Before(':')] then
attrName := '';
end;
if attrName <> '' then
Result.attr[attrName] := attrValue;
end;
end;
var nodes := node.childNodes;
if nodes and (nodes.length > 0) then begin
Result.nodes := [];
for var i := 0 to nodes.length-1 do begin
var child := HTMLSanitizer.DOMtoJSON(nodes[i]);
if child <> nil then
Result.nodes.push(child);
end;
end;
end else if node.nodeType = 3 then begin
Result := node.nodeValue;
end else Result := nil;
end;
class function HTMLSanitizer.JSONtoDOM(obj : Variant) : Variant;
begin
if TypeOf(obj)='string' then
exit Document.createTextNode(obj);
var allowedAttributes := HTMLSanitizer.AllowedTags[obj.tag];
if not allowedAttributes then exit nil;
Result := Document.createElement(obj.tag);
if obj.attr then begin
for var n in obj.attr do begin
if allowedAttributes[n] then begin
var attrValue := obj.attr[n];
if n in ['href', 'src'] then
if not HTMLSanitizer.AllowedSchemes[attrValue.Before(':')] then continue;
Result.setAttribute(n, obj.attr[n]);
end;
end;
end;
if obj.nodes then begin
for var i := 0 to obj.nodes.length-1 do begin
var child := HTMLSanitizer.JSONtoDOM(obj.nodes[i]);
if child <> nil then
Result.appendChild(child);
end;
end;
end;