This repository has been archived by the owner on May 29, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 6.7k
fix(typeahead): Typeahead uses ngSanitize when present #3463
Closed
+86
−34
Closed
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
describe('Security concerns', function() { | ||
var highlightFilter, $sanitize, logSpy; | ||
|
||
beforeEach(module('ui.bootstrap.typeahead', 'ngSanitize')); | ||
|
||
beforeEach(inject(function (typeaheadHighlightFilter, _$sanitize_, $log) { | ||
highlightFilter = typeaheadHighlightFilter; | ||
$sanitize = _$sanitize_; | ||
logSpy = spyOn($log, 'warn'); | ||
})); | ||
|
||
it('should not call the $log service when ngSanitize is present', function() { | ||
highlightFilter('before <script src="">match</script> after', 'match'); | ||
expect(logSpy).not.toHaveBeenCalled(); | ||
}); | ||
|
||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,38 +1,52 @@ | ||
describe('typeaheadHighlight', function() { | ||
var highlightFilter; | ||
describe('typeaheadHighlight', function () { | ||
|
||
var highlightFilter, $log, $sce, logSpy; | ||
|
||
beforeEach(module('ui.bootstrap.typeahead')); | ||
beforeEach(inject(function(typeaheadHighlightFilter) { | ||
|
||
beforeEach(inject(function(_$log_, _$sce_) { | ||
$log = _$log_; | ||
$sce = _$sce_; | ||
logSpy = spyOn($log, 'warn'); | ||
})); | ||
|
||
beforeEach(inject(function (typeaheadHighlightFilter) { | ||
highlightFilter = typeaheadHighlightFilter; | ||
})); | ||
|
||
it('should higlight a match', function() { | ||
expect(highlightFilter('before match after', 'match')).toEqual('before <strong>match</strong> after'); | ||
it('should higlight a match', function () { | ||
expect($sce.getTrustedHtml(highlightFilter('before match after', 'match'))).toEqual('before <strong>match</strong> after'); | ||
}); | ||
|
||
it('should higlight a match with mixed case', function() { | ||
expect(highlightFilter('before MaTch after', 'match')).toEqual('before <strong>MaTch</strong> after'); | ||
it('should higlight a match with mixed case', function () { | ||
expect($sce.getTrustedHtml(highlightFilter('before MaTch after', 'match'))).toEqual('before <strong>MaTch</strong> after'); | ||
}); | ||
|
||
it('should higlight all matches', function() { | ||
expect(highlightFilter('before MaTch after match', 'match')).toEqual('before <strong>MaTch</strong> after <strong>match</strong>'); | ||
it('should higlight all matches', function () { | ||
expect($sce.getTrustedHtml(highlightFilter('before MaTch after match', 'match'))).toEqual('before <strong>MaTch</strong> after <strong>match</strong>'); | ||
}); | ||
|
||
it('should do nothing if no match', function() { | ||
expect(highlightFilter('before match after', 'nomatch')).toEqual('before match after'); | ||
it('should do nothing if no match', function () { | ||
expect($sce.getTrustedHtml(highlightFilter('before match after', 'nomatch'))).toEqual('before match after'); | ||
}); | ||
|
||
it('should do nothing if no or empty query', function() { | ||
expect(highlightFilter('before match after', '')).toEqual('before match after'); | ||
expect(highlightFilter('before match after', null)).toEqual('before match after'); | ||
expect(highlightFilter('before match after', undefined)).toEqual('before match after'); | ||
it('should do nothing if no or empty query', function () { | ||
expect($sce.getTrustedHtml(highlightFilter('before match after', ''))).toEqual('before match after'); | ||
expect($sce.getTrustedHtml(highlightFilter('before match after', null))).toEqual('before match after'); | ||
expect($sce.getTrustedHtml(highlightFilter('before match after', undefined))).toEqual('before match after'); | ||
}); | ||
|
||
it('issue 316 - should work correctly for regexp reserved words', function() { | ||
expect(highlightFilter('before (match after', '(match')).toEqual('before <strong>(match</strong> after'); | ||
it('issue 316 - should work correctly for regexp reserved words', function () { | ||
expect($sce.getTrustedHtml(highlightFilter('before (match after', '(match'))).toEqual('before <strong>(match</strong> after'); | ||
}); | ||
|
||
it('issue 1777 - should work correctly with numeric values', function() { | ||
expect(highlightFilter(123, '2')).toEqual('1<strong>2</strong>3'); | ||
it('issue 1777 - should work correctly with numeric values', function () { | ||
expect($sce.getTrustedHtml(highlightFilter(123, '2'))).toEqual('1<strong>2</strong>3'); | ||
}); | ||
|
||
it('should show a warning when this component is being used unsafely', function() { | ||
highlightFilter('<i>before</i> match after', 'match'); | ||
expect(logSpy).toHaveBeenCalled(); | ||
}); | ||
|
||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position', 'ui.bootstrap.bindHtml']) | ||
angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position']) | ||
|
||
/** | ||
* A helper service that can parse typeahead's syntax (string provided by users) | ||
|
@@ -481,12 +481,29 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position', 'ui.bootstrap | |
}; | ||
}]) | ||
|
||
.filter('typeaheadHighlight', function() { | ||
.filter('typeaheadHighlight', ['$sce', '$injector', '$log', function($sce, $injector, $log) { | ||
|
||
var isSanitizePresent; | ||
isSanitizePresent = $injector.has('$sanitize'); | ||
|
||
function escapeRegexp(queryToEscape) { | ||
// Regex: capture the whole query string and replace it with the string that will be used to match | ||
// the results, for example if the capture is "a" the result will be \a | ||
return queryToEscape.replace(/([.?*+^$[\]\\(){}|-])/g, '\\$1'); | ||
} | ||
|
||
function containsHtml(matchItem) { | ||
return /<.*>/g.test(matchItem); | ||
} | ||
|
||
return function(matchItem, query) { | ||
return query ? ('' + matchItem).replace(new RegExp(escapeRegexp(query), 'gi'), '<strong>$&</strong>') : matchItem; | ||
if(!isSanitizePresent && containsHtml(matchItem)) { | ||
$log.warn('Unsafe use of typeahead please use ngSanitize'); // Warn the user about the danger | ||
} | ||
matchItem = query? ('' + matchItem).replace(new RegExp(escapeRegexp(query), 'gi'), '<strong>$&</strong>') : matchItem; // Replaces the capture string with a the same string inside of a "strong" tag | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The output from the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry, on further thought, I realized your initial logic to check for html tags should be used here like: if (containsHtml(matchItem) && !$sanitize) {
$log.warn('Unsafe use of typeahead please use ngSanitize');
} This way, the user will only be warned when using typeahead with labels that contain HTML. |
||
if(!isSanitizePresent) { | ||
matchItem = $sce.trustAsHtml(matchItem); // If $sanitize is not present we pack the string in a $sce object for the ng-bind-html directive | ||
} | ||
return matchItem; | ||
}; | ||
}); | ||
}]); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
<a href tabindex="-1" bind-html-unsafe="match.label | typeaheadHighlight:query"></a> | ||
<a href tabindex="-1" ng-bind-html="match.label | typeaheadHighlight:query"></a> |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you missed adding ngSanitize into the
demo/app.js
. Is this change needed for the demo to work? If not, we can just leave out this change for now and add it later when needed.