UNPKG

6.49 kBJavaScriptView Raw
1/**
2 * joola.io
3 *
4 * Copyright Joola Smart Solutions, Ltd. <info@joo.la>
5 *
6 * Licensed under GNU General Public License 3.0 or later.
7 * Some rights reserved. See LICENSE, AUTHORS.
8 *
9 * @license GPL-3.0+ <http://spdx.org/licenses/GPL-3.0+>
10 */
11
12var
13 auth = require('../lib/auth/manager'),
14 query = require('./query'),
15 util = require('util');
16
17function ErrorTemplate(err) {
18 this.name = 'joola.io.engine Exception';
19 this.code = 500;
20 if (err.message) this.message = err.message; else this.message = err || '';
21 if (err.stack) this.stack = err.stack; else this.stack = null;
22}
23ErrorTemplate.prototype = Error.prototype;
24exports.ErrorTemplate = ErrorTemplate
25
26function AuthErrorTemplate(err) {
27 this.name = 'joola.io.engine Authentication Exception';
28 this.code = 401;
29 if (err.message) this.message = err.message; else this.message = err || '';
30 if (err.stack) this.stack = err.stack; else this.stack = null;
31}
32AuthErrorTemplate.prototype = ErrorTemplate.prototype;
33exports.AuthErrorTemplate = AuthErrorTemplate;
34
35exports.responseError = function (err, req, res) {
36 if (err.code && err.code == 401)
37 res.status(401);
38 else
39 res.status(500);
40 res.json({"error": err});
41};
42
43exports.responseSuccess = function (data, req, res) {
44 var response = {};
45
46 if (req.token)
47 res.setHeader('joola-token', req.token);
48
49 if (!req.params.minres) {
50 response.id = require('node-uuid').v4();
51 response.timestamp = new Date();
52 response.success = true;
53 response.details = {};
54 response.details.request = req.debug;
55 }
56 response = _.extend(response, data);
57 //response.data = data;
58 res.status(200);
59
60
61 res.json(response);
62};
63
64exports.index = function (req, res) {
65 res.end('ok');
66};
67
68exports.validateToken = function (req, res, callback) {
69 var failed = function () {
70 if (req.method == 'OPTIONS') {
71 return callback(null, true);
72 }
73 else {
74 joola.logger.warn('Detected a connection without a valid token accessing action: ' + req.params.resource + '/' + (req.params.action ? req.params.action : '') + '.');
75 return callback(null, false);
76 }
77 };
78
79 var validate = function (token) {
80 auth.validateToken(token, function (user, _token) {
81 if ((joola.config.auth.bypassToken != null && token == joola.config.auth.bypassToken) || joola.config.auth.store == 'none') {
82 if (!_token)
83 _token = '1234567890';
84 user = {
85 id: 1,
86 displayName: 'Anonymous User',
87 _roles: ['admin', 'user']
88 };
89 }
90 if (user) {
91 joola.logger.debug('Token [' + _token + '] validated.');
92 req.user = user;
93 req.token = _token;
94
95 return callback(null, true);
96 }
97 else {
98 joola.logger.error('Token [' + token + '] is invalid.');
99 failed();
100 }
101 });
102 };
103
104 var approvedActions = [];
105 approvedActions.push('login');
106 approvedActions.push('loginSSO');
107 approvedActions.push('loginNeeded');
108 approvedActions.push('auth.checkToken');
109
110 if (approvedActions.indexOf(req.params.resource) != -1) {
111 joola.logger.debug('Approved action detected, bypassing token inspection.');
112 return callback(null, true);
113 }
114
115 var token = req.headers['joola-token'];
116 if (token == null || typeof(token) == 'undefined' || token == 'undefined')
117 token = req.query.token;
118
119 if (token || joola.config.auth.store == 'none')
120 validate(token);
121 else
122 failed();
123};
124
125exports.validateAction = function (action, req, res, callback) {
126 if (req.method == 'OPTIONS')
127 return callback(null, true);
128
129 var required = action.inputs.required;
130 var optional = action.inputs.optional;
131
132 var _params = [];
133 _params.resource = req.params.resource;
134 _params.action = req.params.action;
135 _params.minres = req.params.minres;
136
137 required.forEach(function (param) {
138 if (!req.params[param])
139 return callback(new ErrorTemplate('Required param [' + param + '] is missing.'), false);
140 _params[param ] = req.params[param];
141 });
142
143 optional.forEach(function (param) {
144 if (req.params[param])
145 _params[param] = req.params[param];
146 else
147 _params[param] = '';
148 });
149
150 req.debug = {};
151 Object.keys(_params).forEach(function (key) {
152 req.debug[key] = _params[key];
153 });
154
155 req.params = _params;
156
157 if (!req.user)
158 return callback(new ErrorTemplate('Request for action by unauthenticated user.'), false);
159
160 var userPermissions = [];
161 req.user._roles.forEach(function (role) {
162 joola.config.auth.roles.forEach(function (roleToCompareAgainst) {
163 if (role === roleToCompareAgainst.id) {
164 userPermissions = userPermissions.concat(roleToCompareAgainst.permissions);
165 }
166 });
167 });
168
169 if (util.isArray(action.permission))
170 action.permission = action.permission[0];
171 if (userPermissions.indexOf(action.permission) == -1)
172 return callback(new ErrorTemplate('Missing permission to run this action.'), false);
173
174 return callback(null, true);
175};
176
177exports.route = function (req, res) {
178 var modulename = req.params.resource;
179 var module;
180 var action = req.params.action;
181
182 _.extend(req.params, req.query);
183
184 exports.validateToken(req, res, function (err, validated) {
185 if (err)
186 return exports.responseError(err, req, res);
187 else if (!validated)
188 return exports.responseError(new AuthErrorTemplate('Authentication failed.'), req, res);
189
190 joola.logger.debug('Token verified ' + req.token);
191
192 if (!modulename)
193 return exports.responseError(new ErrorTemplate('Module not specified.'), req, res);
194
195 try {
196 module = require('./' + modulename);
197 }
198 catch (ex) {
199 return exports.responseError(ex, req, res);
200 }
201
202 if (!action)
203 action = 'index';
204
205 try {
206 action = module[action];
207 exports.validateAction(action, req, res, function (err, validated) {
208 if (err)
209 return exports.responseError(err, req, res);
210 else if (!validated)
211 return exports.responseError(new ErrorTemplate('Failed to validate action.'), req, res);
212 joola.logger.debug('Routing [' + action.name + ']...');
213 return action.run(req, res);
214 });
215 }
216 catch (ex) {
217 console.log('err', ex);
218 console.log(ex.stack);
219 return exports.responseError(ex, req, res);
220 }
221 });
222};
\No newline at end of file