Skip to content
This repository was archived by the owner on Apr 6, 2021. It is now read-only.

Commit b782ea9

Browse files
author
chrisisbeef
committed
Fixed HTMLEntityCodec
1 parent 483577e commit b782ea9

File tree

2 files changed

+172
-29
lines changed

2 files changed

+172
-29
lines changed

src/main/javascript/org/owasp/esapi/Core.js

Lines changed: 168 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,42 @@ if (!Array.prototype.contains) {
5656
};
5757
}
5858

59+
if (!Array.prototype.getLongestKeyLength) {
60+
Array.prototype.getLongestKeyLength = function() {
61+
var len = 0;
62+
for ( var key in this ) {
63+
if ( !key instanceof String ) {
64+
throw new RuntimeException("getLongestKeyMatch only works with Map<String,Object>" );
65+
}
66+
67+
len = Math.max( len, key.length );
68+
}
69+
return len;
70+
};
71+
}
72+
73+
if (!Array.prototype.containsKey) {
74+
Array.prototype.containsKey = function(srch) {
75+
for ( var key in this ) {
76+
if ( key.toLowerCase() == srch.toLowerCase() ) {
77+
return true;
78+
}
79+
}
80+
return false;
81+
};
82+
}
83+
84+
if (!Array.prototype.getCaseInsensitive) {
85+
Array.prototype.getCaseInsensitive = function(key) {
86+
for (var k in this) {
87+
if (k.toLowerCase() == key.toLowerCase()) {
88+
return this[k];
89+
}
90+
}
91+
return null;
92+
};
93+
}
94+
5995
if (!String.prototype.charCodeAt) {
6096
String.prototype.charCodeAt = function( idx ) {
6197
var c = this.charAt(idx);
@@ -67,6 +103,12 @@ if (!String.prototype.charCodeAt) {
67103
};
68104
}
69105

106+
if (!String.prototype.endsWith) {
107+
String.prototype.endsWith = function( test ) {
108+
return this.substr( ( this.length - test.length ), test.length ) == test;
109+
};
110+
}
111+
70112
// Declare some Core Exceptions
71113
if ( !RuntimeException ) {
72114
var RuntimeException = function( sMsg ) {
@@ -271,41 +313,138 @@ org.owasp.esapi.codecs.Codec.getHexForNonAlphanumeric = function(c) {
271313
org.owasp.esapi.codecs.HTMLEntityCodec = function() {
272314
var _super = new org.owasp.esapi.codecs.Codec();
273315

274-
return {
275-
encode: function( aImmune, sInput ) {
276-
var out = '';
277-
for ( var i = 0; i < sInput.length; i ++ ) {
278-
var c = sInput.charCodeAt(i);
279-
if ( characterToEntityMap[c.toString()] ) {
280-
out += characterToEntityMap[c.toString()] + ';';
281-
}
282-
else {
283-
out += String.fromCharCode(c);
316+
var getNumericEntity = function( input ) {
317+
var first = input.peek();
318+
if ( first == null ) {
319+
return null;
320+
}
321+
322+
if ( first == 'x' || first == 'X' ) {
323+
input.next();
324+
return parseHex( input );
325+
}
326+
return parseNumber( input );
327+
};
328+
329+
var parseNumber = function( input ) {
330+
var out = '';
331+
while ( input.hasNext() ) {
332+
var c = input.peek();
333+
if ( c.match( /[0-9]/ ) ) {
334+
out += c;
335+
input.next();
336+
} else if ( c == ';' ) {
337+
input.next();
338+
break;
339+
} else {
340+
break;
341+
}
342+
}
343+
344+
try {
345+
return parseInt( out );
346+
} catch (e) {
347+
return null;
348+
}
349+
};
350+
351+
var parseHex = function( input ) {
352+
var out = '';
353+
while ( input.hasNext() ) {
354+
var c = input.peek();
355+
if ( c.match( /[0-9A-Fa-f]/ ) ) {
356+
out += c;
357+
input.next();
358+
} else if ( c == ';' ) {
359+
input.next();
360+
break;
361+
} else {
362+
break;
363+
}
364+
}
365+
try {
366+
return parseInt( out, 16 );
367+
} catch (e) {
368+
return null;
369+
}
370+
};
371+
372+
var getNamedEntity = function( input ) {
373+
var entity = '';
374+
while (input.hasNext()) {
375+
var c = input.peek();
376+
if ( c.match(/[A-Za-z]/) ) {
377+
entity += c;
378+
input.next();
379+
if ( entityToCharacterMap.containsKey('&'+entity)) {
380+
if ( input.peek(';')) input.next();
381+
break;
284382
}
383+
} else if ( c == ';' ) {
384+
input.next();
385+
} else {
386+
break;
285387
}
286-
return out;
388+
}
389+
390+
return String.fromCharCode(entityToCharacterMap.getCaseInsensitive('&'+entity));
391+
};
392+
393+
return {
394+
encode: _super.encode,
395+
396+
decode: _super.decode,
397+
398+
encodeCharacter: function( aImmune, c ) {
399+
if ( aImmune.contains(c) ) {
400+
return c;
401+
}
402+
403+
var hex = org.owasp.esapi.codecs.Codec.getHexForNonAlphanumeric(c);
404+
if ( hex == null ) {
405+
return c;
406+
}
407+
408+
var cc = c.charCodeAt(0);
409+
if ( ( cc <= 0x1f && c != '\t' && c != '\n' && c != '\r' ) || ( cc >= 0x7f && cc <= 0x9f ) || c == ' ' ) {
410+
return " ";
411+
}
412+
413+
var entityName = characterToEntityMap[cc];
414+
if ( entityName != null ) {
415+
return entityName + ";";
416+
}
417+
418+
return "&#x" + hex + ";";
287419
},
288420

289-
decode: function( sInput ) {
290-
var out = '';
291-
for ( var i = 0; i < sInput.length; i ++ ) {
292-
var c = sInput.charAt(i);
293-
if ( c == '&' ) {
294-
var end = sInput.indexOf( ';', i );
295-
var entity = sInput.substr( i, end-i );
296-
if ( entityToCharacterMap[entity] ) {
297-
out += String.fromCharCode(entityToCharacterMap[entity]);
298-
i = end;
299-
}
300-
else {
301-
out += c;
302-
}
303-
}
304-
else {
305-
out += c;
421+
decodeCharacter: function( oPushbackString ) {
422+
var input = oPushbackString;
423+
input.mark();
424+
var first = input.next();
425+
if ( first == null || first != '&' ) {
426+
input.reset();
427+
return null;
428+
}
429+
430+
var second = input.next();
431+
if ( second == null ) {
432+
input.reset();
433+
return null;
434+
}
435+
436+
if ( second == '#' ) {
437+
var c = getNumericEntity( input );
438+
if ( c != null ) { return c; }
439+
} else if ( second.match(/[A-Za-z]/) ) {
440+
input.pushback(second);
441+
var c = getNamedEntity( input );
442+
if ( c != null ) {
443+
return c;
306444
}
307445
}
308-
return out;
446+
input.reset();
447+
return null;
309448
}
310449
};
311450
};

src/test/javascript/org/owasp/esapi/TestCore.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ function testESAPIInstance() {
1919
assertNotNull($ESAPI);
2020
}
2121

22+
function testStringEndswith() {
23+
assertTrue( "Test".endsWith("t"));
24+
}
25+
2226
function testEncoderEncodeForBase64() {
2327
var testString = 'This is a test string';
2428
assertEquals($ESAPI.encoder().decodeFromBase64($ESAPI.encoder().encodeForBase64(testString)), testString);

0 commit comments

Comments
 (0)