· 9 years ago · Nov 24, 2016, 10:36 PM
1const express = require('express');
2const app = express();
3const router = express.Router();
4const uril = require("util");
5const bodyParser = require('body-parser');
6const _ = require('lodash');
7const http = require('http');
8const fs = require('fs'); //file-system
9const https = require('https'); //https
10const MongoClient = require('mongodb').MongoClient;
11const moment = require('moment');
12const jwt = require('jsonwebtoken')
13// A bcrypt library for NodeJS
14const bcrypt = require('bcrypt');
15// Otherwise known as _id in mongo
16const ObjectId = require('mongodb').ObjectId;
17
18// Child processes
19const spawn = require('child_process').spawn;
20const spawnMongod = spawn('mongod', ['--dbpath', './data/db']);
21
22// should be 12 or more
23const saltRounds = 12;
24
25// Store these in a .JSON file and add that to .gitignore
26const secret = 'goldenbanana';
27const accessToken = 'digestweb';
28// 1 hours
29const expires_in = 60*60*1;
30
31const databaseName = 'digae'
32const nativeMongoDriverUrl = 'mongodb://localhost:27017/';
33const databaseUrl = nativeMongoDriverUrl+databaseName;
34const portNumber = 8001;
35
36const REGEX_EMAIL = /^[^@\s]+@[^@\s]+\.[^@\s]+$/;
37
38// configure app to use bodyParser()
39// this will let us get the data from a POST request
40app.use(bodyParser.json());
41// parse application/x-www-form-urlencoded
42app.use(bodyParser.urlencoded({ extended: true }));
43
44app.use('/', express.static('app'));
45
46// Add headers
47app.use(function (req, res, next) {
48 // res.setHeader('Cache-Control', 'public, max-age=31557600');
49 // Website you wish to allow to connect
50 res.setHeader('Access-Control-Allow-Origin', '*');
51 // Request methods you wish to allowss
52 res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
53 // Request headers you wish to allow
54 res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type,authorization');
55 // Set to true if you need the website to include cookies in the requests sent
56 // to the API (e.g. in case you use sessions)
57 res.setHeader('Access-Control-Allow-Credentials', true);
58 // Pass to next layer of middleware
59 next();
60});
61
62http.createServer(app).listen(portNumber);
63
64function checkMongod(callback){
65 spawnMongod.stdout.on('data', function(data){
66 console.log('Successful Mongod');
67 });
68 spawnMongod.stderr.on('data', (data) => {
69 console.log('Error Mongod');
70 });
71 spawnMongod.on('close', (code) => {
72 console.log('Closed Mongod');
73 });
74}
75
76function encryptionHash(unencryptedString, saltRounds, callback){
77 let callbackResponse = 'Unknown error in encryption hashing';
78 return bcrypt.hash(unencryptedString, saltRounds, function(hashError, hash) {
79 if (hash){
80 callbackResponse = hash;
81 } else if (hashError){
82 callbackResponse = hashError;
83 }
84 callback(callbackResponse);
85 }
86)}
87
88function encryptionCompare(unencryptedString, encryptedString, callback){
89 let callbackResponse = 'Unknown error in encryption comparason';
90 return bcrypt.compare(unencryptedString, encryptedString ,function(compareFailed, compareSuccessful) {
91 if (compareSuccessful){
92 callbackResponse = compareSuccessful;
93 } else if (compareFailed) {
94 callbackResponse = compareFailed;
95 }
96 callback(callbackResponse);
97 }
98)}
99
100function tokenSign(payload, secretKey, options){
101 return jwt.sign(payload,secretKey,options);
102}
103
104function tokenVerify(token, secretKey, callback){
105 return jwt.verify(token, secretKey, function(error, success){
106 return callback(error, success);
107 });
108}
109
110MongoClient.connect(databaseUrl, function(err, db) {
111 checkMongod();
112 if (db){
113 const userCollection = db.collection('user');
114 const authenticationCollection = db.collection('authentication');
115 const tokenCollection = db.collection('token');
116
117 function findAllUsers(query){
118 return db.collection('user').find(query);
119 }
120 function findUser(user, callback){
121 let callbackResponse;
122 return db.collection('user').findOne(user ,function(userError, userFound){
123 if (userFound){
124 callbackResponse = userFound;
125 }
126 callback(callbackResponse);
127 });
128 }
129 function insertUser(user, callback){
130 let callbackResponse;
131 return db.collection('user').insertOne(user,function(userInsertError, userInserted){
132 if (userInserted){
133 callbackResponse = userInserted;
134 }
135 callback(callbackResponse);
136 });
137 }
138
139 function findAllAuthentications(query){
140 return db.collection('authentication').find(query);
141 }
142
143 function findAuthentication(authentication, callback){
144 let callbackResponse;
145 return db.collection('authentication').findOne(authentication, function(authenticationError, authenticationFound){
146 if (authenticationFound){
147 callbackResponse = authenticationFound;
148 }
149 callback(callbackResponse);
150 });
151 }
152
153 function findUpdateAuthentication(authenticationFilter, authenticationUpdate, callback){
154 let callbackResponse;
155 return db.collection('authentication').findOneAndUpdate(authenticationFilter, authenticationUpdate, function(authenticationError, authenticationFound){
156 if (authenticationFound){
157 callbackResponse = authenticationFound;
158 }
159 callback(callbackResponse);
160 });
161 }
162
163 function insertAuthentication(authentication, callback){
164 let callbackResponse;
165 return db.collection('authentication').insertOne(authentication,function(authenticationInsertError, authenticationInserted){
166 if (authenticationInserted){
167 callbackResponse = authenticationInserted;
168 }
169 callback(callbackResponse);
170 });
171 }
172
173 function insertToken(token, callback){
174 let callbackResponse;
175 return db.collection('token').insertOne(token, function(tokenInsertError, tokenInserted){
176 if (tokenInserted){
177 callbackResponse = tokenInserted;
178 }
179 callback(callbackResponse);
180 });
181 }
182
183 function createNewUserObject(user){
184 let newUserObject;
185 if (user){
186 newUserObject = {
187 username: user.username,
188 email: user.email,
189 date_created: moment().valueOf(),
190 active: true
191 }
192 }
193 return newUserObject;
194 }
195
196 function createTestTokenObject(token){
197 let newTokenObject;
198 if (token){
199 newTokenObject = {
200 user_id: token.user_id
201 }
202 }
203 }
204
205 function updateTestTokenObject(refreshToken){
206 let updateTestTokenObject;
207 if (refreshToken){
208
209 }
210 }
211
212 function createCurrentUserObject(user){
213 let userObject;
214 if (user){
215 userObject = {
216 active: user.active || false,
217 verified: user.verified || false,
218 id: user._id || '',
219 username: user.username || '',
220 email: user.email || '',
221 date_created: user.date_created || 0,
222 date_birth: user.date_birth || 0,
223 sex: user.sex || '',
224 pregnant: user.pregnant || '',
225 country: user.country || '',
226 city: user.city || '',
227 achievements: user.achievements || [],
228 friends: user.friends || []
229 }
230 }
231 return userObject;
232 }
233
234 function createMealObject(meal){
235 let mealObject;
236 if (meal){
237 mealObject = {
238 // _id: meal._id,
239 user_id: meal.user_id || '',
240 name: meal.name || '',
241 description: meal.description || '',
242 date_created: meal.date_created || '',
243 user_ids: meal.user_ids || [],
244 food_ids: meal.food_ids || [],
245 comments: meal.comments || [],
246 }
247 }
248 return mealObject;
249 }
250
251 function createEatenObject(eaten){
252 let eatenObject;
253 if (eaten){
254 eatenObject = {
255 // _id: eaten._id,
256 food_id: eaten.user_id || '',
257 meal_id: eaten.meal_id || '',
258 nutrient_id: eaten.nutrient_id || '',
259 units: eaten.units || '',
260 mass: eaten.mass || '',
261 date_eaten: eaten.date_eaten || ''
262 }
263 }
264 return eatenObject;
265 }
266
267 function createCommentObject(comment){
268 let commentObject;
269 if (comment){
270 commentObject = {
271 // _id: comment._id,
272 user_id: comment.user_id || '',
273 content: comment.content || '',
274 date_created: comment.date_created || ''
275 }
276 }
277 return commentObject;
278 }
279
280 function createFavoriteObject(favorite){
281 let favoriteObject;
282 if (favorite){
283 favoriteObject = {
284 // _id: favorite._id,
285 user_id: favorite.user_id || '',
286 food_id: favorite.food_id || null,
287 meal_id: favorite.meal_id || null,
288 nutrient_id: favorite.nutrient_id || null,
289 date_created: favorite.date_created || ''
290 }
291 }
292 return favoriteObject;
293 }
294
295 function createPrivateMessageObject(message){
296 let messageObject;
297 if (message){
298 messageObject = {
299 // _id: message._id,
300 user_id: message.user_id || '',
301 recipient_id: message.recipient_id || '',
302 content: message.content || '',
303 date_created: message.date_created || '',
304 date_read: message.date_read || ''
305 }
306 }
307 return messageObject;
308 }
309
310 function createNewAuthenticationObject(authenticationObject){
311 var newAuthenticationObject;
312 if (authenticationObject){
313 newAuthenticationObject = {
314 user_id: authenticationObject.user_id,
315 password: authenticationObject.password
316 }
317 }
318 return newAuthenticationObject;
319 }
320
321 function createTokenObject(token, expiresIn){
322 var tokenObject = {
323 access_token: token,
324 token_type: 'bearer',
325 expires_in: expiresIn,
326 scope: 'standard',
327 refresh_token: ''
328 }
329 return tokenObject;
330 }
331
332 function createTokenPayloadObject(id, username, email){
333 let tokenPayloadObject;
334 tokenPayloadObject = {
335 user_id: id,
336 username: username,
337 email: email,
338 scope: ['premium', 'standard']
339 }
340 return tokenPayloadObject;
341 }
342
343 function sendResponseSuccess(response, code, message){
344 let successObject = {
345 success: true,
346 message: message
347 }
348 return response.status(code).json(successObject);
349 }
350 function sendResponseError(response, code, message){
351 let successObject = {
352 error: true,
353 message: message
354 }
355 return response.status(code).json(successObject);
356 }
357
358 function sendResponseObject(response, code, object){
359 return response.status(code).json(object);
360 }
361
362 function getBearerToken(headerAuthorization){
363 return headerAuthorization.replace('Bearer ', '');
364 }
365
366 function getBasicToken(headerAuthorization){
367 return headerAuthorization.replace('Basic ', '');
368 }
369
370 function decodeToken(token){
371 return new Buffer(token, 'base64').toString();
372 }
373
374 function getUsername(decodedToken){
375 return decodedToken.slice(0, decodedToken.indexOf(':'));
376 }
377 function getPassword(decodedToken, username){
378 return decodedToken.substring((decodedToken.indexOf(':'), username.length + 1));
379 }
380
381 function getTokenBody(token){
382 let delimiter = '.';
383 let strings = token.split(delimiter).slice(1);
384 let bodyAndSignature = strings.join(delimiter);
385 // console.log(tokens);
386 let body = bodyAndSignature.slice(0, bodyAndSignature.indexOf('.'));
387 return body;
388 }
389
390 // user get
391 router.get('/user/:current?',function(request,response){
392 let hasCurrentUserParameters = request.params.current === 'current';
393 let userQuery = {};
394 // current user
395 if (hasCurrentUserParameters){
396 let headerContentType = request.headers['content-type'];
397 let headerAuthorization = request.headers.authorization;
398 let bearerToken = getBearerToken(headerAuthorization);
399 let bearerTokenBody = getTokenBody(bearerToken);
400 let decodedBearerToken = decodeToken(bearerToken);
401 let username = getUsername(decodedBearerToken);
402 let password = getPassword(decodedBearerToken, username);
403 tokenVerify(bearerToken, secret
404 ,function(verifyError, verified){
405 if (verified){
406 userQuery = {
407 _id: ObjectId(verified.user_id),
408 username: verified.username
409 }
410 findUser(userQuery ,function(user){
411 if(user) {
412 let authenticationQuery = {
413 user_id: ObjectId( user._id )
414 }
415 findAuthentication(authenticationQuery, function(authenticationFound){
416 if (authenticationFound && authenticationFound.access_token === accessToken){
417 sendResponseObject(response,200,createCurrentUserObject(user))
418 } else {
419 sendResponseError(response,400,'No authentication found');
420 }
421 });
422 } else {
423 sendResponseError(response,400,'No user found');
424 }
425 });
426 } else if (verifyError){
427 if(verifyError.name === 'TokenExpiredError'){
428 sendResponseError(response,400,'Token expired');
429 } else {
430 sendResponseError(response,400,'Wrong token');
431 }
432 }
433 })
434 // all users
435 } else {
436 let users = [];
437 if (request.query.id){
438 userQuery = {
439 _id: ObjectId( request.query.id )
440 }
441 }
442 findAllUsers(userQuery).each(function(error, user){
443 if(user) {
444 users.push(createCurrentUserObject(user));
445 } else {
446 response.json(users);
447 }
448 });
449 }
450 });
451
452 // user post
453 router.post('/user/:current?',function(request,response){
454 let hasCurrentUserParameters =
455 request.params.current === 'current';
456
457 let hasNewUserParameters =
458 request.body.email &&
459 request.body.username &&
460 request.body.password;
461
462 // current User
463 if (hasCurrentUserParameters){
464
465 let hasRequiredBodyParameters =
466 false;
467
468 // Update current user
469 if (hasRequiredBodyParameters){
470 }
471 // new user
472 } else if (hasNewUserParameters) {
473
474 let bodyUsername = decodeURIComponent(request.body.username);
475 let bodyPassword = decodeURIComponent(request.body.password);
476 let bodyEmail = decodeURIComponent(request.body.email);
477
478 let hasRequiredBodyParameters =
479 bodyUsername &&
480 bodyPassword &&
481 bodyEmail;
482
483 if (hasRequiredBodyParameters){
484 let passwordLength = request.body.password.length;
485 let isPasswordValid = passwordLength > 8;
486 let isEmailValid = REGEX_EMAIL.test(bodyEmail);
487 let isRequestValid = isEmailValid && isPasswordValid;
488
489 if (isRequestValid){
490 let queryUsername = {
491 username: {$regex: bodyUsername, $options: 'i'}
492 };
493 let queryEmail = {
494 email: {$regex: bodyEmail, $options: 'i'}
495 };
496 findAllUsers(queryEmail).count(function(error, userEmailFound){
497 if (!userEmailFound){
498 findAllUsers(queryUsername).count(function(error, userUsernameFound){
499 if (!userUsernameFound){
500 encryptionHash(request.body.password, saltRounds, function(hash){
501 if (hash){
502 insertUser(createNewUserObject(request.body),function(userInserted){
503 if(userInserted.result.ok){
504 let authenticationObject = {
505 user_id: userInserted.ops[0]._id,
506 password: hash
507 };
508 insertAuthentication(createNewAuthenticationObject(authenticationObject), function(authenticationInserted){
509 if(authenticationInserted.result.ok){
510 // create empty token with user id
511 // to update with token when user
512 // signs in
513 let tokenObject = {
514 user_id: userInserted.ops[0]._id,
515 }
516 insertToken(tokenObject, function(tokenInserted){
517 if(tokenInserted.result.ok){
518 sendResponseSuccess(response,201,'User successfully created');
519 }
520 });
521 }
522 });
523 }
524 });
525 }
526 });
527 } else if (userUsernameFound){
528 sendResponseError(response,400,'Username ' + bodyUsername + ' exists');
529 }
530 });
531 } else if (userEmailFound) {
532 sendResponseError(response,400,'Email ' + bodyEmail + ' exists');
533 }
534 });
535 } else {
536 if (!isEmailValid){
537 sendResponseError(response,400,'Invalid email');
538 }
539 if (!isPasswordValid){
540 sendResponseError(response,400,'Password is too short');
541 }
542 }
543 } else {
544 sendResponseError(response,400,'Missing or invalid parameters1');
545 }
546 } else {
547 sendResponseError(response,400,'Missing or invalid parameters2');
548 }
549 });
550
551 router.post('/token',function(request,response){
552 let users = [];
553 let user = {};
554 let body = {};
555 let responseObject = {};
556
557 let hasPasswordGrantParameters =
558 request.body.grant_type === 'password' &&
559 request.body.username &&
560 request.body.password;
561
562 let hasRefreshTokenParameters =
563 request.body.grant_type === 'refresh_token' &&
564 request.body.refresh_token &&
565 request.body.client_id;
566
567 if (hasPasswordGrantParameters){
568 let headerAuthorization = request.headers.authorization;
569 let basicToken = getBasicToken(headerAuthorization.replace('Basic ', ''));
570 let headerAuthorizationUsernamePassword = decodeToken(basicToken);
571 let headerAuthorizationUsername = headerAuthorizationUsernamePassword.slice(0, headerAuthorizationUsernamePassword.indexOf(':'));
572 let headerAuthorizationPassword = headerAuthorizationUsernamePassword.substring((headerAuthorizationUsernamePassword.indexOf(':'), headerAuthorizationUsername.length + 1));
573 let bodyUsername = decodeURIComponent(request.body.username);
574 let bodyPassword = decodeURIComponent(request.body.password);
575
576 // auth: 1. make sure headers matches body
577 if (headerAuthorizationUsername === bodyUsername && headerAuthorizationPassword === bodyPassword){
578 // auth 2. find user
579 let userQuery = {
580 username: {$regex: bodyUsername, $options: 'i'}
581 }
582 findUser(userQuery, function(user){
583 if (user){
584 // auth 3. find authentication
585 let authenticationFilter = {
586 user_id: user._id
587 }
588 let authenticationUpdate = {
589 $set:{ access_token: accessToken }
590 };
591 findUpdateAuthentication(authenticationFilter, authenticationUpdate, function(authenticationFoundAndUpdated){
592 if (authenticationFoundAndUpdated.ok){
593 // auth 4. compare the header body password with the authentication password
594 encryptionCompare(bodyPassword, authenticationFoundAndUpdated.password, function(compareSuccessful){
595 if (compareSuccessful) {
596 // auth 5. send token
597 response.json(createTokenObject(
598 tokenSign(createTokenPayloadObject(user._id, bodyUsername, request.body.email), secret, {expiresIn: expires_in}),
599 expires_in
600 ));
601 } else {
602 sendResponseError(response,400,'Wrong password for user ' + bodyUsername);
603 }
604 });
605 } else {
606 sendResponseError(response,400,'Authentication for user ' + bodyUsername + ' does not exist');
607 }
608 });
609 } else {
610 sendResponseError(response,400,'User ' + bodyUsername + ' does not exist');
611 }
612 });
613 } else {
614 sendResponseError(response,400,'Wrong token information');
615 }
616 } else if (hasRefreshTokenParameters) {
617 } else {
618 sendResponseError(response,400,'Missing or invalid parameters');
619 }
620 });
621
622 // Custom Shit
623 router.get('/token',function(request,response){
624 });
625 router.post('/token',function(request,response){
626 });
627
628 app.use('/',router);
629 }
630 else {
631 }
632});