server/privacy.js   B
last analyzed

Complexity

Total Complexity 40
Complexity/F 1.9

Size

Lines of Code 235
Function Count 21

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 0
nc 18
dl 0
loc 235
rs 8.2608
c 1
b 0
f 0
wmc 40
mnd 2
bc 36
fnc 21
bpm 1.7142
cpm 1.9047
noi 19

15 Functions

Rating   Name   Duplication   Size   Complexity  
A privacy.js ➔ init 0 6 1
A privacy.js ➔ local 0 17 1
A privacy.js ➔ salt 0 19 2
A privacy.js ➔ hash 0 8 1
A passport.serializeUser 0 1 1
B Router.post(ꞌ/profileꞌ) 0 25 2
A passport.deserializeUser 0 1 1
A Router.get(ꞌ/profileꞌ) 0 3 1
A privacy.js ➔ setLocalStrategy 0 18 1
A privacy.js ➔ registerSARAH 0 13 1
B Router.all(ꞌ/profile/createꞌ) 0 17 5
A Router.get(ꞌ/logoutꞌ) 0 4 1
A Router.get(ꞌ/profile/deleteꞌ) 0 4 1
B Router.all(ꞌ*ꞌ) 0 19 7
A privacy.js ➔ findByUsername 0 9 1

How to fix   Complexity   

Complexity

Complex classes like server/privacy.js often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
var express = require('express');
2
var extend  = require('extend');
3
var request = require('request');
4
5
// ------------------------------------------
6
//  CONSTRUCTOR
7
// ------------------------------------------
8
9
var init = function(){
10
  info('Starting PrivacyManager ...');
11
  salt();
12
  
13
  return PrivacyManager;
14
}
15
16
// ------------------------------------------
17
//  USERS
18
// ------------------------------------------
19
20
var findByUsername = function (username, fn) {
21
  setTimeout(function(){ // slow bruteforce
22
    
23
    var user = Config.auth['local-users'][username]
0 ignored issues
show
Bug introduced by
The variable Config seems to be never declared. If this is a global, consider adding a /** global: Config */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
24
    if (user){ return fn(null, user); }
25
    return fn(null, null);
26
    
27
  }, 1000);
28
}
29
30
// ------------------------------------------
31
//  PASSPORT
32
// ------------------------------------------
33
34
var passport = require('passport');
35
36
passport.serializeUser  (function(user, done) { /*info('serializeUser',   user);*/ done(null, user); });
37
passport.deserializeUser(function(obj, done)  { /*info('deserializeUser', obj);*/  done(null, obj);  });
38
39
// ------------------------------------------
40
//  LOCAL STRATEGY
41
// ------------------------------------------
42
43
var setLocalStrategy = function(passport, router){
44
  router.get('/login', function(req, res, next) {
0 ignored issues
show
Unused Code introduced by
The parameter next is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
45
    res.render('portal/login.ejs', { 'redirect' : req.query.redirect });
46
  });
47
  
48
  router.post('/login', 
49
    passport.authenticate('local', { failureRedirect: '/login', failureFlash: false }), function(req, res) { 
50
      if (req.body.redirect){
51
        res.redirect(req.body.redirect);
52
      } else {
53
        res.redirect('/');
54
      } 
55
    }
56
  );
57
  
58
  var LocalStrategy = require('passport-local').Strategy;
59
  passport.use(new LocalStrategy(local));
60
}
61
62
var local = function(username, password, done) {
63
  process.nextTick(function () {
64
    findByUsername(username, function(err, user) {
65
      
66
      if (err) { return done(err); }
67
      if (!user) { return done(null, false, { message: 'Unknown user ' + username }); }
68
      
69
      var passHash = hash(password);
70
      if (user.password != passHash) { 
71
        info('Invalid password');
72
        return done(null, false, { message: 'Invalid password' }); 
73
      }
74
      
75
      return done(null, user);
76
    });
77
  });
78
}
79
80
// ------------------------------------------
81
//  ROUTER
82
// ------------------------------------------
83
84
var Router = express.Router();
85
Router.use(passport.initialize());
86
Router.use(passport.session());
87
88
Router.get('/logout', function(req, res){
89
  req.logout();
90
  res.redirect('/');
91
});
92
93
// Set local strategy
94
setLocalStrategy(passport, Router);
95
96
// Set google strategy
97
// setGoogleStrategy(passport, Router);
98
99
// Security
100
Router.all('*', function(req, res, next) {
101
  
102
  // Security Hole: ByPass for client
103
  if ( req.path.startsWith('/sarah') 
104
    || req.path.startsWith('/askme')
105
    || req.path.startsWith('/standby')){
106
    return next();
107
  }
108
  
109
  // Set user authentication 
110
  if (Config.auth && Config.auth['local-users']){
0 ignored issues
show
Bug introduced by
The variable Config seems to be never declared. If this is a global, consider adding a /** global: Config */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
111
  if (!req.isAuthenticated()){ 
112
    
113
    var redirectURL = encodeURIComponent(req.url);
114
    return res.redirect('/login?redirect='+redirectURL); }  
115
  } else { req.user = { displayName : '' }}
116
  
117
  next();
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
118
});
119
120
Router.get('/profile', function(req, res){
121
  res.render('portal/profile.ejs', { "user" : req.user });
122
});
123
124
Router.post('/profile', function(req, res){
125
  
126
  var username    = req.body.username;
0 ignored issues
show
Unused Code introduced by
The assignment to variable username seems to be never used. Consider removing it.
Loading history...
127
  var password    = req.body.password;
128
  var newPassword = req.body.newpassword;
129
  var displayName = req.body.displayname;
130
  
131
  // Retrieve user
132
  var user = Config.auth['local-users'][req.user.login];
0 ignored issues
show
Bug introduced by
The variable Config seems to be never declared. If this is a global, consider adding a /** global: Config */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
133
  
134
  // Check Old password
135
  var oldHash = hash(password);
136
  if (user.password !== oldHash){
137
    res.redirect('/');
138
    return;
139
  }
140
  
141
  // Update new password
142
  var newHash = hash(newPassword);
143
  user.password = newHash;
144
  user.displayName = displayName;
145
  SARAH.ConfigManager.save();
0 ignored issues
show
Bug introduced by
The variable SARAH seems to be never declared. If this is a global, consider adding a /** global: SARAH */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
146
  
147
  res.redirect('/');
148
});
149
150
Router.get('/profile/delete', function(req, res){
0 ignored issues
show
Unused Code introduced by
The parameter res is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
151
  delete Config.auth['local-users'][req.query.id]
0 ignored issues
show
Bug introduced by
The variable Config seems to be never declared. If this is a global, consider adding a /** global: Config */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
152
  SARAH.ConfigManager.save();
0 ignored issues
show
Bug introduced by
The variable SARAH seems to be never declared. If this is a global, consider adding a /** global: SARAH */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
153
});
154
155
Router.all('/profile/create', function(req, res){
156
  var msg = undefined;
0 ignored issues
show
Unused Code Comprehensibility introduced by
The assignment of undefined is not necessary as msg is implicitly marked as undefined by the declaration.
Loading history...
157
  var op  = req.body.op;
158
  
159
  if (op){
160
    if (req.body.login && req.body.password && req.body.displayname){
161
      Config.auth['local-users'][req.body.login] = {
0 ignored issues
show
Bug introduced by
The variable Config seems to be never declared. If this is a global, consider adding a /** global: Config */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
162
        login       : req.body.login,
163
        password    : hash(req.body.password),
164
        displayName : req.body.displayname,
165
      }
166
      SARAH.ConfigManager.save();
0 ignored issues
show
Bug introduced by
The variable SARAH seems to be never declared. If this is a global, consider adding a /** global: SARAH */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
167
    } else { msg = i18n('portal.error.missing'); }
168
  }
169
  
170
  res.render('portal/modal-profile.ejs', { 'message': msg, 'op': op });
171
});
172
173
// ------------------------------------------
174
//  CRYPTO
175
// ------------------------------------------
176
177
var bcrypt = require('bcryptjs');
178
179
var ITERATION = 10000;
180
var hash   = function(password){
181
  var salt = Config.auth['local-salt'];
0 ignored issues
show
Bug introduced by
The variable Config seems to be never declared. If this is a global, consider adding a /** global: Config */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
182
  //    salt = new Buffer(salt, 'hex');
183
  //var key  = Crypto.pbkdf2Sync(password, salt, ITERATION, 64);
184
  //var hash = 'pbkdf2$' + ITERATION + '$' + key.toString('hex') + '$' + salt.toString('hex');
185
  var hash = bcrypt.hashSync(password, salt);
186
  return hash;
187
}
188
189
var salt = function(){
190
  if (Config.auth['local-salt'] != false) return;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
Bug introduced by
The variable Config seems to be never declared. If this is a global, consider adding a /** global: Config */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
191
  
192
  // var salt = ('salt' + (Math.random()*10000)).replace('.','0');
193
  var salt = bcrypt.genSaltSync(10);
194
  var sarahId = 'uid-' + (new Date()).getTime();
195
  registerSARAH(sarahId);
196
  
197
  Config.auth['local-uid']  = sarahId
198
  Config.auth['local-salt'] = salt
199
  Config.auth['local-users']          = Config.auth['local-users']          || {};
200
  Config.auth['local-users']['admin'] = Config.auth['local-users']['admin'] || {};
201
  
202
  var admin = Config.auth['local-users']['admin'];
203
  admin.login       = 'admin';
204
  admin.password    = hash('password');
205
  admin.displayName = 'Admin';
206
  SARAH.ConfigManager.save();
0 ignored issues
show
Bug introduced by
The variable SARAH seems to be never declared. If this is a global, consider adding a /** global: SARAH */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
207
}
208
209
var AMZID = '5eVBwYTHp21nzkXrcCC6e4UM93Pr2QMX5cLeD50S';
210
var registerSARAH = function(id){
211
 var url = 'http://tracker.sarah.encausse.net';
212
  request({ 
213
    'uri' : url+'?trackerId='+id, 
214
    'json' : true, 
215
    'headers': {'x-api-key': AMZID } 
216
  },
217
  function (err, response, json){
0 ignored issues
show
Unused Code introduced by
The parameter json is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
218
    if (err || response.statusCode != 200) { 
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if err || response.statusCode != 200 is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
219
      return warn("Can't register SARAH into the Cloud", err, response);   
220
    }
221
  });
222
}
223
224
225
// ------------------------------------------
226
//  PUBLIC
227
// ------------------------------------------
228
229
var PrivacyManager = {
230
  'init' : init,
231
  'Router' : Router
232
}
233
234
// Exports Manager
235
exports.init = PrivacyManager.init;