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(); |
||
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; |
||
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
|
|||
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; |
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
The function
isBig
will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly returnundefined
.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.