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; |
||
0 ignored issues
–
show
|
|||
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) { |
||
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; |
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 you or someone else later decides to put another statement in, only the first statement will be executed.
In this case the statement
b = 42
will always be executed, while the logging statement will be executed conditionally.ensures that the proper code will be executed conditionally no matter how many statements are added or removed.