Skip to content

Commit e5349d2

Browse files
feat(chapter-6): Initial set of samples
1 parent ee99b3d commit e5349d2

25 files changed

+902
-0
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"name": "https-server",
3+
"description": "",
4+
"version": "0.0.1",
5+
"private": true,
6+
"dependencies": {
7+
"express": "~3.0"
8+
},
9+
"devDependencies": { }
10+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
var fs = require('fs');
2+
var http = require('http');
3+
var https = require('https');
4+
var privateKey = fs.readFileSync('cert/privatekey.pem').toString();
5+
var certificate = fs.readFileSync('cert/certificate.pem').toString();
6+
var credentials = {key: privateKey, cert: certificate};
7+
8+
var express = require('express');
9+
10+
var app = express();
11+
var secureServer = https.createServer(credentials, app);
12+
var server = http.createServer(app);
13+
14+
// ... Add your routes and middleware here
15+
16+
// Start up the server on the port specified in the config
17+
server.listen(5678);
18+
console.log('Angular App Server - listening on port: 5678');
19+
secureServer.listen(95678);
20+
console.log('Angular App Server - listening on secure port: 95678');

1820EN_06_Code/02_ngSanitize/app.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
angular.module('expressionsEscaping', ['ngSanitize'])
2+
.controller('ExpressionsEscapingCtrl', function ($scope, $sanitize) {
3+
$scope.msg = 'Hello, <b>World</b>!';
4+
$scope.safeMsg = $sanitize($scope.msg);
5+
});
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<!doctype html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8">
5+
<script src="http://code.angularjs.org/1.0.2/angular.js"></script>
6+
<script src="http://code.angularjs.org/1.0.2/angular-sanitize.js"></script>
7+
<script src="app.js"></script>
8+
</head>
9+
<body ng-app="expressionsEscaping" ng-controller="ExpressionsEscapingCtrl">
10+
<p ng-bind="msg"></p>
11+
<p ng-bind-html-unsafe="msg"></p>
12+
<p ng-bind-html="msg"></p>
13+
<p ng-bind-html-unsafe="safeMsg"></p>
14+
</body>
15+
</html>
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"name": "https-server",
3+
"description": "",
4+
"version": "0.0.1",
5+
"private": true,
6+
"dependencies": {
7+
"express": "~3.0"
8+
},
9+
"devDependencies": { }
10+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// JSON vulnerability protection
2+
// we prepend the data with ")]},\n", which will be stripped by $http in AngularJS
3+
module.exports = function(req, res, next) {
4+
var _send = res.send;
5+
res.send = function(body) {
6+
var contentType = res.getHeader('Content-Type');
7+
if ( contentType && contentType.indexOf('application/json') !== -1 ) {
8+
if (2 == arguments.length) {
9+
// res.send(body, status) backwards compat
10+
if ('number' != typeof body && 'number' == typeof arguments[1]) {
11+
this.statusCode = arguments[1];
12+
} else {
13+
this.statusCode = body;
14+
body = arguments[1];
15+
}
16+
}
17+
body = ")]}',\n" + body;
18+
return _send.call(res, body);
19+
}
20+
_send.apply(res, arguments);
21+
};
22+
next();
23+
};
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
var http = require('http');
2+
var express = require('express');
3+
var protectJSON = require('./protectJSON');
4+
5+
var app = express();
6+
var server = http.createServer(app);
7+
8+
use(protectJSON);
9+
10+
// Start up the server on the port specified in the config
11+
server.listen(5678);
12+
console.log('Angular App Server - listening on port: 5678');

1820EN_06_Code/04_XSRF/server.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
var http = require('http');
2+
var express = require('express');
3+
var xsrf = require('./xsrf');
4+
5+
var app = express();
6+
var server = http.createServer(app);
7+
8+
use(xsrf);
9+
10+
// Start up the server on the port specified in the config
11+
server.listen(5678);
12+
console.log('Angular App Server - listening on port: 5678');

1820EN_06_Code/04_XSRF/xsrf.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
var crypto = require('crypto');
2+
3+
function uid(len) {
4+
return crypto.randomBytes(Math.ceil(len * 3 / 4))
5+
.toString('base64')
6+
.slice(0, len)
7+
.replace(/\//g, '-')
8+
.replace(/\+/g, '_');
9+
}
10+
11+
// The xsrf middleware provide AngularJS style XSRF-TOKEN provision and validation
12+
// Add it to your server configuration after the session middleware:
13+
// app.use(xsrf);
14+
//
15+
module.exports = function(req, res, next) {
16+
// Generate XSRF token
17+
var token = req.session._csrf || (req.session._csrf = uid(24));
18+
// Get the token in the current request
19+
var requestToken = req.headers['x-xsrf-token'];
20+
// Add it to the cookie
21+
res.cookie('XSRF-TOKEN', token);
22+
23+
// Ignore if it is just a read-only request
24+
switch(req.method) {
25+
case 'GET':
26+
case 'HEAD':
27+
case 'OPTIONS':
28+
break;
29+
default:
30+
// Check the token in the request against the one stored in the session
31+
if ( requestToken !== token ) {
32+
return res.send(403);
33+
}
34+
}
35+
// All is OK, continue as you were.
36+
return next();
37+
};
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
angular.module('security.authorization', ['security.service'])
2+
3+
// This service provides guard methods to support AngularJS routes.
4+
// You can add them as resolves to routes to require authorization levels
5+
// before allowing a route change to complete
6+
.provider('securityAuthorization', {
7+
8+
requireAdminUser: ['securityAuthorization', function(securityAuthorization) {
9+
return securityAuthorization.requireAdminUser();
10+
}],
11+
12+
requireAuthenticatedUser: ['securityAuthorization', function(securityAuthorization) {
13+
return securityAuthorization.requireAuthenticatedUser();
14+
}],
15+
16+
$get: ['security', 'securityRetryQueue', function(security, queue) {
17+
var service = {
18+
19+
// Require that there is an authenticated user
20+
// (use this in a route resolve to prevent non-authenticated users from entering that route)
21+
requireAuthenticatedUser: function() {
22+
var promise = security.requestCurrentUser().then(function(userInfo) {
23+
if ( !security.isAuthenticated() ) {
24+
return queue.pushRetryFn('unauthenticated-client', service.requireAuthenticatedUser);
25+
}
26+
});
27+
return promise;
28+
},
29+
30+
// Require that there is an administrator logged in
31+
// (use this in a route resolve to prevent non-administrators from entering that route)
32+
requireAdminUser: function() {
33+
var promise = security.requestCurrentUser().then(function(userInfo) {
34+
if ( !security.isAdmin() ) {
35+
return queue.pushRetryFn('unauthorized-client', service.requireAdminUser);
36+
}
37+
});
38+
return promise;
39+
}
40+
41+
};
42+
43+
return service;
44+
}]
45+
});
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// Based loosely around work by Witold Szczerba - https://github.com/witoldsz/angular-http-auth
2+
angular.module('security', [
3+
'security.service',
4+
'security.interceptor',
5+
'security.login',
6+
'security.authorization']);
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
angular.module('security.interceptor', ['security.retryQueue'])
2+
3+
// This http interceptor listens for authentication failures
4+
.factory('securityInterceptor', ['$injector', 'securityRetryQueue', function($injector, queue) {
5+
return function(promise) {
6+
// Intercept failed requests
7+
return promise.then(null, function(originalResponse) {
8+
if(originalResponse.status === 401) {
9+
// The request bounced because it was not authorized - add a new request to the retry queue
10+
promise = queue.pushRetryFn('unauthorized-server', function retryRequest() {
11+
// We must use $injector to get the $http service to prevent circular dependency
12+
return $injector.get('$http')(originalResponse.config);
13+
});
14+
}
15+
return promise;
16+
});
17+
};
18+
}])
19+
20+
// We have to add the interceptor to the queue as a string because the interceptor depends upon service instances that are not available in the config block.
21+
.config(['$httpProvider', function($httpProvider) {
22+
$httpProvider.responseInterceptors.push('securityInterceptor');
23+
}]);
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
angular.module('security.login.form', ['services.localizedMessages'])
2+
3+
// The LoginFormController provides the behaviour behind a reusable form to allow users to authenticate.
4+
// This controller and its template (login/form.tpl.html) are used in a modal dialog box by the security service.
5+
.controller('LoginFormController', ['$scope', 'security', 'localizedMessages', function($scope, security, localizedMessages) {
6+
// The model for this form
7+
$scope.user = {};
8+
9+
// Any error message from failing to login
10+
$scope.authError = null;
11+
12+
// The reason that we are being asked to login - for instance because we tried to access something to which we are not authorized
13+
// We could do something diffent for each reason here but to keep it simple...
14+
$scope.authReason = null;
15+
if ( security.getLoginReason() ) {
16+
$scope.authReason = ( security.isAuthenticated() ) ?
17+
localizedMessages.get('login.reason.notAuthorized') :
18+
localizedMessages.get('login.reason.notAuthenticated');
19+
}
20+
21+
// Attempt to authenticate the user specified in the form's model
22+
$scope.login = function() {
23+
// Clear any previous security errors
24+
$scope.authError = null;
25+
26+
// Try to login
27+
security.login($scope.user.email, $scope.user.password).then(function(loggedIn) {
28+
if ( !loggedIn ) {
29+
// If we get here then the login failed due to bad credentials
30+
$scope.authError = localizedMessages.get('login.error.invalidCredentials');
31+
}
32+
}, function(x) {
33+
// If we get here then there was a problem with the login request to the server
34+
$scope.authError = localizedMessages.get('login.error.serverError', { exception: x });
35+
});
36+
};
37+
38+
$scope.clearForm = function() {
39+
user = {};
40+
};
41+
42+
$scope.cancelLogin = function() {
43+
security.cancelLogin();
44+
};
45+
}]);
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<form name="form" novalidate class="login-form">
2+
<div class="modal-header">
3+
<h4>Sign in</h4>
4+
</div>
5+
<div class="modal-body">
6+
<div class="alert alert-warning" ng-show="authReason">
7+
{{authReason}}
8+
</div>
9+
<div class="alert alert-error" ng-show="authError">
10+
{{authError}}
11+
</div>
12+
<div class="alert alert-info">Please enter your login details</div>
13+
<label>E-mail</label>
14+
<input name="login" type="email" ng-model="user.email" required autofocus>
15+
<label>Password</label>
16+
<input name="pass" type="password" ng-model="user.password" required>
17+
</div>
18+
<div class="modal-footer">
19+
<button class="btn btn-primary login" ng-click="login()" ng-disabled='form.$invalid'>Sign in</button>
20+
<button class="btn clear" ng-click="clearForm()">Clear</button>
21+
<button class="btn btn-warning cancel" ng-click="cancelLogin()">Cancel</button>
22+
</div>
23+
</form>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
angular.module('security.login', ['security.login.form', 'security.login.toolbar']);
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
angular.module('security.login.toolbar', [])
2+
3+
// The loginToolbar directive is a reusable widget that can show login or logout buttons
4+
// and information the current authenticated user
5+
.directive('loginToolbar', ['security', function(security) {
6+
var directive = {
7+
templateUrl: 'security/login/toolbar.tpl.html',
8+
restrict: 'E',
9+
replace: true,
10+
scope: true,
11+
link: function($scope, $element, $attrs, $controller) {
12+
$scope.isAuthenticated = security.isAuthenticated;
13+
$scope.login = security.showLogin;
14+
$scope.logout = security.logout;
15+
$scope.$watch(function() {
16+
return security.currentUser;
17+
}, function(currentUser) {
18+
$scope.currentUser = currentUser;
19+
});
20+
}
21+
};
22+
return directive;
23+
}]);
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<ul class="nav pull-right">
2+
<li class="divider-vertical"></li>
3+
<li ng-show="isAuthenticated()">
4+
<a href="#">{{currentUser.firstName}} {{currentUser.lastName}}</a>
5+
</li>
6+
<li ng-show="isAuthenticated()" class="logout">
7+
<form class="navbar-form">
8+
<button class="btn logout" ng-click="logout()">Log out</button>
9+
</form>
10+
</li>
11+
<li ng-hide="isAuthenticated()" class="login">
12+
<form class="navbar-form">
13+
<button class="btn login" ng-click="login()">Log in</button>
14+
</form>
15+
</li>
16+
</ul>

0 commit comments

Comments
 (0)