Notes from AngularJS Playbook course
Code is as-is from the tutorial. One could always refactor into the latest and greatest, but there is too much good material out there by excellent authors, like Scott Allen, the author of this Pluralsight course.
These notes are findings I find interesting or enlightening at this moment of my coding career. I hope others may find them useful as well.
1.1 The Revealing Module Pattern and an Auth Token Service
1.3 Protecting from XSS and using Sanitization and $sce
This is a nice way to encapsulate logic in a service. Just return an object with the methods as keys. No need to expose internal business logic.
Example: localStorage.service.js
(function(module) {
var localStorage = function($window) {
var store = $window.localStorage;
var add = function (key, value) {
value = angular.toJson(value);
store.setItem(key, value);
};
var get = function(key) {
var value = store.getItem(key);
if (value) {
value = angular.fromJson(value);
}
return value;
};
var remove = function(key) {
store.removeItem(key);
};
// here just return the methods
return {
add: add,
get: get,
remove: remove
};
};
// and put class-like object above into factory def
module.factory("localStorage", localStorage);
}(angular.module("common")));
And a form encoder service
example: formEncoder.service.js
(function(module) {
var formEncode = function() {
return function(data) {
var pairs = [];
for (var name in data) {
pairs.push(encodeURIComponent(name) + '=' + encodeURIComponent(data[name]));
}
return pairs.join('&').replace(/%20/g, '+');
};
};
module.factory("formEncode", formEncode);
}(angular.module("common")));
and this service can be used in ANOTHER service
Example: oauth.service.js
(function (module) {
var oauth = function ($http, formEncode, currentUser) {
var login = function (username, password) {
var config = {
headers: {
"Content-Type": "application/x-www-form-urlencoded"
}
}
// call that above formEncode serfice
var data = formEncode({
username: username,
password: password,
grant_type: "password"
});
// object returns a promise
return $http.post("/login", data, config)
.then(function (response) {
currentUser.setProfile(username, response.data.access_token);
return username;
});
};
// and returns above class-like modularized object
return {
login: login
};
};
module.factory("oauth", oauth);
}(angular.module("common")));
Moving along, if the above code gets a successful response with a token, we can store that. Example: currentUser.js
(function(module) {
var currentUser = function(localStorage){
var USERKEY = "utoken";
var setProfile = function (username, token) {
profile.username = username;
profile.token = token;
localStorage.add(USERKEY, profile);
};
var initialize = function () {
var user = {
username: "",
token: "",
get loggedIn() { // notice get keyword
return this.token;
}
};
var localUser = localStorage.get(USERKEY);
if (localUser) {
user.username = localUser.username;
user.token = localUser.token;
}
return user;
};
var profile = initialize();
return {
setProfile: setProfile,
profile: profile
};
};
module.factory("currentUser", currentUser);
}(angular.module("common")));
Interceptors invoked for:
- request
- requestError
- response
- responseError
General Use:
In this example, an interceptor is used to add a token to an HTTP header.
Example: addToken.js
(function (module) {
var addToken = function (currentUser, $q) {
var request = function (config) {
if (currentUser.profile.loggedIn) {
config.headers.Authorization = "Bearer " + currentUser.profile.token;
}
return $q.when(config); // $q.when() always resolves, wraps in a promise
};
return {
request: request
}
};
module.factory("addToken", addToken);
// use this factory inside the config, push to interceptors array
module.config(function ($httpProvider) {
$httpProvider.interceptors.push("addToken");
});
}(angular.module("common")));
HTML tags are not trusted by default to protect against XSS Cross Site Script attacks. Note - not 100% secure - apps still can be exploited in other ways.
Using Interpolation {{ }}:
vm.test = "French <em>Test</em";
<p>{{ vm.test }}</p>
Output:
French <em>Test</em>
Using ng-bind:
<p ng-bind="vm.test"></p>
Output is same:
French <em>Test</em>
Using ng-bind-html:
<p ng-bind="vm.test">{{ test }}</p>
Output is blank:
- Console error shows trying to use ng-bind-html in an unsafe context.
-
Good to use with trusted users.
-
Not for all users, since susceptible to XSS.
-
Include angular-sanitize script:
<script src="[path to]/angular-sanitize.js"></script>
angular.module('app',['ngSanitize'])
Result:
vm.test = "French <em>Test</em";
<p>{{ vm.test }}</p>
Output: French Test
- Sanitize will also remove any event handlers or script tags
- Can use a function getter for this
<p ng-bind-html="vm.getTrustedParagraph()"></p>
vm.getTrustedParagraph = function() {
return $sce.trustAsHtml(vm.test);
}