2lift

Untitled

Nov 21st, 2017
126
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 15.74 KB | None | 0 0
  1. // IMPORTS
  2. var express = require('express');
  3. var app = express();
  4. var fs = require('fs');
  5. var http = require('http');
  6. var https = require('https');
  7. var mongoose = require('mongoose');
  8. var jwt = require('jsonwebtoken');
  9. var config = require('./config');
  10. var bodyParser = require('body-parser');
  11. var User = require('./user');
  12.  
  13. // connect database
  14. mongoose.connect(config.DATABASE);
  15.  
  16. // GLOBAL MIDDLEWARE
  17. app.use(express.static('public'));
  18. app.use(bodyParser.json({limit: '50mb'}));
  19. app.use(bodyParser.urlencoded({limit: '50mb', extended: true}));
  20. app.use(function(req, res, next){
  21. res.header('Access-Control-Allow-Origin', '*');
  22. res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
  23. res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Content-Length, X-Requested-With, x-access-token');
  24.  
  25. // intercept OPTIONS method
  26. if ('OPTIONS' == req.method) {
  27. res.sendStatus(200);
  28. }
  29. else {
  30. next();
  31. }
  32. });
  33. app.use(bodyParser.urlencoded({ extended: false }));
  34. app.use(bodyParser.json());
  35.  
  36. // MS API FUNCTIONS
  37. /**
  38. * Call MS face detection
  39. *
  40. * @param {*} imageData image as dataURL
  41. * @param {*} onSuccess success callback
  42. * @param {*} onError error callback
  43. */
  44. function callMsDetect(imageData, onSuccess, onError) {
  45. var msDetectOptions = {
  46. host: config.FACE_API_HOST,
  47. method: 'POST',
  48. port: 443,
  49. path: config.FACE_API_PATH_DETECT,
  50. headers: {
  51. 'Content-Type': 'application/octet-stream',
  52. 'Content-Length': Buffer.byteLength(imageData),
  53. 'Ocp-Apim-Subscription-Key': config.FACE_API_KEY
  54. }
  55. };
  56.  
  57. var msDetectReq = https.request(msDetectOptions, function(msDetectResponse) {
  58. msDetectResponse.setEncoding('utf8');
  59. msDetectResponse.on('data', function(msDetectData){
  60. onSuccess(JSON.parse(msDetectData));
  61. });
  62. });
  63.  
  64. msDetectReq.on('error', onError);
  65. msDetectReq.write(imageData);
  66. msDetectReq.end();
  67. }
  68.  
  69. /**
  70. *
  71. * @param {*} faceId1 face1 to compare
  72. * @param {*} faceId2 face2 to compare
  73. * @param {*} onSuccess success callback
  74. * @param {*} onError error callback
  75. */
  76. function callMsCompare(faceId1, faceId2, onSuccess, onError) {
  77. var msVerifyOptions = {
  78. host: config.FACE_API_HOST,
  79. method: 'POST',
  80. port: 443,
  81. path: config.FACE_API_PATH_VERIFY,
  82. headers: {
  83. 'Ocp-Apim-Subscription-Key': config.FACE_API_KEY
  84. }
  85. }
  86.  
  87. var msVerifyReq = https.request(msVerifyOptions, function(msVerifyResponse) {
  88. msVerifyResponse.setEncoding('utf8');
  89. msVerifyResponse.on('data', function(msVerifyData) {
  90. onSuccess(JSON.parse(msVerifyData));
  91. });
  92. })
  93.  
  94. msVerifyReq.on('error', onError);
  95. msVerifyReq.write(JSON.stringify({faceId1: faceId1, faceId2: faceId2}));
  96. msVerifyReq.end();
  97. }
  98.  
  99. // PUBLIC API ENDPOINTS
  100.  
  101. // login endpoint
  102. app.post('/login', function(req, res){
  103. // possible login methods: image or password
  104. var imageData,
  105. password = req.body.password;
  106.  
  107. // if neither password nor image is sent, send 400;
  108. if(!req.body.password && !req.body.image) {
  109. res.statusCode = 400;
  110. res.json({'message': 'Either image or password is required'});
  111. return;
  112. }
  113.  
  114. // select user from database
  115. User.findOne({
  116. username: req.body.username
  117. }).select('user username faceId password').exec(function(err, user){
  118. if(err || !user){
  119. res.statusCode = 403;
  120. res.json({message:'user not found'});
  121. return;
  122. }
  123. // password login
  124. if(password) {
  125.  
  126. // check password
  127. var validPassword = user.comparePassword(password);
  128. if(!validPassword){
  129. // if password does not match, send 403
  130. res.statusCode = 403;
  131. res.json({message: 'Authentication failed. Wrong username / password.'});
  132. }
  133. else {
  134. // if user is found and password is right, create a token
  135. var token = jwt.sign({
  136. username: user.username
  137. }, config.SECRET);
  138.  
  139. // send the token
  140. res.json({
  141. message: 'Enjoy your token!',
  142. token:token
  143. });
  144. }
  145. }
  146. else {
  147. // get image as binary data, so it can be sent to MS
  148. if(req.body.image) {
  149. imageData = Buffer.from(req.body.image.split(",")[1], 'base64');
  150. }
  151. // image login
  152. if (imageData) {
  153. // detect faces on the login image
  154. callMsDetect(imageData,
  155. function(msDetectData) {
  156. // check for the first face
  157. // TODO: send error when more than one face is recognized and let the user pick one
  158. if(msDetectData[0]){
  159. // compare the recognized face to the saved one
  160. callMsCompare(user.faceId, msDetectData[0].faceId,
  161. function(msCompareData){
  162. if(msCompareData.isIdentical && msCompareData.confidence >= config.FACE_API_CONFIDENCE_TRESHOLD){
  163. //if faces match, create a token
  164. var token = jwt.sign({
  165. username: user.username
  166. }, config.SECRET);
  167.  
  168. //return the information including token as JSON
  169. res.json({
  170. message: 'Login succesful',
  171. token:token
  172. });
  173. }
  174. else {
  175. // if faces do not match, send 403
  176. res.statusCode = 403;
  177. res.json({'message': 'image login failed - face could not be verified'});
  178. }
  179. },
  180. function(error){
  181. // if an error occurs during the compare, send 500
  182. res.statusCode = 500;
  183. res.json({'message': 'Failed'});
  184. });
  185. }
  186. else {
  187. // if no face can be recognized on the login image, send 400
  188. res.statusCode = 400;
  189. res.json({'message': 'Failed - No data'});
  190. }
  191. },
  192. function(error) {
  193. // if an error occurs during the detection, send 500
  194. res.statusCode = 500;
  195. res.json({'message':'image login failed - face detection failed'});
  196. });
  197. }
  198. else {
  199. // if neither password nor valid image data is given, send error
  200. res.statusCode = 400;
  201. res.json({message: 'Either password or image is required'});
  202. }
  203. }
  204. })
  205. });
  206.  
  207. // register endpoint
  208. app.post('/register', function(req, res){
  209.  
  210. // if username or password is missing, send 400
  211. if(!req.body.user.username || !req.body.user.password) {
  212. res.statusCode = 400;
  213. res.json({'message': 'username and password are required'});
  214. return;
  215. }
  216.  
  217. // create new user object
  218. var user = new User();
  219. user.username = req.body.user.username;
  220. user.age = req.body.user.age;
  221. user.password = req.body.user.password;
  222.  
  223. // if image is given
  224. if(req.body.image) {
  225. // call face detection
  226. callMsDetect(Buffer.from(req.body.image.split(",")[1], 'base64'),
  227. function(msDetectData) {
  228. var faceMessage = '';
  229. // face will only be saved if only one face is recognized
  230. // if no face or more than one face is recognized, the user will be informed
  231. // the account will be created without any faceId anyways
  232. if(msDetectData.length === 1){
  233. user.faceId = msDetectData[0].faceId;
  234. }
  235. else if(!msDetectData.length){
  236. faceMessage = 'No face was recognized.'
  237. }
  238. else {
  239. faceMessage = 'More than one face was recognized.'
  240. }
  241. user.save(function(error){
  242. if(error) {
  243. // if an error occurs during save, send 500
  244. res.statusCode = 500;
  245. res.json({'message':'error during save'});
  246. return;
  247. }
  248.  
  249. // login user
  250. var token = jwt.sign({
  251. username: user.username
  252. }, config.SECRET);
  253.  
  254. res.json({
  255. message: 'User was created. ' + faceMessage,
  256. token: token
  257. });
  258. });
  259. },
  260. function(error) {
  261. // if an error occurs during face detection, inform user
  262. // the account will be created without any faceId anyways
  263. user.save(function(error){
  264. var faceMessage = 'Face recognition failed';
  265. if(error) {
  266. // if an error occurs during save, send 500
  267. res.statusCode = 500;
  268. res.json({message:JSON.stringify(error)});
  269. return;
  270. }
  271.  
  272. // login user
  273. var token = jwt.sign({
  274. username: user.username
  275. }, config.SECRET);
  276.  
  277. res.json({
  278. message: 'User was created. ' + faceMessage,
  279. token: token
  280. });
  281. });
  282. });
  283. }
  284.  
  285. // if no image was sent, just create the account
  286. else {
  287. user.save(function(error){
  288. if(error) {
  289. // if an error occurs during save, send 500
  290. res.statusCode = 500;
  291. res.json({message:'Error during save'});
  292. return;
  293. }
  294. var token = jwt.sign({username: user.username}, config.SECRET);
  295. res.json({message:'user created',token: token});
  296. });
  297. }
  298.  
  299. });
  300.  
  301. // PRIVATE API ENDPOINTS
  302.  
  303. // interceptor for private endpoints
  304. app.use(function(req, res, next){
  305. //check header or url parameters or post parameters for token
  306. var token = req.body.token || req.query['token'] || req.headers['x-access-token'];
  307.  
  308. //decode token
  309. if(token){
  310.  
  311. //verifiy secret
  312. jwt.verify(token, config.SECRET, function(err, decoded){
  313. if(err){
  314. return res.status(401).send({
  315. message: 'Failed to authenticate token.'
  316. });
  317. } else{
  318. //if everything is good, save to request for use in other reoutes
  319. req.user = decoded;
  320. next();
  321. }
  322. })
  323. } else {
  324. //if there is no token
  325. //return an HTTP response of 403 (access forbidden ) and an error message
  326. return res.status(403).send({
  327. message: 'No token provided.'
  328. });
  329. }
  330.  
  331. });
  332.  
  333. // home endpoint: just some test stuff to check that private APIs actually work
  334. app.get('/home', function(req, res) {
  335. res.json({'message': 'As a logged in user, you are allowed to see this content. On this page, you can change your securtity information. You can update your password and your login image.'});
  336. });
  337.  
  338. // update password endpoint: update users password
  339. app.post('/updatePassword', function(req, res) {
  340.  
  341. if(!req.body.oldPassword || !req.body.newPassword) {
  342. res.statusCode = 400;
  343. res.json({message: 'old password and new password are required'});
  344. return;
  345. }
  346.  
  347. // get user from token
  348. User.findOne({
  349. username: req.user.username
  350. }).select('user username faceId password').exec(function(err, user){
  351. if(err || !user){
  352. // if no user is found, send 400
  353. res.statusCode = 400;
  354. res.json({message:'user not found'});
  355. }
  356. // if user is found, check for password
  357. var validPassword = user.comparePassword(req.body.oldPassword);
  358. if(validPassword){
  359. // if password is valid, set new password and save
  360. user.password = req.body.newPassword;
  361. user.save(function(error){
  362. if(error) {
  363. // if an error ouccurs during save, send 500
  364. res.statusCode = 500;
  365. res.json({'message':'error during save'});
  366. }
  367. res.json({message:'Password changed'});
  368. });
  369. }
  370. else {
  371. //if password is invalid, send 403
  372. res.statusCode = 403;
  373. res.json({message: 'Authentication failed. Wrong old password.'});
  374. }
  375. });
  376. });
  377.  
  378. // udpate image endpoint: update user image
  379. app.post('/updateImage', function(req, res) {
  380.  
  381. if(!req.body.image) {
  382. // if no image was sent, send 400
  383. res.statusCode = 400;
  384. res.json({message: 'image is required'});
  385. return;
  386. }
  387.  
  388. // get user from token
  389. User.findOne({
  390. username: req.user.username
  391. }).select('user username faceId').exec(function(error, user){
  392. if(error || !user){
  393. // if no user is found, send 400
  394. res.statusCode = 400;
  395. res.json({message:'user not found'});
  396. return;
  397. }
  398. // call face detection with new face
  399. callMsDetect(Buffer.from(req.body.image.split(",")[1], 'base64'),
  400. function(msDetectData) {
  401. if(msDetectData.length === 1){
  402. user.faceId = msDetectData[0].faceId;
  403. user.save(function(error){
  404. if(error) {
  405. // if error occurs during save, send 500
  406. res.statusCode = 500;
  407. res.json({'message':'error during save'});
  408. return;
  409. }
  410.  
  411. res.json({
  412. message: 'Image was updated.',
  413. });
  414. });
  415. }
  416. // if no face or more than one face was recognized, send 400
  417. // TODO: give user the opportunity to pick one of them in frontend
  418. else if(!msDetectData.length){
  419. res.statusCode = 400;
  420. res.json({message: 'No face was recognized.'})
  421. }
  422. else {
  423. res.statusCode = 400;
  424. res.json({message: 'More than one face was recognized.'})
  425. }
  426. },
  427. function(error) {
  428. // if an error occurs during face detection, send 500
  429. res.statusCode = 500;
  430. res.json({message: 'image update failed - face recognition error'});
  431. });
  432.  
  433. });
  434. });
  435.  
  436. // start server
  437. var server = app.listen(8081, function () {
  438. var host = server.address().address;
  439. var port = server.address().port;
  440.  
  441. console.log("Example app listening at http://%s:%s", host, port);
  442. })
Add Comment
Please, Sign In to add comment