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] |
||
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) { |
||
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']){ |
||
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
![]() |
|||
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; |
||
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]; |
||
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(); |
||
146 | |||
147 | res.redirect('/'); |
||
148 | }); |
||
149 | |||
150 | Router.get('/profile/delete', function(req, res){ |
||
151 | delete Config.auth['local-users'][req.query.id] |
||
152 | SARAH.ConfigManager.save(); |
||
153 | }); |
||
154 | |||
155 | Router.all('/profile/create', function(req, res){ |
||
156 | var msg = undefined; |
||
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] = { |
||
162 | login : req.body.login, |
||
163 | password : hash(req.body.password), |
||
164 | displayName : req.body.displayname, |
||
165 | } |
||
166 | SARAH.ConfigManager.save(); |
||
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']; |
||
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
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 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. ![]() |
|||
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(); |
||
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){ |
||
218 | if (err || response.statusCode != 200) { |
||
0 ignored issues
–
show
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 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 This behaviour may not be what you had intended. In any case, you can add a
![]() |
|||
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; |