Dynamic Syntax Highlighting with AngularJS and Highlight.js

All we need is an easy explanation of the problem, so here it is.

I am building a site that illustrates common application vulnerabilities such as SQL Injection. I am using AngularJS and highlight.js to create interactive examples.

How can I make both AngularJS and highlight.js update my code snippets?

Example

This Fiddle demonstrates how entering ' OR 1=1 -- in the Email field could change the intended behavior of the query if the user’s input is not validated or sanitized.

SELECT * FROM dbo.Users WHERE Email='{{email}}' AND Password='{{password}}'  

When a user enters an email address and password, Angular updates the query. However, syntax highlighting does not update.

SELECT * FROM dbo.Users WHERE Email='[email protected]' AND Password=''

I tried re-initializing hljs, but when I do angular stops updating the query.

hljs.initHighlighting.called = false;
hljs.initHighlighting();

Application

<script>
    var app = angular.module("app", ['hljs']);
    app.controller("controller", function($scope) {
        $scope.email = "[email protected]";
        $scope.password = "";
    })
</script>
<div ng-app="app" ng-controller="controller">
    <div>
        <div class="row">
            <div class="col-sm-4">Email
                <input type="text" class="form-control" ng-model="email">
            </div>
            <div class="col-sm-4">Password
                <input type="text" class="form-control" ng-model="password">
            </div>
        </div>
        <br>
        <div hljs include="'compile-me'" compile="true" language="sql"></div>
    </div>
    <script type="text/ng-template" id="compile-me">
        SELECT * FROM dbo.Users WHERE Email = '{{email}}'
        AND Password = '{{password}}'
    </script>
</div>

How to solve :

I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.

Method 1

In the jsfiddle you have provided you’re using angular-highlightjs which in your case basically:

  1. Fetches the template you have provided with include directive applies
  2. Invokes highlightjs library API on the template which produces HTML markup with highlighted elements having correct style for particular language
  3. The highlighted HTML markup is then passed over to angularjs $compile

Afterwards no highglighting takes place – in particular even when interpolated content changes.

One way to solve it is to use source directive from angular-highlightjs which is observed but I think it’s simpler to build a custom directive.

The trick here is to manually interpolate and highlight content. I’ve updated your fiddle with a simplistic highlight directive that presents the idea:

app.directive('highlight', function($interpolate, $window){
    return {
    restrict: 'EA',
    scope: true,
    compile: function (tElem, tAttrs) {
      var interpolateFn = $interpolate(tElem.html(), true);
      tElem.html(''); // stop automatic intepolation

      return function(scope, elem, attrs){
        scope.$watch(interpolateFn, function (value) {
          elem.html(hljs.highlight('sql',value).value);
        });
      }
    }
  };
});

Method 2

A simpler way I just found is to use a filter:

app.filter('highlight', function($sce) {
  return function(input, lang) {
    if (lang && input) return hljs.highlight(lang, input).value;
    return input;
  }
}).filter('unsafe', function($sce) { return $sce.trustAsHtml; })

Then you can say:

<pre><code ng-bind-html="someScopeVariable | highlight | unsafe"></code></pre>

The $sce needs to be injected into your app, and tells Angular to display the HTML raw – that you trust it.

Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply