I intend to allow users to input iframes, custom inlines styles and maybe other things. But I would like to remove anything JS.
By using $sanitize I seem to remove too much.
If you only want to strip out script tags you should do something like this:
angular.module('app', ['ngSanitize'])
.directive('testDir', function() {
return {
restrict: 'A',
controller: function($scope, $sce) {
$scope.sanitizeIt = function() {
var replacer = /<script>.*(<\/?script>?)?/gi;
var stripped = $scope.html.replace(replacer, '');
$scope.sanitizedHtml = $sce.trustAsHtml(stripped);
};
$scope.$watch('html', $scope.sanitizeIt);
}
};
});
The regular expression will wipe out all script tags and $sce tells the application that you can trust the string that is stripped as HTML.
In your application you can then write something like this:
<body ng-app="app">
<div test-dir>
<textarea ng-model="html"></textarea>
<div ng-bind-html="sanitizedHtml"></div>
</div>
</body>
When you persist to the database, make sure you save the sanitized HTML string instead of the html one.
Here's more documentation on $sce:
https://docs.angularjs.org/api/ng/service/$sce
It's basically what $sanitize uses behind the scenes. NOTE: I have not tested this regular expression in browsers aside from Chrome, so you might have to do some of your own tweaking to get it to work to suit your needs. However, the idea is the same.
<script> tags and therefore JavaScript may get executed in onclick, onmouseover, onmouseout etc events. Therefore this is not a save approach at all if any JavaScript execution should be prevented.