A Journey With Trusted HTML in AngularJS

Wednesday, September 10, 2014 by K. Scott Allen
2 comments

AngularJSAngularJS  provides protection against cross-site scripting attacks by default.  Let’s look at some examples.

HTML Entity Encoding With ngBind

Consider the following controller which maintains a collection of strings with HTML inside. Perhaps the strings arrived in the controller as the result of an HTTP call, or perhaps the controller built the strings dynamically. In either case, the controller wants the links to display as clickable navigation links in a browser.

app.controller("mainController", function() {
    var main = this;

    main.links = [
        "<a href='http://google.com'>Google</a>",
        "<a href='http://odetocode.com'>OdeToCode</a>",
        "<a href='http://twitter.com'>Twitter</a>",
    ];
});

In the view, we’ll use a {{bind expression}} to display the links.

<section ng-controller="mainController as main">

    <nav>
        <ul>
            <li ng-repeat="link in main.links">{{link}}</li>
        </ul>
    </nav>

</section>

HTML Encoded with ngBind The links will appear as inert text (see the figure to the right), because interpolation with ngBind will produce encoded text.

Technically, this isn’t because of any special code inside of the ngBind directive, but because ngBind uses jqLite’s .text method, which ultimately sets the textContent property of the associated element.

Render HTML with ngBindHtml

Instead of using ngBind, the view can use ngBindHtml to render the links as real, clickable anchor tags.

<ul>
    <li ng-repeat="link in main.links"
        ng-bind-html="link">
    </li>
</ul>

However, making only this change in the view will result in an error.

Error: [$sce:unsafe] Attempting to use an unsafe value in a safe context.

Angular will only render “safe” HTML into the DOM. If you are looking for a quick fix to this error, just read the “Sanitized HTML” section below.

From a developer’s perspective, there are two general categories of “safe” HTML in Angular.

  1. Explicitly trusted HTML is safe
  2. Sanitized HTML is safe

Let’s look at #2 first.

Sanitizing HTML

Synonyms for sanitize include “sterilize”, “disinfect”, “clean”, “cleanse”, and “purify”. All of these synonyms are capable words for describing the process of making HTML “safe” for display. Being “safe” means the HTML won’t carry script code into the DOM, because script code is dangerous if the script comes from the wrong place.

AngularJS includes a $sanitize service that will parse an HTML string into tokens and only allow safe and white-listed markup and attributes to survive, thus sterilizing a string so the markup contains no scripting expressions or dangerous attributes.

Angular will consider HTML processed by $sanitize as trusted.

The ngBindHtml directive will use the $sanitize service implicitly, however, the $sanitize service is not part of the core ng module, so an additional script needs to be added into the page.

<script src="angular.js"></script>
<script src="angular-sanitize.js"></script>
<script src="app.js"></script>

Then when registering the application module, the code must list ngSantize as a dependency.

var app = angular.module("app", ["ngSanitize"]);

Render sanitized HTML with ngBindHtml With these changes in place, the app will now render proper links.

So what was sanitized?

Watching $sanitize

One way to see how and when $sanitize works is to decorate the $sanitize service (which is a function object).

var app = angular.module("app", ["ngSanitize"]);

app.config(function($provide){
    $provide.decorator("$sanitize", function($delegate, $log){
        return function(text, target){

            var result = $delegate(text, target);
            $log.info("$sanitize input: " + text);
            $log.info("$sanitize output: " + result);

            return result;
        };
    });
});

Now let’s use the following link collection inside the controller. Notice each link has some attribute present.

app.controller("mainController", function() {

    var main = this;
    main.links = [
        "<a onmouseover='...' href='http://google.com'>Google</a>",
        "<a class='...' href='http://odetocode.com'>OdeToCode</a>",
        "<a ng-click='...' href='http://twitter.com'>Twitter</a>"
    ];
});

With the decorator, we can see exactly what goes into $sanitize, and what comes out. The mouseover attributes disappear, as does the ng-click directive.

$sanitize input: <a onmouseover='...' href='http://google.com'>Google</a> 
$sanitize output: <a href="http://google.com">Google</a> 

$sanitize input: <a class='...' href='http://odetocode.com'>OdeToCode</a>
$sanitize output: <a class="..." href="http://odetocode.com">OdeToCode</a>

$sanitize input: <a ng-click='...' href='http://twitter.com'>Twitter</a>
$sanitize output: <a href="http://twitter.com">Twitter</a> 

While $sanitize can provide trusted HTML for Angular to render, it does so by modifying the HTML. If we really want to render HTML without encoding and without sanitization, we have to turn to what I referred to as category #1 earlier – explicitly marking the HTML as “trusted”.

Explicitly Trusting HTML With $sce

When you want Angular to render model data as HTML with no questions asked, the $sce service is what you’ll need. $sce is the Strict Contextual Escaping service – a fancy name for a service that can wrap an HTML string with an object that tells the rest of Angular the HTML is trusted to render anywhere.

In the following version of the controller, the code asks for the $sce service and uses the service to transform the array of links into an array of trusted HTML objects using $sce.trustAsHtml.

app.controller("mainController", function($sce) {

    var main = this;
    main.links = [
        "<a onmouseover='alert(\"careful!\")' href='http://google.com'>Google</a>",
        "<a href='http://odetocode.com'>OdeToCode</a>",
        "<a href='http://twitter.com'>Twitter</a>"
    ];

    for (var i = 0; i < main.links.length; i++) {
        main.links[i] = $sce.trustAsHtml(main.links[i]);
    }
});

The only difference between this version of the controller code and the previous version is the for loop to mark the strings as trusted. When binding to each trusted link using ngBindHtml, the HTML will no longer go through the $sanitize service. This means the first link will now enter the DOM with an onmouseover attribute and carry along executable JavaScript code. Be careful!

Bonus: Compiling Trusted HTML

Instead of using onmouseover or onclick attributes, let’s say we have some strings on our controller that want to follow the “Angular Way” and use ngClick or ngMouseover.

app.controller("mainController", function($sce, $log) {

    var main = this;
    main.links = [
        "<a ng-click='main.go(\"google\")' href=''>Google</a>",
        "<a ng-click='main.go(\"otc\")' href=''>OdeToCode</a>",
        "<a ng-click='main.go(\"twitter\")' href=''>Twitter</a>"
    ];

    for (var i = 0; i < main.links.length; i++) {
        main.links[i] = $sce.trustAsHtml(main.links[i]);
    }

    main.go = function(name){
       $log.info("Goto: " + name);
    };
});

If these links pass through the $sanitize service, the sanitizer will remove ng-click and other attribute directives. Fortunately, the controller marks the HTML as trusted so they will render with ngClick. However, clicking will not work since Angular doesn’t compile the markup after it enters the DOM with ngBindHtml.

The solution is to use a custom directive in combination with $sce and trusted HTML.

app.directive("compileHtml", function($parse, $sce, $compile) {
    return {
        restrict: "A",
        link: function (scope, element, attributes) {

            var expression = $sce.parseAsHtml(attributes.compileHtml);

            var getResult = function () {
                return expression(scope);
            };

            scope.$watch(getResult, function (newValue) {
                var linker = $compile(newValue);
                element.append(linker(scope));
            });
        }
    }
});

Now the view looks like:

<ul>
    <li ng-repeat="link in main.links"
        compile-html="link">
    </li>
</ul>

Features Of ES6 Part 5: The Spread

Tuesday, September 2, 2014 by K. Scott Allen
2 comments

The spread operator shares the same syntax we saw with rest parameters, a series of three dots (...). However, a rest parameter will collect individual parameters into an array when you use the dots in a function parameter definition, while the spread operator expands an array into individual parameters when using the dots in a function call.

let doWork = function(x, y, z) {
    return x + y + z;
}

var result = doWork(...[1, 2, 3]);
expect(result).toBe(6);

In the above code, the spread operator will “spread” the array of three values across the parameters x, y, and z.

The spread operator can also expand an array to create individual elements in an array literal.

var a = [4, 5, 6]; 
var b = [1, 2, 3, ...a, 7, 8, 9]; 

expect(b).toEqual([1,2,3,4,5,6,7,8,9]);

Although the examples here are all using the spread operator with an array, the spread operator also works with any iterable object. We’ll look at iterable objects in a future post.

The Impact of the Spread

Before rest parameters and the spread operator came along, Function.apply and the implicit arguments variable were widely used to accept an unknown number of arguments to a function and pass the arguments along to another function, like in the example below.

var doWork = function(x, y, z){
    return x + y + z;
}

var doSomething = function(){
    return doWork.apply(null, arguments);
}

var result = doSomething(...[1,2,3,4,5]);
expect(result).toBe(6);

The implementation of doSomething is cleaner and more obvious when using a rest parameter and the spread.

var doWork = function(x, y, z){
    return x + y + z;
}

var doSomething = function(...args){
    return doWork(...args);
}

var result = doSomething(...[1,2,3,4,5]);
expect(result).toBe(6);

Notice that when using the spread (or apply), you can have more values in the array than the destination function requires. The spread will start from the beginning of the array to populate parameters, so in the above example, doWork will see the first three values in the array.

Want more? Watch JavaScript Fundamentals for ES6 on Pluralsight!

Karma Is Not Just For AngularJS

Tuesday, August 19, 2014 by K. Scott Allen
4 comments

The AngularJS team created Karma, but Karma isn’t tied to AngularJS. As a test runner, I can use Karma to run tests against any JavaScript code using a variety of testing frameworks in a variety of browsers. All I need is Node.js.

Pretend I am writing code to represent a point in two dimensional space. I might create a file point.js.

var Point = function(x,y) {
    this.x = x;
    this.y = y;
}

I’ll test the code using specifications in a file named pointSpecs.js.

describe("a point", function() {
    it("initializes with x and y", function() {
        var p1 = new Point(3,5);
        
        expect(p1.x).toBe(3);
        expect(p1.y).toBe(5);
    });
});

What Karma can do is:

- Provide web browsers with all of the HTML and JavaScript required to run the tests I’ve written.

- Automate web browsers to execute all the tests

- Tell me if the tests are passing or failing

- Monitor the file system to re-execute tests whenever a file changes.

Setup

The first step is using npm to install the Karma command line interface globally, so I can run Karma from anywhere.

npm install karma-cli –g

Then I can install Karma locally in the root of my project where the Point code resides.

npm install karma --save-dev

Karma requires a configuration file so it knows what browsers to automate, and which files I’ve authored that I need Karma to load into the browser. The easiest way to create a basic configuration file is to run karma init from the command line. The init command will walk you through a series of questions to create the karma.conf.js file. Here is a sample session.

>karma init 

Which testing framework do you want to use ?
Press tab to list possible options. Enter to move to the next question.
> jasmine 

Do you want to use Require.js ?
This will add Require.js plugin.
Press tab to list possible options. Enter to move to the next question.
> no 

Do you want to capture any browsers automatically ?
Press tab to list possible options. Enter empty string to move to the next question.
> PhantomJS
> Chrome
> 

What is the location of your source and test files ?
You can use glob patterns, eg. "js/*.js" or "test/**/*Spec.js".
Enter empty string to move to the next question.
> js/**/*.js
> specs/**/*.js
> 

Should any of the files included by the previous patterns be excluded ?
You can use glob patterns, eg. "**/*.swp".
Enter empty string to move to the next question.
> 

Do you want Karma to watch all the files and run the tests on change ?
Press tab to list possible options.
> yes 

Config file generated at "C:\temp\testjs\karma.conf.js".

I can open the config file to tweak settings and maintain the configuration in the future. The code is simple.

module.exports = function(config) {
  config.set({
    basePath: '',
    frameworks: ['jasmine'],
    files: [
      'js/**/*.js',
      'specs/**/*.js'
    ],
    exclude: [
    ],
    preprocessors: {
    },
    reporters: ['progress'],
    port: 9876,
    colors: true,
    logLevel: config.LOG_INFO,
    autoWatch: true,
    browsers: ['PhantomJS', 'Chrome'],
    singleRun: false
  });
};

Note that when I enter the location of the source and test files, I want to enter the location of the source files first. It’s helpful if you can organize source and test files into a directory structure so you can use globbing (**) patterns, but sometimes you need to explicitly name individual files to control the order of loading.

At this point I can start Karma, and the tests will execute in two browsers (Chrome, which I can see, and PhantomJS, which is headless). I’d probably tweak the config file to only use Phantom in the future.

Karma in action!

Now, Karma will continuously run tests in the background while I work.

Easy!

Features of ES6 Part 4: Rest Parameters

Monday, August 18, 2014 by K. Scott Allen
0 comments

A rest parameter allows a function to work with an unknown or variable number of arguments. A function’s rest parameter always appears at the end of the function’s argument list and uses a triple dot prefix (...), as shown below.

let doWork = function(name, ...numbers){
    let result = 0;
    
    numbers.forEach(function(n){
        result += n;
    });

    return result;
};

A caller invoking doWork can pass zero or more parameters at the rest parameter position. You can say the numbers argument will take “the rest” of the parameters a caller passes, and numbers will hold the parameter values in an array. In the following example, numbers will reference an array with the values 1, 2, 3.

let result = doWork("Scott", 1, 2, 3);
expect(result).toBe(6);

In the case where a caller passes no parameters in the rest parameter position, the rest parameter will be an empty array.

let doWork = function(...numbers){
    return numbers;
};

let result = doWork();
expect(result.length).toBe(0);

The Impact of Rest Parameters

Before ES6, we could allow callers to pass a variable number of arguments to a function by using the implicit arguments variable inside of the function. The arguments variable contains all the parameters to a function in an array-like object, but arguments is not an array, which creates confusion. It is also difficult to spot if a function is using arguments without reading through the code or documentation for the function.

ES6 rest parameters will avoid the confusion by always giving us a true array, and by using a dedicated syntax that makes rest parameters easy to spot when reading the function signature.

Want more? Watch JavaScript Fundamentals for ES6 on Pluralsight!

C# 6.0 Features Part II : Primary Constructors

Thursday, August 14, 2014 by K. Scott Allen
5 comments

Primary constructors are a feature you’ll find in a few programming languages, including F#, Scala, and Kotlin. A primary constructor allows us to define a constructor for a type and capture the constructor parameters to use in initialization expressions throughout the rest of the type definition.  Here’s one simple example:

public struct Money(string currency, decimal amount) 
{
    public string Currency { get; } = currency;
    public decimal Amount { get; } = amount;
}

Notice how the primary constructor arguments appear inside parentheses just after the type name. The code can then use the arguments in field initializers and property initializers. Common questions about this new syntax revolve around parameter validation, and how primary constructors can work with other explicit constructors. Here’s another example.

public class AddUserCommand(User newUser, User creator) : Command
{
    public AddUserCommand(User newUser)
        : this(newUser, creator: newUser)
    {
    }

    public User NewUser { get; protected set; } = newUser;
    public User Creator { get; protected set; } = Verify.NotNull("creator", creator);
    Guid _creatorId = creator.Id;
}

Once you have a primary constructor, all other constructors must ultimately call into the primary ctor using this(), which makes sense since we always want the primary constructor arguments to be available for initialization (although a struct will still have a non-replaceable default constructor that will initialize all members to default values).

Validation is a bit trickier, but simple validation checks are possible in the initialization expressions.

I really like the primary constructor syntax for components that are managed by an IoC container. Typically these components have a single constructor to accept dependencies, and they need to store the dependencies in a field or property. Validation of the dependencies is not a concern as most containers will (or can) raise an error if a dependency cannot be found.

public class UserController(IUserStorage storage) : Controller
{
    public ActionResult Index()
    {
         // ...
    }

    IUserStorage _storage = storage;
}

The primary constructor syntax means there is a little less code to write for these types of components.

Features of ES6 Part 3: Default Parameter Values

Wednesday, August 13, 2014 by K. Scott Allen
2 comments

If a JavaScript function takes two parameters, we have always had the ability to invoke the function and pass two parameters, or one parameter, or no parameters, or three parameters if we wanted. In cases where we do not pass enough parameters, the author of a function might want to specify a default value instead of working with undefined.

Before ES6, developers applied default values to simple parameters using || expressions inside the function.

let doWork = function(name) {
    name = name || "Scott";
    return name;
};

With ES6, default parameters are explicit and appear in the argument list for a function.

let doWork = function(name = "Scott") {
    return name;
};

expect(doWork()).toBe("Scott");

A function can even calculate a default using something more than just a literal expression.

let doWork = function(x = Math.random()) { return x; }

The Significance of default parameters

The default parameter syntax is a good example of how ES6 is providing a clean syntax for a common requirement. No longer will we have to scan through a function implementation or documentation to discover the defaults.

Of course, not all parameters are simple values. A common programming technique for operations involving complex configurations, like an HTTP call, is to accept a single object argument and use some sort of extend API to merge the incoming configuration with configuration defaults (jQuery.extend or angular.extend, as two examples). Default parameters are useful in this scenario, too, but we’ll have to learn about object destructuring in an upcoming post, first.

Want more? Watch JavaScript Fundamentals for ES6 on Pluralsight!

Thoughts on Angular's Controller As Syntax

Monday, August 11, 2014 by K. Scott Allen
10 comments

I’ve been a bit late to the Angular controller as syntax. I was skeptical of the feature at first, and with an Angular project already in flight, I felt it wasn’t the type of change to make with a significant amount of code already committed.

The controller as syntax allows me to alias a controller in markup.

<div ng-controller="MainController as main">
    {{ main.title }}
</div>

Then instead of injecting a $scope into the controller, model data and behavior is added to the controller instance itself.

app.controller("MainController", function(){
    this.title = “Hello!”;
});

Behind the scenes the controller as syntax adds the controller alias (main in the above example) to a scope object, because Angular still evaluates all binding expressions against a scope object.

Here’s what I think about controller as now.

The Good

- Using the controller alias in a view is a push into the pit of success. View code is more explicit and easier to maintain. Even when using $scope in a controller, I’ve come to view any reliance on prototypal inheritance in the scope chain with suspicion, as the inheritance is brittle, subtle, and often complicates both controller and test code. With a controller alias there is no reliance on scope inheritance hierarchies.

- Not having to inject a $scope makes test code slightly easier.

- Having no access to the $scope API inside a controller is a good thing. I’ve come to view any use of $scope.$watch, $scope.$emit, $scope.$on, and $scope.$* in general with suspicion, at least when inside the controller code for a view. Nearly all the functionality available through the $scope API is better used inside of directives or services that provide a better abstraction.

- Thinking of the controller as a true constructor function instead of a function that adds stuff to $scope is healthier. You can take advantage of the constructor function prototype property to organize code, and this will work well with ES6 class definitions (which presumably will work well with ng 2.0). 

The Bad

- Writing directive controllers is different than writing view controllers. With directive controllers the instance members are often used as an API for intra-controller coordination, and this API should be separate from the model for the view.

- Somewhat related to the above, I’m still not convinced that tangling the controller and view model together is a good idea. I think there is some value in having a dedicated factory for view models.

Summary

The good appears to outweigh the bad, so I’ll switch over to using controller as syntax moving forward. I don’t think controller as is a panacea for complicated$scope code, but it does push people in a better direction.

I also think controller as  highlights the need for Angular 2.0 to make some huge, breaking changes. Once of Angular’s greatest strengths, for me, is that the framework provides enough flexibility to build a variety of apps both large and small. Routing is optional, for example, and most programming can be done with plain old JavaScript objects. However, the surface area of the framework is dangerously close to being a Mirkwood forest of programming techniques. A streamlined API with stronger opinions about how to tie components together would make the framework easier to use.

by K. Scott Allen K.Scott Allen
My Pluralsight Courses
The Podcast!